diff --git a/.github/workflows/publisher.yml b/.github/workflows/publisher.yml new file mode 100644 index 0000000000..6dc43014d2 --- /dev/null +++ b/.github/workflows/publisher.yml @@ -0,0 +1,72 @@ +name: Publisher + +# Trigger on new github release, a tag with format vX.Y.Z is expected (used to tag the docker) +on: + release: + types: [published] + +env: + OPENDR_VERSION: ${{ github.event.release.tag_name }} + +defaults: + run: + shell: bash + +jobs: + publish-wheel: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install prerequisites + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build Wheel + run: | + ./bin/build_wheel.sh + - name: Upload Wheel + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run : | + twine upload dist/* + publish-docker-cpu: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Build Docker Image + run: docker build --tag opendr-toolkit:cpu_$OPENDR_VERSION --file Dockerfile . + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Publish Image + run: | + docker tag opendr-toolkit:cpu_$OPENDR_VERSION opendr/opendr-toolkit:cpu_$OPENDR_VERSION + docker push opendr/opendr-toolkit:cpu_$OPENDR_VERSION + publish-docker-cuda: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Build Docker Image + run: docker build --tag opendr-toolkit:cuda_$OPENDR_VERSION --file Dockerfile-cuda . + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + - name: Publish Image + run: | + docker tag opendr-toolkit:cuda_$OPENDR_VERSION opendr/opendr-toolkit:cuda_$OPENDR_VERSION + docker push opendr/opendr-toolkit:cuda_$OPENDR_VERSION diff --git a/.github/workflows/test_packages.yml b/.github/workflows/test_packages.yml index e7a3b718ea..13cd407950 100644 --- a/.github/workflows/test_packages.yml +++ b/.github/workflows/test_packages.yml @@ -61,7 +61,6 @@ jobs: source venv/bin/activate wget https://raw.githubusercontent.com/opendr-eu/opendr/master/dependencies/pip_requirements.txt cat pip_requirements.txt | xargs -n 1 -L 1 pip install - # Test new package pip install opendr-toolkit python -m unittest discover -s tests/sources/tools/${{ matrix.package }} test-docker: @@ -89,7 +88,7 @@ jobs: - control/mobile_manipulation - simulation/human_model_generation - control/single_demo_grasp - #- perception/object_tracking_3d + # - perception/object_tracking_3d runs-on: ${{ matrix.os }} steps: - name: Set up Python 3.8 diff --git a/.github/workflows/tests_suite.yml b/.github/workflows/tests_suite.yml index 82b80e7e96..d17c596702 100644 --- a/.github/workflows/tests_suite.yml +++ b/.github/workflows/tests_suite.yml @@ -12,7 +12,7 @@ defaults: jobs: cleanup-runs: - if: ${{ contains(github.event.pull_request.labels.*.name, 'test sources') || contains(github.event.pull_request.labels.*.name, 'test tools') || github.event_name == 'schedule' }} + if: ${{ contains(github.event.pull_request.labels.*.name, 'test sources') || contains(github.event.pull_request.labels.*.name, 'test tools') || contains(github.event.pull_request.labels.*.name, 'test release') || github.event_name == 'schedule' }} runs-on: ubuntu-latest steps: - uses: rokroskar/workflow-run-cleanup-action@master @@ -106,4 +106,134 @@ jobs: source tests/sources/tools/control/mobile_manipulation/run_ros.sh python -m unittest discover -s tests/sources/tools/${{ matrix.package }} fi - + build-wheel: + needs: cleanup-runs + if: ${{ contains(github.event.pull_request.labels.*.name, 'test release') || github.event_name == 'schedule' }} + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install prerequisites + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build Wheel + run: + ./bin/build_wheel.sh + - name: Upload wheel as artifact + uses: actions/upload-artifact@v2 + with: + path: + dist/*.tar.gz + build-docker: + needs: cleanup-runs + if: ${{ contains(github.event.pull_request.labels.*.name, 'test release') || github.event_name == 'schedule' }} + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Build image + run: | + docker build --tag opendr/opendr-toolkit:cpu_test --file Dockerfile . + docker save opendr/opendr-toolkit:cpu_test > cpu_test.zip + - name: Upload image artifact + uses: actions/upload-artifact@v2 + with: + path: + cpu_test.zip + test-wheel: + needs: build-wheel + if: ${{ contains(github.event.pull_request.labels.*.name, 'test release') || github.event_name == 'schedule' }} + strategy: + matrix: + os: [ubuntu-20.04] + package: + - engine + - utils + - perception/activity_recognition + - perception/compressive_learning + - perception/face_recognition + - perception/heart_anomaly_detection + - perception/multimodal_human_centric + - perception/object_tracking_2d + - perception/pose_estimation + - perception/speech_recognition + - perception/skeleton_based_action_recognition + - perception/semantic_segmentation + - perception/object_detection_2d + - perception/facial_expression_recognition + # - perception/object_detection_3d + # - control/mobile_manipulation + # - simulation/human_model_generation + # - control/single_demo_grasp + # - perception/object_tracking_3d + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Download artifact + uses: actions/download-artifact@v2 + with: + path: artifact + - name: Get branch name + id: branch-name + uses: tj-actions/branch-names@v5.1 + - name: Test Wheel + run: | + export DISABLE_BCOLZ_AVX2=true + sudo apt -y install python3.8-venv libfreetype6-dev git build-essential cmake python3-dev wget libopenblas-dev libsndfile1 libboost-dev python3-dev + python3 -m venv venv + source venv/bin/activate + wget https://raw.githubusercontent.com/opendr-eu/opendr/${{ steps.branch-name.outputs.current_branch }}/dependencies/pip_requirements.txt + cat pip_requirements.txt | xargs -n 1 -L 1 pip install + pip install ./artifact/artifact/*.tar.gz + python -m unittest discover -s tests/sources/tools/${{ matrix.package }} + test-docker: + needs: build-docker + if: ${{ contains(github.event.pull_request.labels.*.name, 'test release') || github.event_name == 'schedule' }} + strategy: + matrix: + os: [ubuntu-20.04] + package: + - engine + - utils + - perception/activity_recognition + - perception/compressive_learning + - perception/face_recognition + - perception/heart_anomaly_detection + - perception/multimodal_human_centric + - perception/object_tracking_2d + - perception/pose_estimation + - perception/speech_recognition + - perception/skeleton_based_action_recognition + - perception/semantic_segmentation + - perception/object_detection_2d + - perception/facial_expression_recognition + - perception/object_detection_3d + - control/mobile_manipulation + - simulation/human_model_generation + - control/single_demo_grasp + # - perception/object_tracking_3d + runs-on: ubuntu-20.04 + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + path: artifact + - name: Test docker + run: | + docker load < ./artifact/artifact/cpu_test.zip + docker run --name toolkit -i opendr/opendr-toolkit:cpu_test bash + docker start toolkit + docker exec -i toolkit bash -c "source bin/activate.sh && source tests/sources/tools/control/mobile_manipulation/run_ros.sh && python -m unittest discover -s tests/sources/tools/${{ matrix.package }}" diff --git a/docs/reference/index.md b/docs/reference/index.md index 60d2cfc530..f0926d311e 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -67,11 +67,14 @@ Neither the copyright holder nor any applicable licensor will be liable for any - [single_demo_grasp Module](single-demonstration-grasping.md) - `simulation` Module + - [human_model_generation Module](human_model_generation.md) + - `data_generation` Module + - [synthetic_facial_image_generation Module](synthetic_facial_image_generator.md) - [human_model_generation Module](human-model-generation.md) - `utils` Module - [Hyperparameter Tuning Module](hyperparameter_tuner.md) -- `Stand-alone Utility Frameworks` - - [Engine Agnostic Gym Environment with Reactive extension (EAGERx)](eagerx.md) + - `Stand-alone Utility Frameworks` + - [Engine Agnostic Gym Environment with Reactive extension (EAGERx)](eagerx.md) - [ROSBridge Package](rosbridge.md) - [C Inference API](c-api.md) - [data.h](c-data-h.md) diff --git a/docs/reference/synthetic_facial_image_generator.md b/docs/reference/synthetic_facial_image_generator.md new file mode 100644 index 0000000000..5f2dedac56 --- /dev/null +++ b/docs/reference/synthetic_facial_image_generator.md @@ -0,0 +1,58 @@ +## synthetic_facial_image_generator module + +The *synthetic_facial_image_generator* module contains the *MultiviewDataGeneration* class, which implements the multi-view facial image rendering operation. + +### Class MultiviewDataGeneration + +The *MultiviewDataGeneration* class is a wrapper of the Rotate-and-Render [[1]](#R-R-paper) photorealistic multi-view facial image generator based on the original +[Rotate-and-Render implementation](https://github.com/Hangz-nju-cuhk/Rotate-and-Render). +It can be used to perform multi-view facial image generation from a single view image on the wild (eval). +The [MultiviewDataGeneration](#projects.data_generation.synthetic-multi-view-facial-image-generation.3ddfa.SyntheticDataGeneration.py ) class has the +following public methods: + +#### `MultiviewDataGeneration` constructor +```python +MultiviewDataGeneration(self, args) +``` + +Constructor main parameters *args* explanation: + +- **path_in**: *str, default='./example/Images'* \ +An absolute path (path in) which indicates the folder that contains the set of single view facial image snapshots to be processed by the algorithm. +- **path_3ddfa**: *str, default='./'* \ +An absolute path (path 3ddfa) which indicates the 3ddfa module folder of the software structure as presented in the repository. This path is necessary in order for the software to create the folders for the intermediate / temporary storage of files generated during the pre-processing such as 3d face models, facial landmarks etc. +in the folder results of this path. +- **save_path**: *str, default='./results'* \ +The output images are stored in the folder indicated by save path which is also a class input parameter. +- **val_yaw**: *str, default='10,20'* \ +Definition of the yaw angles (in the interval [−90°,90°]) for which the rendered images will be produced. +- **val_pitch**: *str, default=' 30,40'* \ +Definition of the pitch angles (in the interval [−90°,90°]) for which the rendered images will be produced. +- **device**: *{'cuda', 'cpu'}, default='cpu'* \ +Specifies the device to be used. + + +#### `MultiviewDataGeneration.eval` +```python +MultiviewDataGeneration.eval() +``` + +This function is implementing the main procedure for the creation of the multi-view facial images, which consists of three different stages. +Instead of initializing the main parameters of the 3DDFA network in the intializer, the first stage includes detection of the candidate faces in the input images and 3D-head mesh fitting using 3DDFA. +Moreover, the second stage extracts the facial landmarks in order to derive the head pose and align the images with the 3d head model mesh. +Finally, the main functionality of the multiview facial image rendering is executed by loading the respective network parameters. + +### Usage Example + +```python +python3 tool_synthetic_facial_generation.py -path_in ./demos/imgs_input/ -path_3ddfa ./algorithm/DDFA/ -save_path ./results -val_yaw 10, 40 -val_pitch 10, 30 -device cuda +``` +The corresponding paths for the input, output folders as well as the pitch and yaw angles for which the user wants to +produce the facial images can be easily incorporated in the class creation while the method is initialized. +The process is executed for the CNN parameters and GPUs specified in the arguments of the aforementioned command. +Users that wish to modify these parameters shall change the respective input arguments which derived from a parser including the arguments path in, path_3ddfa, save_path, val_yaw, val_pitch etc. + +#### References +[1] +Hang Zhou, Jihao Liu, Ziwei Liu, Yu Liu, Xiaogang Wang, Rotate-and-Render: Unsupervised Photorealistic Face Rotation from Single-View Images, +[arXiv](https://arxiv.org/abs/2003.08124#). diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/README.md b/projects/data_generation/synthetic_multi_view_facial_image_generation/README.md new file mode 100644 index 0000000000..c8a650489d --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/README.md @@ -0,0 +1,70 @@ +# Synthentic Multi-view Facial Image Generation based on Rotate-and-Render: Unsupervised Photorealistic Face Rotation from Single-View Images (CVPR 2020) + +Based on: [[Rotate-and-Render: Unsupervised Photorealistic Face Rotation from Single-View Images]](https://arxiv.org/abs/2003.08124) + +We utilize, with small modifications in order to be easily executed, publicly available code, namely an un-supervised framework that can synthesize photorealistic rotated facial images using as input a single facial image, or multiple such images (one per person). +The implemented method allows for rotating faces in the 3D space back and forth, and then re-rendering them to the 2D plane. +The generated multi-view facial images can be used for different learning tasks, such as in self-supervised learning tasks. + +## Sources: +* Face Alignment in Full Pose Range: A 3D Total Solution (IEEE TPAMI 2017) +* Neural 3D Mesh Renderer (CVPR 2018) +* Rotate-and-Render: Unsupervised Photorealistic Face Rotation from Single-View Images (CVPR 2020) + +## Requirements +* Python 3.6 is used. Basic requirements are listed in the 'requirements.txt'. + +``` +pip3 install -r requirements.txt +``` +* Install the [Neural_Renderer](https://github.com/daniilidis-group/neural_renderer) following the instructions. +``` +pip install git+https://github.com/cidl-auth/neural_renderer +``` + +* Download checkpoint and BFM model from [checkpoint.zip](ftp://opendrdata.csd.auth.gr/data_generation/synthetic_multi-view-facial-generator/ckpt_and_bfm.zip) put it in ```3ddfa``` and unzip it: +```bash +wget ftp://opendrdata.csd.auth.gr/data_generation/synthetic_multi-view-facial-generator/checkpoints.zip +unzip checkpoints.zip +unzip checkpoints/ckpt_and_bfm.zip -d 3ddfa +``` +The 3D models are borrowed from [3DDFA](https://github.com/cleardusk/3DDFA). + +* Compile cython code and download remaining models: +```bash +cd algorithm/DDFA/utils/cython/ +python3 setup.py build_ext -i +cd ../../../.. +mkdir algorithm/DDFA/models +mkdir algorithm/DDFA/example +wget https://github.com/cleardusk/3DDFA/blob/master/models/phase1_wpdc_vdc.pth.tar?raw=true -O algorithm/DDFA/models/phase1_wpdc_vdc.pth.tar +``` + +## Usage Example + +1. Execute the one-step OPENDR function ```tool_synthetic_facial_generation.py``` specifying the input images folder, the output folder, the desired degrees (range -90 to 90) for generating the facial images in multiple view angles pitch and yaw as indicated in the command line: +```sh +python3 tool_synthetic_facial_generation.py -path_in ./demos/imgs_input/ -path_3ddfa ./algorithm/DDFA/ -save_path ./results -val_yaw 10, 40 -val_pitch 10, 30 -device cuda +``` + +3. The results can be found in ```results/rs_model/example/```, where multi-view facial images are generated for every person in a respective folder. + +## License +Rotate-and-Render is provided under [CC-BY-4.0](https://github.com/Hangz-nju-cuhk/Rotate-and-Render/blob/master/LICENSE) license. +SPADE, SyncBN, 3DDFA are under [MIT License](https://github.com/tasostefas/opendr_internal/blob/synthetic-multi-view-facial-generator/projects/data_generation/synthetic-multi-view-facial-image-generation/3ddfa/LICENSE) + +## Acknowledgement +Large parts of the code are taken from: +* The structure of this codebase is borrowed from [SPADE](https://github.com/NVlabs/SPADE). +* The [SyncBN](https://github.com/vacancy/Synchronized-BatchNorm-PyTorch) module is used in the current code. +* The [3DDFA](https://github.com/cleardusk/3DDFA) implementation for 3D reconstruction. +* The code [Rotate-and-Render](https://github.com/Hangz-nju-cuhk/Rotate-and-Render/) + +with the following modifications to make them compatible with the OpenDR specifications: +## Minor Modifications +1. All scripts: PEP8 changes +2. ```3ddfa/preprocessing_1.py, 3ddfa/preprocessing_2.py, test_multipose.py``` Modified to work as a callable functions +3. ```options/base_options.py, options/test_options.py ``` Commented out/change several parameters to be easily executed +4. ```models/networks/render.py``` Minor functional changes +5. The OPENDR created functions are ```SyntheticDataGeneration.py, tool_synthetic_facial_generation.py``` +6. The rest are taken from the aforementioned repositories diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/SyntheticDataGeneration.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/SyntheticDataGeneration.py new file mode 100644 index 0000000000..4df8e55fff --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/SyntheticDataGeneration.py @@ -0,0 +1,141 @@ +# Copyright 2020-2022 OpenDR European Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# MIT License +# +# Copyright (c) 2019 Jian Zhao +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# !/usr/bin/env python3.7 +# coding: utf-8 +from tqdm import tqdm +from shutil import copyfile +import cv2 +import os +from algorithm.DDFA import preprocessing_1 +from algorithm.DDFA import preprocessing_2 +from algorithm.Rotate_and_Render import test_multipose + + +class MultiviewDataGeneration(): + + def __init__(self, args): + + self.path_in = args.path_in + self.key = str(args.path_3ddfa + "/example/Images/") + self.key1 = str(args.path_3ddfa + "/example/") + self.key2 = str(args.path_3ddfa + "/results/") + self.save_path = args.save_path + self.val_yaw = args.val_yaw + self.val_pitch = args.val_pitch + self.args = args + + def eval(self): + + # STAGE No1 : detect faces and fitting to 3d mesh by main.py execution + list_im = [] + + print("START") + + a = open("file_list.txt", "w") + for subdir, dirs, files in os.walk(self.path_in): + current_directory_path = os.path.abspath(subdir) + for file in files: + name, ext = os.path.splitext(file) + if ext == ".jpg": + current_image_path = os.path.join(current_directory_path, file) + current_image = cv2.imread(current_image_path) + list_im.append(current_image_path) + a.write(str(file) + os.linesep) + cv2.imwrite(os.path.join(self.key, file), current_image) + self.args.files = list_im.copy() + list_im.clear() + preprocessing_1.main(self.args) + a.close() + + # STAGE No2: Landmarks Output with inference.py execution + + im_list2 = [] + d = open(os.path.join(self.key1, 'realign_lmk'), "w") + for subdir, dirs, files in os.walk(self.path_in): + current_directory_path = os.path.abspath(subdir) + self.args.img_prefix = current_directory_path + self.args.save_dir = os.path.abspath(self.key2) + self.args.save_lmk_dir = os.path.abspath(self.key1) + if not os.path.exists(self.args.save_dir): + os.mkdir(self.args.save_dir) + if not os.path.exists(self.args.save_lmk_dir): + os.mkdir(self.args.save_lmk_dir) + + list_lfw_batch = './file_list.txt' + dst = os.path.join(self.args.save_lmk_dir, "file_list.txt") + copyfile(list_lfw_batch, dst) + b = open("txt_name_batch.txt", "w") + for file in files: + + with open(list_lfw_batch) as f: + img_list = [x.strip() for x in f.readlines()] + + for img_idx, img_fp in enumerate(tqdm(img_list)): + if img_fp == str(file): + im_list2.append(str(file)) + b.write(str(file) + os.linesep) + self.args.img_list = './txt_name_batch.txt' + b.close() + self.args.dump_lmk = 'true' + im_list2.clear() + preprocessing_2.main(self.args) + with open(os.path.join(self.args.save_lmk_dir, 'realign_lmk_')) as f: + img_list = [x.strip() for x in f.readlines()] + for img_idx, img_fp in enumerate(tqdm(img_list)): + d.write(img_fp + os.linesep) + d.close() + + # STAGE No3: Generate Facial Images in specific pitch and yaw angles + test_multipose.main(self.save_path, self.val_yaw, self.val_pitch) + + def fit(self): + raise NotImplementedError() + + def infer(self): + raise NotImplementedError() + + def load(self): + raise NotImplementedError() + + def optimize(self): + raise NotImplementedError() + + def reset(self): + raise NotImplementedError() + + def save(self): + raise NotImplementedError() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/bfm_show.m b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/bfm_show.m new file mode 100644 index 0000000000..392dcdf62c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/bfm_show.m @@ -0,0 +1,14 @@ +model = load('model_refine.mat'); +model = model.model_refine; + +mu = model.mu_shape + model.mu_exp; +mu = reshape(mu, 3, length(mu) / 3); +tri = model.tri; +keypoints = model.keypoints; +pts68_3d = mu(:, keypoints); + +render_face_mesh(mu, tri, pts68_3d); + +A = getframe(gcf); +mimg = A.cdata; +imwrite(mimg, 'imgs/bfm_noneck.jpg', 'quality', 95); diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_noneck.jpg b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_noneck.jpg new file mode 100644 index 0000000000..e05cd6073d Binary files /dev/null and b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_noneck.jpg differ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_refine.jpg b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_refine.jpg new file mode 100644 index 0000000000..e05cd6073d Binary files /dev/null and b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/imgs/bfm_refine.jpg differ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/readme.md b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/readme.md new file mode 100644 index 0000000000..5fb8557645 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/readme.md @@ -0,0 +1,16 @@ +The original version with neck: +

+ neck +

+ +[bfm.ply](https://github.com/Hangz-nju-cuhk/Rotate-and-Render/blob/master/3ddfa/BFM_Remove_Neck/bfm.ply) + +The image is rendered by MeshLab. + +`bfm_show.m` shows how to render it with 68 keypoints in Matlab. + +

+ no neck +

+ +Attention: Do not use the `ply` file in training. diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/render_face_mesh.m b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/render_face_mesh.m new file mode 100644 index 0000000000..623e19cce7 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/BFM_Remove_Neck/render_face_mesh.m @@ -0,0 +1,22 @@ +function render_face_mesh(vertex, tri, pts68_3d) + trisurf(tri', vertex(1, :), vertex(2, :), vertex(3, :), ones(size(vertex, 2),1), 'edgecolor', 'none'); + + re=[1 1 1]; + colormap(re); + + light('Position', [0 0 1], 'Style', 'infinite'); + lighting gouraud + axis equal + view([0 90]); + + if nargin == 3 + hold on; plot3(pts68_3d(1,:), pts68_3d(2,:), pts68_3d(3,:)+1, '*'); + end + + xlabel('x'); + ylabel('y'); + zlabel('z'); + + axis on; + grid on; +end \ No newline at end of file diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/LICENSE b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/LICENSE new file mode 100644 index 0000000000..4695f23b74 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jianzhu Guo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/example/Images/.keep b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/example/Images/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/mobilenet_v1.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/mobilenet_v1.py new file mode 100644 index 0000000000..e48dd7a60d --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/mobilenet_v1.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +from __future__ import division + +""" +Creates a MobileNet Model as defined in: +Andrew G. Howard Menglong Zhu Bo Chen, et.al. (2017). +MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications. +Copyright (c) Yang Lu, 2017 + +Modified By cleardusk +""" +import math +import torch.nn as nn + +__all__ = ['mobilenet_2', 'mobilenet_1', 'mobilenet_075', 'mobilenet_05', 'mobilenet_025'] + + +class DepthWiseBlock(nn.Module): + def __init__(self, inplanes, planes, stride=1, prelu=False): + super(DepthWiseBlock, self).__init__() + inplanes, planes = int(inplanes), int(planes) + self.conv_dw = nn.Conv2d(inplanes, inplanes, kernel_size=3, padding=1, stride=stride, groups=inplanes, + bias=False) + self.bn_dw = nn.BatchNorm2d(inplanes) + self.conv_sep = nn.Conv2d(inplanes, planes, kernel_size=1, stride=1, padding=0, bias=False) + self.bn_sep = nn.BatchNorm2d(planes) + if prelu: + self.relu = nn.PReLU() + else: + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + out = self.conv_dw(x) + out = self.bn_dw(out) + out = self.relu(out) + + out = self.conv_sep(out) + out = self.bn_sep(out) + out = self.relu(out) + + return out + + +class MobileNet(nn.Module): + def __init__(self, widen_factor=1.0, num_classes=1000, prelu=False, input_channel=3): + """ Constructor + Args: + widen_factor: config of widen_factor + num_classes: number of classes + """ + super(MobileNet, self).__init__() + + block = DepthWiseBlock + self.conv1 = nn.Conv2d(input_channel, int(32 * widen_factor), kernel_size=3, stride=2, padding=1, + bias=False) + + self.bn1 = nn.BatchNorm2d(int(32 * widen_factor)) + if prelu: + self.relu = nn.PReLU() + else: + self.relu = nn.ReLU(inplace=True) + + self.dw2_1 = block(32 * widen_factor, 64 * widen_factor, prelu=prelu) + self.dw2_2 = block(64 * widen_factor, 128 * widen_factor, stride=2, prelu=prelu) + + self.dw3_1 = block(128 * widen_factor, 128 * widen_factor, prelu=prelu) + self.dw3_2 = block(128 * widen_factor, 256 * widen_factor, stride=2, prelu=prelu) + + self.dw4_1 = block(256 * widen_factor, 256 * widen_factor, prelu=prelu) + self.dw4_2 = block(256 * widen_factor, 512 * widen_factor, stride=2, prelu=prelu) + + self.dw5_1 = block(512 * widen_factor, 512 * widen_factor, prelu=prelu) + self.dw5_2 = block(512 * widen_factor, 512 * widen_factor, prelu=prelu) + self.dw5_3 = block(512 * widen_factor, 512 * widen_factor, prelu=prelu) + self.dw5_4 = block(512 * widen_factor, 512 * widen_factor, prelu=prelu) + self.dw5_5 = block(512 * widen_factor, 512 * widen_factor, prelu=prelu) + self.dw5_6 = block(512 * widen_factor, 1024 * widen_factor, stride=2, prelu=prelu) + + self.dw6 = block(1024 * widen_factor, 1024 * widen_factor, prelu=prelu) + + self.avgpool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(int(1024 * widen_factor), num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + x = self.dw2_1(x) + x = self.dw2_2(x) + x = self.dw3_1(x) + x = self.dw3_2(x) + x = self.dw4_1(x) + x = self.dw4_2(x) + x = self.dw5_1(x) + x = self.dw5_2(x) + x = self.dw5_3(x) + x = self.dw5_4(x) + x = self.dw5_5(x) + x = self.dw5_6(x) + x = self.dw6(x) + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + return x + + +def mobilenet(widen_factor=1.0, num_classes=1000): + """ + Construct MobileNet. + widen_factor=1.0 for mobilenet_1 + widen_factor=0.75 for mobilenet_075 + widen_factor=0.5 for mobilenet_05 + widen_factor=0.25 for mobilenet_025 + """ + model = MobileNet(widen_factor=widen_factor, num_classes=num_classes) + return model + + +def mobilenet_2(num_classes=62, input_channel=3): + model = MobileNet(widen_factor=2.0, num_classes=num_classes, input_channel=input_channel) + return model + + +def mobilenet_1(num_classes=62, input_channel=3): + model = MobileNet(widen_factor=1.0, num_classes=num_classes, input_channel=input_channel) + return model + + +def mobilenet_075(num_classes=62, input_channel=3): + model = MobileNet(widen_factor=0.75, num_classes=num_classes, input_channel=input_channel) + return model + + +def mobilenet_05(num_classes=62, input_channel=3): + model = MobileNet(widen_factor=0.5, num_classes=num_classes, input_channel=input_channel) + return model + + +def mobilenet_025(num_classes=62, input_channel=3): + model = MobileNet(widen_factor=0.25, num_classes=num_classes, input_channel=input_channel) + return model diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_1.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_1.py new file mode 100644 index 0000000000..43607ab14f --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_1.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +The pipeline of 3DDFA prediction: given one image, predict the 3d face vertices, 68 landmarks and visualization. + +[todo] +1. CPU optimization: https://pmchojnacki.wordpress.com/2018/10/07/slow-pytorch-cpu-performance +""" + +import torch +import torchvision.transforms as transforms +from . import mobilenet_v1 +import numpy as np +import cv2 +from os import path +import face_alignment +from .utils.ddfa import ToTensorGjz, NormalizeGjz +import scipy.io as sio +from .utils.inference import get_suffix, parse_roi_box_from_landmark, crop_img, predict_68pts, dump_to_ply, \ + dump_vertex, draw_landmarks, predict_dense, parse_roi_box_from_bbox, get_colors, write_obj_with_colors +from .utils.cv_plot import plot_pose_box +from .utils.estimate_pose import parse_pose +from .utils.render import cget_depths_image, cpncc +from .utils.paf import gen_img_paf +import torch.backends.cudnn as cudnn +import sys + +__author__ = 'cleardusk' +STD_SIZE = 120 + + +def main(args): + # 1. load pre-tained model + checkpoint_fp = 'algorithm/DDFA/models/phase1_wpdc_vdc.pth.tar' + arch = 'mobilenet_1' + + checkpoint = torch.load(checkpoint_fp, map_location=lambda storage, loc: storage)['state_dict'] + model = getattr(mobilenet_v1, arch)(num_classes=62) # 62 = 12(pose) + 40(shape) +10(expression) + + model_dict = model.state_dict() + # because the model is trained by multiple gpus, prefix module should be removed + for k in checkpoint.keys(): + model_dict[k.replace('module.', '')] = checkpoint[k] + model.load_state_dict(model_dict) + if args.mode == 'gpu': + cudnn.benchmark = True + model = model.cuda() + model.eval() + + ''' + # 2. load dlib model for face detection and landmark used for face cropping + if args.dlib_landmark: + dlib_landmark_model = 'models/shape_predictor_68_face_landmarks.dat' + face_regressor = dlib.shape_predictor(dlib_landmark_model) + if args.dlib_bbox: + face_detector = dlib.get_frontal_face_detector() + ''' + face_regressor = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, flip_input=False) + # face_detector = face_regressor.face_detector + + # 3. forward + tri = sio.loadmat('algorithm/DDFA/visualize/tri.mat')['tri'] + transform = transforms.Compose([ToTensorGjz(), NormalizeGjz(mean=127.5, std=128)]) + # print(args.files) + for img_fp in args.files: + print(img_fp) + suffix = get_suffix(img_fp) + wfp = '{}_{}.obj'.format(img_fp.replace(suffix, ''), 0) + if not path.exists(wfp): + img_ori = cv2.imread(img_fp) + if img_ori is None: + print("Can't load image, please check the path", file=sys.stderr) + sys.exit(1) + + try: + rect + except NameError: + rect = None + ''' + if args.dlib_bbox: + rects = face_detector(img_ori, 1) + else: + rects = [] + + if len(rects) == 0: + rects = dlib.rectangles() + rect_fp = img_fp + '.bbox' + lines = open(rect_fp).read().strip().split('\n')[1:] + for l in lines: + l, r, t, b = [int(_) for _ in l.split(' ')[1:]] + rect = dlib.rectangle(l, r, t, b) + rects.append(rect) + ''' + img_rgb = img_ori[:, :, ::-1] + ptss = face_regressor.get_landmarks(img_rgb) + pts_res = [] + Ps = [] # Camera matrix collection + poses = [] # pose collection, [todo: validate it] + vertices_lst = [] # store multiple face vertices + ind = 0 + + for pts in ptss: + # whether use dlib landmark to crop image, if not, use only face bbox to calc roi bbox for cropping + if args.dlib_landmark: + # - use landmark for cropping + # pts = face_regressor(img_ori, rect).parts() + # pts = np.array([[pt.x, pt.y] for pt in pts]).T + roi_box = parse_roi_box_from_landmark(pts.T) + else: + # - use detected face bbox + bbox = [rect.left(), rect.top(), rect.right(), rect.bottom()] + roi_box = parse_roi_box_from_bbox(bbox) + + img = crop_img(img_ori, roi_box) + + # forward: one step + img = cv2.resize(img, dsize=(STD_SIZE, STD_SIZE), interpolation=cv2.INTER_LINEAR) + input = transform(img).unsqueeze(0) + with torch.no_grad(): + if args.mode == 'gpu': + input = input.cuda() + param = model(input) + param = param.squeeze().cpu().numpy().flatten().astype(np.float32) + + # 68 pts + pts68 = predict_68pts(param, roi_box) + + # two-step for more accurate bbox to crop face + if args.bbox_init == 'two': + roi_box = parse_roi_box_from_landmark(pts68) + img_step2 = crop_img(img_ori, roi_box) + img_step2 = cv2.resize(img_step2, dsize=(STD_SIZE, STD_SIZE), interpolation=cv2.INTER_LINEAR) + input = transform(img_step2).unsqueeze(0) + with torch.no_grad(): + if args.mode == 'gpu': + input = input.cuda() + param = model(input) + param = param.squeeze().cpu().numpy().flatten().astype(np.float32) + + pts68 = predict_68pts(param, roi_box) + + pts_res.append(pts68) + P, pose = parse_pose(param) + Ps.append(P) + poses.append(pose) + + # dense face 3d vertices + if args.dump_ply or args.dump_vertex or args.dump_depth or args.dump_pncc or args.dump_obj: + vertices = predict_dense(param, roi_box) + vertices_lst.append(vertices) + if args.dump_ply: + dump_to_ply(vertices, tri, '{}_{}.ply'.format(img_fp.replace(suffix, ''), ind)) + if args.dump_vertex: + dump_vertex(vertices, '{}_{}.mat'.format(img_fp.replace(suffix, ''), ind)) + if args.dump_pts: + wfp = '{}_{}.txt'.format(img_fp.replace(suffix, ''), ind) + np.savetxt(wfp, pts68, fmt='%.3f') + print('Save 68 3d landmarks to {}'.format(wfp)) + if args.dump_roi_box: + wfp = '{}_{}.roibox'.format(img_fp.replace(suffix, ''), ind) + np.savetxt(wfp, roi_box, fmt='%.3f') + print('Save roi box to {}'.format(wfp)) + if args.dump_paf: + wfp_paf = '{}_{}_paf.jpg'.format(img_fp.replace(suffix, ''), ind) + wfp_crop = '{}_{}_crop.jpg'.format(img_fp.replace(suffix, ''), ind) + paf_feature = gen_img_paf(img_crop=img, param=param, kernel_size=args.paf_size) + + cv2.imwrite(wfp_paf, paf_feature) + cv2.imwrite(wfp_crop, img) + print('Dump to {} and {}'.format(wfp_crop, wfp_paf)) + if args.dump_obj: + wfp = '{}_{}.obj'.format(img_fp.replace(suffix, ''), ind) + colors = get_colors(img_ori, vertices) + write_obj_with_colors(wfp, vertices, tri, colors) + print('Dump obj with sampled texture to {}'.format(wfp)) + ind += 1 + + if args.dump_pose: + # P, pose = parse_pose(param) # Camera matrix (without scale), and pose (yaw, pitch, roll, to verify) + img_pose = plot_pose_box(img_ori, Ps, pts_res) + wfp = img_fp.replace(suffix, '_pose.jpg') + cv2.imwrite(wfp, img_pose) + print('Dump to {}'.format(wfp)) + if args.dump_depth: + wfp = img_fp.replace(suffix, '_depth.png') + # depths_img = get_depths_image(img_ori, vertices_lst, tri-1) # python version + depths_img = cget_depths_image(img_ori, vertices_lst, tri - 1) # cython version + cv2.imwrite(wfp, depths_img) + print('Dump to {}'.format(wfp)) + if args.dump_pncc: + wfp = img_fp.replace(suffix, '_pncc.png') + pncc_feature = cpncc(img_ori, vertices_lst, tri - 1) # cython version + cv2.imwrite(wfp, pncc_feature[:, :, ::-1]) # cv2.imwrite will swap RGB -> BGR + print('Dump to {}'.format(wfp)) + if args.dump_res: + draw_landmarks(img_ori, pts_res, wfp=img_fp.replace(suffix, '_3DDFA.jpg'), show_flg=args.show_flg) + else: + print("Main_Done") + + +''' +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='3DDFA inference pipeline') + parser.add_argument('-f', '--files', nargs='+', + help='image files paths fed into network, single or multiple images') + parser.add_argument('-m', '--mode', default='cpu', type=str, help='gpu or cpu mode') + parser.add_argument('--show_flg', default='true', type=str2bool, help='whether show the visualization result') + parser.add_argument('--bbox_init', default='one', type=str, + help='one|two: one-step bbox initialization or two-step') + parser.add_argument('--dump_res', default='true', type=str2bool, help='whether write out the visualization image') + parser.add_argument('--dump_vertex', default='false', type=str2bool, + help='whether write out the dense face vertices to mat') + parser.add_argument('--dump_ply', default='true', type=str2bool) + parser.add_argument('--dump_pts', default='true', type=str2bool) + parser.add_argument('--dump_roi_box', default='false', type=str2bool) + parser.add_argument('--dump_pose', default='true', type=str2bool) + parser.add_argument('--dump_depth', default='true', type=str2bool) + parser.add_argument('--dump_pncc', default='true', type=str2bool) + parser.add_argument('--dump_paf', default='true', type=str2bool) + parser.add_argument('--paf_size', default=3, type=int, help='PAF feature kernel size') + parser.add_argument('--dump_obj', default='true', type=str2bool) + parser.add_argument('--dlib_bbox', default='true', type=str2bool, help='whether use dlib to predict bbox') + parser.add_argument('--dlib_landmark', default='true', type=str2bool, + help='whether use dlib landmark to crop image') + + args = parser.parse_args() + main(args) +''' diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_2.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_2.py new file mode 100644 index 0000000000..821cf06b5a --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/preprocessing_2.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +The pipeline of 3DDFA prediction: given one image, predict the 3d face vertices, 68 landmarks and visualization. + +[todo] +1. CPU optimization: https://pmchojnacki.wordpress.com/2018/10/07/slow-pytorch-cpu-performance +""" + +import torch +import torchvision.transforms as transforms +from . import mobilenet_v1 +import numpy as np +import cv2 +import os +from tqdm import tqdm +import face_alignment +from .utils.ddfa import ToTensorGjz, NormalizeGjz +import scipy.io as sio +from .utils.inference import parse_roi_box_from_landmark, crop_img, predict_68pts, predict_dense, get_colors, \ + get_5lmk_from_68lmk +from .utils.estimate_pose import parse_pose +from .utils.params import param_mean, param_std +from .utils.render import crender_colors +import torch.backends.cudnn as cudnn +__author__ = 'cleardusk' +STD_SIZE = 120 + + +def main(args): + # 1. load pre-tained model + checkpoint_fp = 'algorithm/DDFA/models/phase1_wpdc_vdc.pth.tar' + arch = 'mobilenet_1' + + checkpoint = torch.load(checkpoint_fp, map_location=lambda storage, loc: storage)['state_dict'] + model = getattr(mobilenet_v1, arch)(num_classes=62) # 62 = 12(pose) + 40(shape) +10(expression) + + model_dict = model.state_dict() + # because the model is trained by multiple gpus, prefix module should be removed + for k in checkpoint.keys(): + model_dict[k.replace('module.', '')] = checkpoint[k] + model.load_state_dict(model_dict) + if args.mode == 'gpu': + cudnn.benchmark = True + model = model.cuda() + model.eval() + + tri = sio.loadmat('algorithm/DDFA/visualize/tri.mat')['tri'] + transform = transforms.Compose([ToTensorGjz(), NormalizeGjz(mean=127.5, std=128)]) + + # 2. parse images list + with open(args.img_list) as f: + img_list = [x.strip() for x in f.readlines()] + landmark_list = [] + + alignment_model = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, flip_input=False) + + if not os.path.exists(args.save_dir): + os.mkdir(args.save_dir) + if not os.path.exists(args.save_lmk_dir): + os.mkdir(args.save_lmk_dir) + + for img_idx, img_fp in enumerate(tqdm(img_list)): + img_ori = cv2.imread(os.path.join(args.img_prefix, img_fp)) + print("Image", img_fp) + pts_res = [] + Ps = [] # Camera matrix collection + poses = [] # pose collection, [todo: validate it] + # vertices_lst = [] # store multiple face vertices + # ind = 0 + # suffix = get_suffix(img_fp) + + # face alignment model use RGB as input, result is a tuple with landmarks and boxes + preds = alignment_model.get_landmarks(img_ori[:, :, ::-1]) + pts_2d_68 = preds[0] + pts_2d_5 = get_5lmk_from_68lmk(pts_2d_68) + landmark_list.append(pts_2d_5) + roi_box = parse_roi_box_from_landmark(pts_2d_68.T) + + img = crop_img(img_ori, roi_box) + # import pdb; pdb.set_trace() + + # forward: one step + img = cv2.resize(img, dsize=(STD_SIZE, STD_SIZE), interpolation=cv2.INTER_LINEAR) + input = transform(img).unsqueeze(0) + with torch.no_grad(): + if args.mode == 'gpu': + input = input.cuda() + param = model(input) + param = param.squeeze().cpu().numpy().flatten().astype(np.float32) + + # 68 pts + pts68 = predict_68pts(param, roi_box) + + # two-step for more accurate bbox to crop face + if args.bbox_init == 'two': + roi_box = parse_roi_box_from_landmark(pts68) + img_step2 = crop_img(img_ori, roi_box) + img_step2 = cv2.resize(img_step2, dsize=(STD_SIZE, STD_SIZE), interpolation=cv2.INTER_LINEAR) + input = transform(img_step2).unsqueeze(0) + with torch.no_grad(): + if args.mode == 'gpu': + input = input.cuda() + param = model(input) + param = param.squeeze().cpu().numpy().flatten().astype(np.float32) + + pts68 = predict_68pts(param, roi_box) + + pts_res.append(pts68) + P, pose = parse_pose(param) + Ps.append(P) + poses.append(pose) + + # dense face 3d vertices + vertices = predict_dense(param, roi_box) + + if args.dump_2d_img: + wfp_2d_img = os.path.join(args.save_dir, os.path.basename(img_fp)) + colors = get_colors(img_ori, vertices) + # aligned_param = get_aligned_param(param) + # vertices_aligned = predict_dense(aligned_param, roi_box) + # h, w, c = 120, 120, 3 + h, w, c = img_ori.shape + img_2d = crender_colors(vertices.T, (tri - 1).T, colors[:, ::-1], h, w) + cv2.imwrite(wfp_2d_img, img_2d[:, :, ::-1]) + if args.dump_param: + split = img_fp.split('/') + save_name = os.path.join(args.save_dir, '{}.txt'.format(os.path.splitext(split[-1])[0])) + this_param = param * param_std + param_mean + this_param = np.concatenate((this_param, roi_box)) + this_param.tofile(save_name, sep=' ') + if args.dump_lmk: + save_path = os.path.join(args.save_lmk_dir, 'realign_lmk_') + with open(save_path, 'w') as f: + for idx, (fname, land) in enumerate(zip(img_list, landmark_list)): + # f.write('{} {} {} {}') + land = land.astype(np.int) + land_str = ' '.join([str(x) for x in land]) + msg = f'{fname} {idx} {land_str}\n' + f.write(msg) + + +if __name__ == '__main__': + ''' + parser = argparse.ArgumentParser(description='3DDFA inference pipeline') + parser.add_argument('-m', '--mode', default='gpu', type=str, help='gpu or cpu mode') + parser.add_argument('--bbox_init', default='two', type=str, + help='one|two: one-step bbox initialization or two-step') + parser.add_argument('--dump_2d_img', default='true', type=str2bool, help='whether to save 3d rendered image') + parser.add_argument('--dump_param', default='true', type=str2bool, help='whether to save param') + parser.add_argument('--dump_lmk', default='true', type=str2bool, help='whether to save landmarks') + parser.add_argument('--save_dir', default='results', type=str, help='dir to save result') + parser.add_argument('--save_lmk_dir', default='example', type=str, help='dir to save landmark result') + parser.add_argument('--img_list', default='example/file_list.txt', type=str, help='test image list file') + parser.add_argument('--img_prefix', default='example/Images/', type=str, help='test image prefix') + parser.add_argument('--rank', default=0, type=int, help='used when parallel run') + parser.add_argument('--world_size', default=1, type=int, help='used when parallel run') + parser.add_argument('--resume_idx', default=0, type=int) + + args = parser.parse_args() + ''' + # main(args) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/simple_dataset.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/simple_dataset.py new file mode 100644 index 0000000000..44ac859e5c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/simple_dataset.py @@ -0,0 +1,39 @@ +from torch.utils.data import Dataset +import numpy as np +import cv2 +from utils.inference import crop_img, parse_roi_box_from_landmark + + +def cv2_loader(img_str): + img_array = np.frombuffer(img_str, dtype=np.uint8) + return cv2.imdecode(img_array, cv2.IMREAD_COLOR) + + +class McDataset(Dataset): + def __init__(self, img_list, landmarks, std_size=120, transform=None): + self.img_list = img_list + self.landmarks = landmarks + self.transform = transform + self.std_size = std_size + assert len(self.img_list) == len(self.landmarks) + self.num = len(self.img_list) + + self.initialized = False + + def __len__(self): + return self.num + + def __getitem__(self, idx): + filename = self.img_list[idx] + ori_img = cv2.imread(filename) + + landmark = self.landmarks[idx] + + # preprocess img + roi_box = parse_roi_box_from_landmark(landmark.T) + img = crop_img(ori_img, roi_box) + img = cv2.resize(img, dsize=(self.std_size, self.std_size), interpolation=cv2.INTER_LINEAR) + if self.transform is not None: + img = self.transform(img) + + return img, ori_img, filename, np.array(roi_box) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/test.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/test.py new file mode 100644 index 0000000000..59814bc726 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/test.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +The pipeline of 3DDFA prediction: given one image, predict the 3d face vertices, 68 landmarks and visualization. + +[todo] +1. CPU optimization: https://pmchojnacki.wordpress.com/2018/10/07/slow-pytorch-cpu-performance +""" + +import torch +import torchvision.transforms as transforms +import mobilenet_v1 +import numpy as np +import cv2 +import os +from tqdm import tqdm +import time +from utils.ddfa import ToTensorGjz, NormalizeGjz, str2bool +from utils.inference import parse_roi_box_from_landmark, crop_img, predict_68pts, parse_quality_list_part +from utils.params import param_mean, param_std +import argparse +import torch.backends.cudnn as cudnn +from simple_dataset import McDataset +from torch.utils.data import DataLoader +__author__ = 'cleardusk' +STD_SIZE = 120 + + +def main(args): + # 1. load pre-tained model + checkpoint_fp = 'models/phase1_wpdc_vdc.pth.tar' + arch = 'mobilenet_1' + + checkpoint = torch.load(checkpoint_fp, map_location=lambda storage, loc: storage)['state_dict'] + model = getattr(mobilenet_v1, arch)(num_classes=62) # 62 = 12(pose) + 40(shape) +10(expression) + + model_dict = model.state_dict() + # because the model is trained by multiple gpus, prefix module should be removed + for k in checkpoint.keys(): + model_dict[k.replace('module.', '')] = checkpoint[k] + model.load_state_dict(model_dict) + if args.mode == 'gpu': + cudnn.benchmark = True + model = model.cuda() + model.eval() + + # tri = sio.loadmat('visualize/tri.mat')['tri'] + transform = transforms.Compose([ToTensorGjz(), NormalizeGjz(mean=127.5, std=128)]) + + if not os.path.exists(args.save_dir): + os.mkdir(args.save_dir) + + # 2. parse images list and landmark + lmk_file = args.lmk_file + ts = time.time() + rank_land, rank_img_list, start, end = parse_quality_list_part(lmk_file, args.world_size, args.rank, + args.resume_idx) + print('parse land file in {:.3f} seconds'.format(time.time() - ts)) + + # for batch processing + print('World size {}, rank {}, start from {}, end with {}'.format(args.world_size, args.rank, start, end)) + dataset = McDataset(rank_img_list, rank_land, transform=transform, std_size=STD_SIZE) + dataloader = DataLoader(dataset, batch_size=args.batch_size, shuffle=False, num_workers=2, pin_memory=True) + + for img_idx, (inputs, ori_imgs, img_fps, roi_boxes) in enumerate(tqdm(dataloader)): + + # forward: one step + with torch.no_grad(): + if args.mode == 'gpu': + inputs = inputs.cuda() + params = model(inputs) + params = params.cpu().numpy() + + roi_boxes = roi_boxes.numpy() + outputs_roi_boxes = roi_boxes + if args.bbox_init == 'two': + step_two_ori_imgs = [] + step_two_roi_boxes = [] + ori_imgs = ori_imgs.numpy() + for ii in range(params.shape[0]): + # 68 pts + pts68 = predict_68pts(params[ii], roi_boxes[ii]) + + # two-step for more accurate bbox to crop face + roi_box = parse_roi_box_from_landmark(pts68) + img_step2 = crop_img(ori_imgs[ii], roi_box) + img_step2 = cv2.resize(img_step2, dsize=(STD_SIZE, STD_SIZE), interpolation=cv2.INTER_LINEAR) + # input = transform(img_step2).unsqueeze(0) + step_two_ori_imgs.append(transform(img_step2)) + step_two_roi_boxes.append(roi_box) + with torch.no_grad(): + step_two_ori_imgs = torch.stack(step_two_ori_imgs, dim=0) + inputs = step_two_ori_imgs + if args.mode == 'gpu': + inputs = inputs.cuda() + params = model(inputs) + params = params.cpu().numpy() + outputs_roi_boxes = step_two_roi_boxes + + # dump results + if args.dump_param: + for img_fp, param, roi_box in zip(img_fps, params, outputs_roi_boxes): + split = img_fp.split('/') + save_name = os.path.join(args.save_dir, '{}.txt'.format(os.path.splitext(split[-1])[0])) + this_param = param * param_std + param_mean + this_param = np.concatenate((this_param, roi_box)) + this_param.tofile(save_name, sep=' ') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='3DDFA inference pipeline') + parser.add_argument('-m', '--mode', default='gpu', type=str, help='gpu or cpu mode') + parser.add_argument('--bbox_init', default='two', type=str, + help='one|two: one-step bbox initialization or two-step') + parser.add_argument('--dump_2d_img', default='false', type=str2bool, help='whether to save 3d rendered image') + parser.add_argument('--dump_param', default='true', type=str2bool, help='whether to save param') + parser.add_argument('--save_dir', default='results', type=str, help='dir to save result') + parser.add_argument('--lmk_file', default='quality_list', type=str, help='landmarks file') + parser.add_argument('--rank', default=0, type=int, help='used when parallel run') + parser.add_argument('--world_size', default=1, type=int, help='used when parallel run') + parser.add_argument('--resume_idx', default=0, type=int) + parser.add_argument('--batch_size', default=80, type=int, help='batch size') + + args = parser.parse_args() + main(args) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cv_plot.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cv_plot.py new file mode 100644 index 0000000000..cb75eb1d27 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cv_plot.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# coding: utf-8 + + +""" +Modified from: https://sourcegraph.com/github.com/YadiraF/PRNet@master/-/blob/utils/cv_plot.py +""" + +import numpy as np +import cv2 + +from .inference import calc_hypotenuse + +end_list = np.array([17, 22, 27, 42, 48, 31, 36, 68], dtype=np.int32) - 1 + + +def plot_kpt(image, kpt): + ''' Draw 68 key points + Args: + image: the input image + kpt: (68, 3). + ''' + image = image.copy() + kpt = np.round(kpt).astype(np.int32) + for i in range(kpt.shape[0]): + st = kpt[i, :2] + image = cv2.circle(image, (st[0], st[1]), 1, (0, 0, 255), 2) + if i in end_list: + continue + ed = kpt[i + 1, :2] + image = cv2.line(image, (st[0], st[1]), (ed[0], ed[1]), (255, 255, 255), 1) + return image + + +def build_camera_box(rear_size=90): + point_3d = [] + rear_depth = 0 + point_3d.append((-rear_size, -rear_size, rear_depth)) + point_3d.append((-rear_size, rear_size, rear_depth)) + point_3d.append((rear_size, rear_size, rear_depth)) + point_3d.append((rear_size, -rear_size, rear_depth)) + point_3d.append((-rear_size, -rear_size, rear_depth)) + + front_size = int(4 / 3 * rear_size) + front_depth = int(4 / 3 * rear_size) + point_3d.append((-front_size, -front_size, front_depth)) + point_3d.append((-front_size, front_size, front_depth)) + point_3d.append((front_size, front_size, front_depth)) + point_3d.append((front_size, -front_size, front_depth)) + point_3d.append((-front_size, -front_size, front_depth)) + point_3d = np.array(point_3d, dtype=np.float).reshape(-1, 3) + + return point_3d + + +def plot_pose_box(image, Ps, pts68s, color=(40, 255, 0), line_width=2): + ''' Draw a 3D box as annotation of pose. Ref:https://github.com/yinguobing/head-pose-estimation/blob/master/pose_estimator.py + Args: + image: the input image + P: (3, 4). Affine Camera Matrix. + kpt: (2, 68) or (3, 68) + ''' + image = image.copy() + if not isinstance(pts68s, list): + pts68s = [pts68s] + if not isinstance(Ps, list): + Ps = [Ps] + for i in range(len(pts68s)): + pts68 = pts68s[i] + llength = calc_hypotenuse(pts68) + point_3d = build_camera_box(llength) + P = Ps[i] + + # Map to 2d image points + point_3d_homo = np.hstack((point_3d, np.ones([point_3d.shape[0], 1]))) # n x 4 + point_2d = point_3d_homo.dot(P.T)[:, :2] + + point_2d[:, 1] = - point_2d[:, 1] + point_2d[:, :2] = point_2d[:, :2] - np.mean(point_2d[:4, :2], 0) + np.mean(pts68[:2, :27], 1) + point_2d = np.int32(point_2d.reshape(-1, 2)) + + # Draw all the lines + cv2.polylines(image, [point_2d], True, color, line_width, cv2.LINE_AA) + cv2.line(image, tuple(point_2d[1]), tuple( + point_2d[6]), color, line_width, cv2.LINE_AA) + cv2.line(image, tuple(point_2d[2]), tuple( + point_2d[7]), color, line_width, cv2.LINE_AA) + cv2.line(image, tuple(point_2d[3]), tuple( + point_2d[8]), color, line_width, cv2.LINE_AA) + + return image + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.cpp b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.cpp new file mode 100644 index 0000000000..4f51572d82 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.cpp @@ -0,0 +1,215 @@ +/* +Author: Yao Feng (https://github.com/YadiraF) +Modified by cleardusk (https://github.com/cleardusk) +*/ + +#include "mesh_core.h" + +/* Judge whether the point is in the triangle +Method: + http://blackpawn.com/texts/pointinpoly/ +Args: + point: [x, y] + tri_points: three vertices(2d points) of a triangle. 2 coords x 3 vertices +Returns: + bool: true for in triangle +*/ +bool is_point_in_tri(point p, point p0, point p1, point p2) { + // vectors + point v0, v1, v2; + v0 = p2 - p0; + v1 = p1 - p0; + v2 = p - p0; + + // dot products + float dot00 = v0.dot(v0); //v0.x * v0.x + v0.y * v0.y //np.dot(v0.T, v0) + float dot01 = v0.dot(v1); //v0.x * v1.x + v0.y * v1.y //np.dot(v0.T, v1) + float dot02 = v0.dot(v2); //v0.x * v2.x + v0.y * v2.y //np.dot(v0.T, v2) + float dot11 = v1.dot(v1); //v1.x * v1.x + v1.y * v1.y //np.dot(v1.T, v1) + float dot12 = v1.dot(v2); //v1.x * v2.x + v1.y * v2.y//np.dot(v1.T, v2) + + // barycentric coordinates + float inverDeno; + if(dot00*dot11 - dot01*dot01 == 0) + inverDeno = 0; + else + inverDeno = 1/(dot00*dot11 - dot01*dot01); + + float u = (dot11*dot02 - dot01*dot12)*inverDeno; + float v = (dot00*dot12 - dot01*dot02)*inverDeno; + + // check if point in triangle + return (u >= 0) && (v >= 0) && (u + v < 1); +} + +void get_point_weight(float* weight, point p, point p0, point p1, point p2) { + // vectors + point v0, v1, v2; + v0 = p2 - p0; + v1 = p1 - p0; + v2 = p - p0; + + // dot products + float dot00 = v0.dot(v0); //v0.x * v0.x + v0.y * v0.y //np.dot(v0.T, v0) + float dot01 = v0.dot(v1); //v0.x * v1.x + v0.y * v1.y //np.dot(v0.T, v1) + float dot02 = v0.dot(v2); //v0.x * v2.x + v0.y * v2.y //np.dot(v0.T, v2) + float dot11 = v1.dot(v1); //v1.x * v1.x + v1.y * v1.y //np.dot(v1.T, v1) + float dot12 = v1.dot(v2); //v1.x * v2.x + v1.y * v2.y//np.dot(v1.T, v2) + + // barycentric coordinates + float inverDeno; + if(dot00*dot11 - dot01*dot01 == 0) + inverDeno = 0; + else + inverDeno = 1/(dot00*dot11 - dot01*dot01); + + float u = (dot11*dot02 - dot01*dot12)*inverDeno; + float v = (dot00*dot12 - dot01*dot02)*inverDeno; + + // weight + weight[0] = 1 - u - v; + weight[1] = v; + weight[2] = u; +} + +void _get_normal_core(float* normal, float* tri_normal, int* triangles, int ntri) { + int i, j; + int tri_p0_ind, tri_p1_ind, tri_p2_ind; + + for(i = 0; i < ntri; i++) + { + tri_p0_ind = triangles[3*i]; + tri_p1_ind = triangles[3*i + 1]; + tri_p2_ind = triangles[3*i + 2]; + + for(j = 0; j < 3; j++) + { + normal[3*tri_p0_ind + j] = normal[3*tri_p0_ind + j] + tri_normal[3*i + j]; + normal[3*tri_p1_ind + j] = normal[3*tri_p1_ind + j] + tri_normal[3*i + j]; + normal[3*tri_p2_ind + j] = normal[3*tri_p2_ind + j] + tri_normal[3*i + j]; + } + } +} + +void _get_normal(float *ver_normal, float *vertices, int *triangles, int nver, int ntri) { + int tri_p0_ind, tri_p1_ind, tri_p2_ind; + float v1x, v1y, v1z, v2x, v2y, v2z; + + // get tri_normal + std::vector tri_normal_vector(3 * ntri); + float* tri_normal = tri_normal_vector.data(); + for (int i = 0; i < ntri; i++) { + tri_p0_ind = triangles[3 * i]; + tri_p1_ind = triangles[3 * i + 1]; + tri_p2_ind = triangles[3 * i + 2]; + + // counter clockwise order + v1x = vertices[3 * tri_p1_ind] - vertices[3 * tri_p0_ind]; + v1y = vertices[3 * tri_p1_ind + 1] - vertices[3 * tri_p0_ind + 1]; + v1z = vertices[3 * tri_p1_ind + 2] - vertices[3 * tri_p0_ind + 2]; + + v2x = vertices[3 * tri_p2_ind] - vertices[3 * tri_p0_ind]; + v2y = vertices[3 * tri_p2_ind + 1] - vertices[3 * tri_p0_ind + 1]; + v2z = vertices[3 * tri_p2_ind + 2] - vertices[3 * tri_p0_ind + 2]; + + + tri_normal[3 * i] = v1y * v2z - v1z * v2y; + tri_normal[3 * i + 1] = v1z * v2x - v1x * v2z; + tri_normal[3 * i + 2] = v1x * v2y - v1y * v2x; + + } + + // get ver_normal + for (int i = 0; i < ntri; i++) { + tri_p0_ind = triangles[3 * i]; + tri_p1_ind = triangles[3 * i + 1]; + tri_p2_ind = triangles[3 * i + 2]; + + for (int j = 0; j < 3; j++) { + ver_normal[3 * tri_p0_ind + j] += tri_normal[3 * i + j]; + ver_normal[3 * tri_p1_ind + j] += tri_normal[3 * i + j]; + ver_normal[3 * tri_p2_ind + j] += tri_normal[3 * i + j]; + } + } + + // normalizing + float nx, ny, nz, det; + for (int i = 0; i < nver; ++i) { + nx = ver_normal[3 * i]; + ny = ver_normal[3 * i + 1]; + nz = ver_normal[3 * i + 2]; + + det = sqrt(nx * nx + ny * ny + nz * nz); +// if (det <= 0) det = 1e-6; + ver_normal[3 * i] = nx / det; + ver_normal[3 * i + 1] = ny / det; + ver_normal[3 * i + 2] = nz / det; + } +} + +void _render_colors_core( + float* image, float* vertices, int* triangles, + float* colors, + float* depth_buffer, + int nver, int ntri, + int h, int w, int c +) { + int i; + int x, y, k; + int tri_p0_ind, tri_p1_ind, tri_p2_ind; + point p0, p1, p2, p; + int x_min, x_max, y_min, y_max; + float p_depth, p0_depth, p1_depth, p2_depth; + float p_color, p0_color, p1_color, p2_color; + float weight[3]; + + for(i = 0; i < ntri; i++) + { + tri_p0_ind = triangles[3*i]; + tri_p1_ind = triangles[3*i + 1]; + tri_p2_ind = triangles[3*i + 2]; + + p0.x = vertices[3*tri_p0_ind]; p0.y = vertices[3*tri_p0_ind + 1]; p0_depth = vertices[3*tri_p0_ind + 2]; + p1.x = vertices[3*tri_p1_ind]; p1.y = vertices[3*tri_p1_ind + 1]; p1_depth = vertices[3*tri_p1_ind + 2]; + p2.x = vertices[3*tri_p2_ind]; p2.y = vertices[3*tri_p2_ind + 1]; p2_depth = vertices[3*tri_p2_ind + 2]; + + x_min = max((int)ceil(min(p0.x, min(p1.x, p2.x))), 0); + x_max = min((int)floor(max(p0.x, max(p1.x, p2.x))), w - 1); + + y_min = max((int)ceil(min(p0.y, min(p1.y, p2.y))), 0); + y_max = min((int)floor(max(p0.y, max(p1.y, p2.y))), h - 1); + + if(x_max < x_min || y_max < y_min) + { + continue; + } + + for(y = y_min; y <= y_max; y++) //h + { + for(x = x_min; x <= x_max; x++) //w + { + p.x = x; p.y = y; + if(is_point_in_tri(p, p0, p1, p2)) + { + get_point_weight(weight, p, p0, p1, p2); + p_depth = weight[0]*p0_depth + weight[1]*p1_depth + weight[2]*p2_depth; + + if((p_depth > depth_buffer[y*w + x])) + { + for(k = 0; k < c; k++) // c + { + p0_color = colors[c*tri_p0_ind + k]; + p1_color = colors[c*tri_p1_ind + k]; + p2_color = colors[c*tri_p2_ind + k]; + + p_color = weight[0]*p0_color + weight[1]*p1_color + weight[2]*p2_color; + image[y*w*c + x*c + k] = p_color; + } + + depth_buffer[y*w + x] = p_depth; + } + } + } + } + } +} diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.h b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.h new file mode 100644 index 0000000000..8a47153d34 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core.h @@ -0,0 +1,65 @@ +/* +Author: Yao Feng (https://github.com/YadiraF) +Modified by cleardusk (https://github.com/cleardusk) +*/ + +#ifndef MESH_CORE_HPP_ +#define MESH_CORE_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class point { + public: + float x; + float y; + + float dot(point p) + { + return this->x * p.x + this->y * p.y; + } + + point operator-(const point& p) + { + point np; + np.x = this->x - p.x; + np.y = this->y - p.y; + return np; + } + + point operator+(const point& p) + { + point np; + np.x = this->x + p.x; + np.y = this->y + p.y; + return np; + } + + point operator*(float s) + { + point np; + np.x = s * this->x; + np.y = s * this->y; + return np; + } +}; + +bool is_point_in_tri(point p, point p0, point p1, point p2, int h, int w); +void get_point_weight(float* weight, point p, point p0, point p1, point p2); +void _get_normal_core(float* normal, float* tri_normal, int* triangles, int ntri); +void _get_normal(float *ver_normal, float *vertices, int *triangles, int nver, int ntri); +void _render_colors_core( + float* image, float* vertices, int* triangles, + float* colors, + float* depth_buffer, + int nver, int ntri, + int h, int w, int c); + +#endif diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cp37-win_amd64.pyd b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cp37-win_amd64.pyd new file mode 100644 index 0000000000..5a2658ff06 Binary files /dev/null and b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cp37-win_amd64.pyd differ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cpp b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cpp new file mode 100644 index 0000000000..c64e963201 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.cpp @@ -0,0 +1,8365 @@ +/* Generated by Cython 0.29.6 */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) + #error Cython requires Python 2.6+ or Python 3.3+. +#else +#define CYTHON_ABI "0_29_6" +#define CYTHON_HEX_VERSION 0x001D06F0 +#define CYTHON_FUTURE_DIVISION 0 +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#define __PYX_COMMA , +#ifndef HAVE_LONG_LONG + #if PY_VERSION_HEX >= 0x02070000 + #define HAVE_LONG_LONG + #endif +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#ifdef PYPY_VERSION + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #if PY_VERSION_HEX < 0x03050000 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 +#elif defined(PYSTON_VERSION) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 + #undef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT 0 + #undef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE 0 + #undef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS 0 + #undef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYTYPE_LOOKUP + #define CYTHON_USE_PYTYPE_LOOKUP 0 + #elif !defined(CYTHON_USE_PYTYPE_LOOKUP) + #define CYTHON_USE_PYTYPE_LOOKUP 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLONG_INTERNALS) + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif + #ifndef CYTHON_PEP489_MULTI_PHASE_INIT + #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) + #endif + #ifndef CYTHON_USE_TP_FINALIZE + #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) + #endif + #ifndef CYTHON_USE_DICT_VERSIONS + #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1) + #endif + #ifndef CYTHON_USE_EXC_INFO_STACK + #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3) + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #include "longintrepr.h" + #undef SHIFT + #undef BASE + #undef MASK + #ifdef SIZEOF_VOID_P + enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; + #endif +#endif +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute + #define __has_cpp_attribute(x) 0 +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) +#ifdef _MSC_VER + #ifndef _MSC_STDINT_H_ + #if _MSC_VER < 1300 + typedef unsigned char uint8_t; + typedef unsigned int uint32_t; + #else + typedef unsigned __int8 uint8_t; + typedef unsigned __int32 uint32_t; + #endif + #endif +#else + #include +#endif +#ifndef CYTHON_FALLTHROUGH + #if defined(__cplusplus) && __cplusplus >= 201103L + #if __has_cpp_attribute(fallthrough) + #define CYTHON_FALLTHROUGH [[fallthrough]] + #elif __has_cpp_attribute(clang::fallthrough) + #define CYTHON_FALLTHROUGH [[clang::fallthrough]] + #elif __has_cpp_attribute(gnu::fallthrough) + #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] + #endif + #endif + #ifndef CYTHON_FALLTHROUGH + #if __has_attribute(fallthrough) + #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) + #else + #define CYTHON_FALLTHROUGH + #endif + #endif + #if defined(__clang__ ) && defined(__apple_build_version__) + #if __apple_build_version__ < 7000000 + #undef CYTHON_FALLTHROUGH + #define CYTHON_FALLTHROUGH + #endif + #endif +#endif + +#ifndef __cplusplus + #error "Cython files generated with the C++ option must be compiled with a C++ compiler." +#endif +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #else + #define CYTHON_INLINE inline + #endif +#endif +template +void __Pyx_call_destructor(T& x) { + x.~T(); +} +template +class __Pyx_FakeReference { + public: + __Pyx_FakeReference() : ptr(NULL) { } + __Pyx_FakeReference(const T& ref) : ptr(const_cast(&ref)) { } + T *operator->() { return ptr; } + T *operator&() { return ptr; } + operator T&() { return *ptr; } + template bool operator ==(U other) { return *ptr == other; } + template bool operator !=(U other) { return *ptr != other; } + private: + T *ptr; +}; + +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define Py_OptimizeFlag 0 +#endif +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyClass_Type +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyType_Type +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef METH_STACKLESS + #define METH_STACKLESS 0 +#endif +#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) + #ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + #endif + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); + typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #define __Pyx_PyCFunctionFast _PyCFunctionFast + #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords +#endif +#if CYTHON_FAST_PYCCALL +#define __Pyx_PyFastCFunction_Check(func)\ + ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))))) +#else +#define __Pyx_PyFastCFunction_Check(func) 0 +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030400A1 + #define PyMem_RawMalloc(n) PyMem_Malloc(n) + #define PyMem_RawRealloc(p, n) PyMem_Realloc(p, n) + #define PyMem_RawFree(p) PyMem_Free(p) +#endif +#if CYTHON_COMPILING_IN_PYSTON + #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#elif PY_VERSION_HEX >= 0x03060000 + #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() +#elif PY_VERSION_HEX >= 0x03000000 + #define __Pyx_PyThreadState_Current PyThreadState_GET() +#else + #define __Pyx_PyThreadState_Current _PyThreadState_Current +#endif +#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) +#include "pythread.h" +#define Py_tss_NEEDS_INIT 0 +typedef int Py_tss_t; +static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { + *key = PyThread_create_key(); + return 0; +} +static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { + Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); + *key = Py_tss_NEEDS_INIT; + return key; +} +static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { + PyObject_Free(key); +} +static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { + return *key != Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { + PyThread_delete_key(*key); + *key = Py_tss_NEEDS_INIT; +} +static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { + return PyThread_set_key_value(*key, value); +} +static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { + return PyThread_get_key_value(*key); +} +#endif +#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) +#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) +#else +#define __Pyx_PyDict_NewPresized(n) PyDict_New() +#endif +#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif +#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS +#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) +#else +#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name) +#endif +#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) + #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact + #define PyObject_Unicode PyObject_Str +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) +#endif +#if CYTHON_ASSUME_SAFE_MACROS + #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) +#else + #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t PyInt_AsLong +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) +#else + #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef __Pyx_PyAsyncMethodsStruct + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; +#endif + +#if defined(WIN32) || defined(MS_WINDOWS) + #define _USE_MATH_DEFINES +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + + +#define __PYX_ERR(f_index, lineno, Ln_error) \ +{ \ + __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ +} + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__mesh_core_cython +#define __PYX_HAVE_API__mesh_core_cython +/* Early includes */ +#include +#include +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" +#include "ios" +#include "new" +#include "stdexcept" +#include "typeinfo" +#include +#include "mesh_core.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { + return (size_t) i < (size_t) limit; +} +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) + #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) +#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { + const Py_UNICODE *u_end = u; + while (*u_end++) ; + return (size_t)(u_end - u - 1); +} +#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) +#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +#define __Pyx_PySequence_Tuple(obj)\ + (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ +static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } + +static PyObject *__pyx_m = NULL; +static PyObject *__pyx_d; +static PyObject *__pyx_b; +static PyObject *__pyx_cython_runtime = NULL; +static PyObject *__pyx_empty_tuple; +static PyObject *__pyx_empty_bytes; +static PyObject *__pyx_empty_unicode; +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm= __FILE__; +static const char *__pyx_filename; + +/* Header.proto */ +#if !defined(CYTHON_CCOMPLEX) + #if defined(__cplusplus) + #define CYTHON_CCOMPLEX 1 + #elif defined(_Complex_I) + #define CYTHON_CCOMPLEX 1 + #else + #define CYTHON_CCOMPLEX 0 + #endif +#endif +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + #include + #else + #include + #endif +#endif +#if CYTHON_CCOMPLEX && !defined(__cplusplus) && defined(__sun__) && defined(__GNUC__) + #undef _Complex_I + #define _Complex_I 1.0fj +#endif + + +static const char *__pyx_f[] = { + "mesh_core_cython.pyx", + "__init__.pxd", + "type.pxd", +}; +/* BufferFormatStructs.proto */ +#define IS_UNSIGNED(type) (((type) -1) > 0) +struct __Pyx_StructField_; +#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0) +typedef struct { + const char* name; + struct __Pyx_StructField_* fields; + size_t size; + size_t arraysize[8]; + int ndim; + char typegroup; + char is_unsigned; + int flags; +} __Pyx_TypeInfo; +typedef struct __Pyx_StructField_ { + __Pyx_TypeInfo* type; + const char* name; + size_t offset; +} __Pyx_StructField; +typedef struct { + __Pyx_StructField* field; + size_t parent_offset; +} __Pyx_BufFmt_StackElem; +typedef struct { + __Pyx_StructField root; + __Pyx_BufFmt_StackElem* head; + size_t fmt_offset; + size_t new_count, enc_count; + size_t struct_alignment; + int is_complex; + char enc_type; + char new_packmode; + char enc_packmode; + char is_valid_array; +} __Pyx_BufFmt_Context; + + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":776 + * # in Cython to enable them only on the right systems. + * + * ctypedef npy_int8 int8_t # <<<<<<<<<<<<<< + * ctypedef npy_int16 int16_t + * ctypedef npy_int32 int32_t + */ +typedef npy_int8 __pyx_t_5numpy_int8_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":777 + * + * ctypedef npy_int8 int8_t + * ctypedef npy_int16 int16_t # <<<<<<<<<<<<<< + * ctypedef npy_int32 int32_t + * ctypedef npy_int64 int64_t + */ +typedef npy_int16 __pyx_t_5numpy_int16_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":778 + * ctypedef npy_int8 int8_t + * ctypedef npy_int16 int16_t + * ctypedef npy_int32 int32_t # <<<<<<<<<<<<<< + * ctypedef npy_int64 int64_t + * #ctypedef npy_int96 int96_t + */ +typedef npy_int32 __pyx_t_5numpy_int32_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":779 + * ctypedef npy_int16 int16_t + * ctypedef npy_int32 int32_t + * ctypedef npy_int64 int64_t # <<<<<<<<<<<<<< + * #ctypedef npy_int96 int96_t + * #ctypedef npy_int128 int128_t + */ +typedef npy_int64 __pyx_t_5numpy_int64_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":783 + * #ctypedef npy_int128 int128_t + * + * ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<< + * ctypedef npy_uint16 uint16_t + * ctypedef npy_uint32 uint32_t + */ +typedef npy_uint8 __pyx_t_5numpy_uint8_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":784 + * + * ctypedef npy_uint8 uint8_t + * ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<< + * ctypedef npy_uint32 uint32_t + * ctypedef npy_uint64 uint64_t + */ +typedef npy_uint16 __pyx_t_5numpy_uint16_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":785 + * ctypedef npy_uint8 uint8_t + * ctypedef npy_uint16 uint16_t + * ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<< + * ctypedef npy_uint64 uint64_t + * #ctypedef npy_uint96 uint96_t + */ +typedef npy_uint32 __pyx_t_5numpy_uint32_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":786 + * ctypedef npy_uint16 uint16_t + * ctypedef npy_uint32 uint32_t + * ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<< + * #ctypedef npy_uint96 uint96_t + * #ctypedef npy_uint128 uint128_t + */ +typedef npy_uint64 __pyx_t_5numpy_uint64_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":790 + * #ctypedef npy_uint128 uint128_t + * + * ctypedef npy_float32 float32_t # <<<<<<<<<<<<<< + * ctypedef npy_float64 float64_t + * #ctypedef npy_float80 float80_t + */ +typedef npy_float32 __pyx_t_5numpy_float32_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":791 + * + * ctypedef npy_float32 float32_t + * ctypedef npy_float64 float64_t # <<<<<<<<<<<<<< + * #ctypedef npy_float80 float80_t + * #ctypedef npy_float128 float128_t + */ +typedef npy_float64 __pyx_t_5numpy_float64_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":800 + * # The int types are mapped a bit surprising -- + * # numpy.int corresponds to 'l' and numpy.long to 'q' + * ctypedef npy_long int_t # <<<<<<<<<<<<<< + * ctypedef npy_longlong long_t + * ctypedef npy_longlong longlong_t + */ +typedef npy_long __pyx_t_5numpy_int_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":801 + * # numpy.int corresponds to 'l' and numpy.long to 'q' + * ctypedef npy_long int_t + * ctypedef npy_longlong long_t # <<<<<<<<<<<<<< + * ctypedef npy_longlong longlong_t + * + */ +typedef npy_longlong __pyx_t_5numpy_long_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":802 + * ctypedef npy_long int_t + * ctypedef npy_longlong long_t + * ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<< + * + * ctypedef npy_ulong uint_t + */ +typedef npy_longlong __pyx_t_5numpy_longlong_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":804 + * ctypedef npy_longlong longlong_t + * + * ctypedef npy_ulong uint_t # <<<<<<<<<<<<<< + * ctypedef npy_ulonglong ulong_t + * ctypedef npy_ulonglong ulonglong_t + */ +typedef npy_ulong __pyx_t_5numpy_uint_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":805 + * + * ctypedef npy_ulong uint_t + * ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<< + * ctypedef npy_ulonglong ulonglong_t + * + */ +typedef npy_ulonglong __pyx_t_5numpy_ulong_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":806 + * ctypedef npy_ulong uint_t + * ctypedef npy_ulonglong ulong_t + * ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<< + * + * ctypedef npy_intp intp_t + */ +typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":808 + * ctypedef npy_ulonglong ulonglong_t + * + * ctypedef npy_intp intp_t # <<<<<<<<<<<<<< + * ctypedef npy_uintp uintp_t + * + */ +typedef npy_intp __pyx_t_5numpy_intp_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":809 + * + * ctypedef npy_intp intp_t + * ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<< + * + * ctypedef npy_double float_t + */ +typedef npy_uintp __pyx_t_5numpy_uintp_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":811 + * ctypedef npy_uintp uintp_t + * + * ctypedef npy_double float_t # <<<<<<<<<<<<<< + * ctypedef npy_double double_t + * ctypedef npy_longdouble longdouble_t + */ +typedef npy_double __pyx_t_5numpy_float_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":812 + * + * ctypedef npy_double float_t + * ctypedef npy_double double_t # <<<<<<<<<<<<<< + * ctypedef npy_longdouble longdouble_t + * + */ +typedef npy_double __pyx_t_5numpy_double_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":813 + * ctypedef npy_double float_t + * ctypedef npy_double double_t + * ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<< + * + * ctypedef npy_cfloat cfloat_t + */ +typedef npy_longdouble __pyx_t_5numpy_longdouble_t; +/* Declarations.proto */ +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + typedef ::std::complex< float > __pyx_t_float_complex; + #else + typedef float _Complex __pyx_t_float_complex; + #endif +#else + typedef struct { float real, imag; } __pyx_t_float_complex; +#endif +static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float, float); + +/* Declarations.proto */ +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + typedef ::std::complex< double > __pyx_t_double_complex; + #else + typedef double _Complex __pyx_t_double_complex; + #endif +#else + typedef struct { double real, imag; } __pyx_t_double_complex; +#endif +static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double, double); + + +/*--- Type declarations ---*/ + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":815 + * ctypedef npy_longdouble longdouble_t + * + * ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<< + * ctypedef npy_cdouble cdouble_t + * ctypedef npy_clongdouble clongdouble_t + */ +typedef npy_cfloat __pyx_t_5numpy_cfloat_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":816 + * + * ctypedef npy_cfloat cfloat_t + * ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<< + * ctypedef npy_clongdouble clongdouble_t + * + */ +typedef npy_cdouble __pyx_t_5numpy_cdouble_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":817 + * ctypedef npy_cfloat cfloat_t + * ctypedef npy_cdouble cdouble_t + * ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<< + * + * ctypedef npy_cdouble complex_t + */ +typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t; + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":819 + * ctypedef npy_clongdouble clongdouble_t + * + * ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<< + * + * cdef inline object PyArray_MultiIterNew1(a): + */ +typedef npy_cdouble __pyx_t_5numpy_complex_t; + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, int); + void (*DECREF)(void*, PyObject*, int); + void (*GOTREF)(void*, PyObject*, int); + void (*GIVEREF)(void*, PyObject*, int); + void* (*SetupContext)(const char*, int, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) +#endif + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ + const char* function_name); + +/* ArgTypeTest.proto */ +#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ + ((likely((Py_TYPE(obj) == type) | (none_allowed && (obj == Py_None)))) ? 1 :\ + __Pyx__ArgTypeTest(obj, type, name, exact)) +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); + +/* IsLittleEndian.proto */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void); + +/* BufferFormatCheck.proto */ +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts); +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type); + +/* BufferGetAndValidate.proto */ +#define __Pyx_GetBufferAndValidate(buf, obj, dtype, flags, nd, cast, stack)\ + ((obj == Py_None || obj == NULL) ?\ + (__Pyx_ZeroBuffer(buf), 0) :\ + __Pyx__GetBufferAndValidate(buf, obj, dtype, flags, nd, cast, stack)) +static int __Pyx__GetBufferAndValidate(Py_buffer* buf, PyObject* obj, + __Pyx_TypeInfo* dtype, int flags, int nd, int cast, __Pyx_BufFmt_StackElem* stack); +static void __Pyx_ZeroBuffer(Py_buffer* buf); +static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info); +static Py_ssize_t __Pyx_minusones[] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +static Py_ssize_t __Pyx_zeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* PyThreadStateGet.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; +#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; +#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type +#else +#define __Pyx_PyThreadState_declare +#define __Pyx_PyThreadState_assign +#define __Pyx_PyErr_Occurred() PyErr_Occurred() +#endif + +/* PyErrFetchRestore.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) +#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) +#else +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#endif +#else +#define __Pyx_PyErr_Clear() PyErr_Clear() +#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) +#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) +#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) +#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) +#endif + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* RaiseException.proto */ +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); + +/* PyCFunctionFastCall.proto */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); +#else +#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) +#endif + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs); +#else +#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) +#endif +#define __Pyx_BUILD_ASSERT_EXPR(cond)\ + (sizeof(char [1 - 2*!(cond)]) - 1) +#ifndef Py_MEMBER_SIZE +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) +#endif + static size_t __pyx_pyframe_localsplus_offset = 0; + #include "frameobject.h" + #define __Pxy_PyFrame_Initialize_Offsets()\ + ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ + (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) + #define __Pyx_PyFrame_GetLocalsplus(frame)\ + (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) +#endif + +/* PyObjectCallMethO.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); +#endif + +/* PyObjectCallOneArg.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); + +/* DictGetItem.proto */ +#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY +static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); +#define __Pyx_PyObject_Dict_GetItem(obj, name)\ + (likely(PyDict_CheckExact(obj)) ?\ + __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) +#else +#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) +#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) +#endif + +/* RaiseTooManyValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected); + +/* RaiseNeedMoreValuesToUnpack.proto */ +static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index); + +/* RaiseNoneIterError.proto */ +static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void); + +/* ExtTypeTest.proto */ +static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); + +/* GetTopmostException.proto */ +#if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); +#endif + +/* SaveResetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); +#else +#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) +#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) +#endif + +/* PyErrExceptionMatches.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) +static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); +#else +#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) +#endif + +/* GetException.proto */ +#if CYTHON_FAST_THREAD_STATE +#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); +#endif + +/* TypeImport.proto */ +#ifndef __PYX_HAVE_RT_ImportType_proto +#define __PYX_HAVE_RT_ImportType_proto +enum __Pyx_ImportType_CheckSize { + __Pyx_ImportType_CheckSize_Error = 0, + __Pyx_ImportType_CheckSize_Warn = 1, + __Pyx_ImportType_CheckSize_Ignore = 2 +}; +static PyTypeObject *__Pyx_ImportType(PyObject* module, const char *module_name, const char *class_name, size_t size, enum __Pyx_ImportType_CheckSize check_size); +#endif + +/* Import.proto */ +static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); + +/* PyDictVersioning.proto */ +#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) +#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ + (version_var) = __PYX_GET_DICT_VERSION(dict);\ + (cache_var) = (value); +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ + static PY_UINT64_T __pyx_dict_version = 0;\ + static PyObject *__pyx_dict_cached_value = NULL;\ + if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ + (VAR) = __pyx_dict_cached_value;\ + } else {\ + (VAR) = __pyx_dict_cached_value = (LOOKUP);\ + __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ + }\ +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); +#else +#define __PYX_GET_DICT_VERSION(dict) (0) +#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) +#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); +#endif + +/* CLineInTraceback.proto */ +#ifdef CYTHON_CLINE_IN_TRACEBACK +#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) +#else +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); +#endif + +/* CodeObjectCache.proto */ +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* BufferStructDeclare.proto */ +typedef struct { + Py_ssize_t shape, strides, suboffsets; +} __Pyx_Buf_DimInfo; +typedef struct { + size_t refcount; + Py_buffer pybuffer; +} __Pyx_Buffer; +typedef struct { + __Pyx_Buffer *rcbuffer; + char *data; + __Pyx_Buf_DimInfo diminfo[8]; +} __Pyx_LocalBuf_ND; + +#if PY_MAJOR_VERSION < 3 + static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); + static void __Pyx_ReleaseBuffer(Py_buffer *view); +#else + #define __Pyx_GetBuffer PyObject_GetBuffer + #define __Pyx_ReleaseBuffer PyBuffer_Release +#endif + + +/* RealImag.proto */ +#if CYTHON_CCOMPLEX + #ifdef __cplusplus + #define __Pyx_CREAL(z) ((z).real()) + #define __Pyx_CIMAG(z) ((z).imag()) + #else + #define __Pyx_CREAL(z) (__real__(z)) + #define __Pyx_CIMAG(z) (__imag__(z)) + #endif +#else + #define __Pyx_CREAL(z) ((z).real) + #define __Pyx_CIMAG(z) ((z).imag) +#endif +#if defined(__cplusplus) && CYTHON_CCOMPLEX\ + && (defined(_WIN32) || defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 5 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4 )) || __cplusplus >= 201103) + #define __Pyx_SET_CREAL(z,x) ((z).real(x)) + #define __Pyx_SET_CIMAG(z,y) ((z).imag(y)) +#else + #define __Pyx_SET_CREAL(z,x) __Pyx_CREAL(z) = (x) + #define __Pyx_SET_CIMAG(z,y) __Pyx_CIMAG(z) = (y) +#endif + +/* Arithmetic.proto */ +#if CYTHON_CCOMPLEX + #define __Pyx_c_eq_float(a, b) ((a)==(b)) + #define __Pyx_c_sum_float(a, b) ((a)+(b)) + #define __Pyx_c_diff_float(a, b) ((a)-(b)) + #define __Pyx_c_prod_float(a, b) ((a)*(b)) + #define __Pyx_c_quot_float(a, b) ((a)/(b)) + #define __Pyx_c_neg_float(a) (-(a)) + #ifdef __cplusplus + #define __Pyx_c_is_zero_float(z) ((z)==(float)0) + #define __Pyx_c_conj_float(z) (::std::conj(z)) + #if 1 + #define __Pyx_c_abs_float(z) (::std::abs(z)) + #define __Pyx_c_pow_float(a, b) (::std::pow(a, b)) + #endif + #else + #define __Pyx_c_is_zero_float(z) ((z)==0) + #define __Pyx_c_conj_float(z) (conjf(z)) + #if 1 + #define __Pyx_c_abs_float(z) (cabsf(z)) + #define __Pyx_c_pow_float(a, b) (cpowf(a, b)) + #endif + #endif +#else + static CYTHON_INLINE int __Pyx_c_eq_float(__pyx_t_float_complex, __pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sum_float(__pyx_t_float_complex, __pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_diff_float(__pyx_t_float_complex, __pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prod_float(__pyx_t_float_complex, __pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex, __pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_neg_float(__pyx_t_float_complex); + static CYTHON_INLINE int __Pyx_c_is_zero_float(__pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conj_float(__pyx_t_float_complex); + #if 1 + static CYTHON_INLINE float __Pyx_c_abs_float(__pyx_t_float_complex); + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_pow_float(__pyx_t_float_complex, __pyx_t_float_complex); + #endif +#endif + +/* Arithmetic.proto */ +#if CYTHON_CCOMPLEX + #define __Pyx_c_eq_double(a, b) ((a)==(b)) + #define __Pyx_c_sum_double(a, b) ((a)+(b)) + #define __Pyx_c_diff_double(a, b) ((a)-(b)) + #define __Pyx_c_prod_double(a, b) ((a)*(b)) + #define __Pyx_c_quot_double(a, b) ((a)/(b)) + #define __Pyx_c_neg_double(a) (-(a)) + #ifdef __cplusplus + #define __Pyx_c_is_zero_double(z) ((z)==(double)0) + #define __Pyx_c_conj_double(z) (::std::conj(z)) + #if 1 + #define __Pyx_c_abs_double(z) (::std::abs(z)) + #define __Pyx_c_pow_double(a, b) (::std::pow(a, b)) + #endif + #else + #define __Pyx_c_is_zero_double(z) ((z)==0) + #define __Pyx_c_conj_double(z) (conj(z)) + #if 1 + #define __Pyx_c_abs_double(z) (cabs(z)) + #define __Pyx_c_pow_double(a, b) (cpow(a, b)) + #endif + #endif +#else + static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex, __pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex); + static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex); + #if 1 + static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex); + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex, __pyx_t_double_complex); + #endif +#endif + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* FastTypeChecks.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); +static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); +#else +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) +#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) +#endif +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(void); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + + +/* Module declarations from 'cpython.buffer' */ + +/* Module declarations from 'libc.string' */ + +/* Module declarations from 'libc.stdio' */ + +/* Module declarations from '__builtin__' */ + +/* Module declarations from 'cpython.type' */ +static PyTypeObject *__pyx_ptype_7cpython_4type_type = 0; + +/* Module declarations from 'cpython' */ + +/* Module declarations from 'cpython.object' */ + +/* Module declarations from 'cpython.ref' */ + +/* Module declarations from 'cpython.mem' */ + +/* Module declarations from 'numpy' */ + +/* Module declarations from 'numpy' */ +static PyTypeObject *__pyx_ptype_5numpy_dtype = 0; +static PyTypeObject *__pyx_ptype_5numpy_flatiter = 0; +static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0; +static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0; +static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0; +static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/ +static CYTHON_INLINE int __pyx_f_5numpy_import_array(void); /*proto*/ + +/* Module declarations from 'libcpp.string' */ + +/* Module declarations from 'cython' */ + +/* Module declarations from 'mesh_core_cython' */ +static __Pyx_TypeInfo __Pyx_TypeInfo_float = { "float", NULL, sizeof(float), { 0 }, 0, 'R', 0, 0 }; +static __Pyx_TypeInfo __Pyx_TypeInfo_int = { "int", NULL, sizeof(int), { 0 }, 0, IS_UNSIGNED(int) ? 'U' : 'I', IS_UNSIGNED(int), 0 }; +#define __Pyx_MODULE_NAME "mesh_core_cython" +extern int __pyx_module_is_main_mesh_core_cython; +int __pyx_module_is_main_mesh_core_cython = 0; + +/* Implementation of 'mesh_core_cython' */ +static PyObject *__pyx_builtin_ValueError; +static PyObject *__pyx_builtin_range; +static PyObject *__pyx_builtin_RuntimeError; +static PyObject *__pyx_builtin_ImportError; +static const char __pyx_k_c[] = "c"; +static const char __pyx_k_h[] = "h"; +static const char __pyx_k_w[] = "w"; +static const char __pyx_k_np[] = "np"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_name[] = "__name__"; +static const char __pyx_k_ntri[] = "ntri"; +static const char __pyx_k_nver[] = "nver"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_image[] = "image"; +static const char __pyx_k_numpy[] = "numpy"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_colors[] = "colors"; +static const char __pyx_k_import[] = "__import__"; +static const char __pyx_k_normal[] = "normal"; +static const char __pyx_k_vertices[] = "vertices"; +static const char __pyx_k_triangles[] = "triangles"; +static const char __pyx_k_ValueError[] = "ValueError"; +static const char __pyx_k_get_normal[] = "get_normal"; +static const char __pyx_k_tri_normal[] = "tri_normal"; +static const char __pyx_k_ver_normal[] = "ver_normal"; +static const char __pyx_k_ImportError[] = "ImportError"; +static const char __pyx_k_RuntimeError[] = "RuntimeError"; +static const char __pyx_k_depth_buffer[] = "depth_buffer"; +static const char __pyx_k_get_normal_core[] = "get_normal_core"; +static const char __pyx_k_mesh_core_cython[] = "mesh_core_cython"; +static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; +static const char __pyx_k_render_colors_core[] = "render_colors_core"; +static const char __pyx_k_mesh_core_cython_pyx[] = "mesh_core_cython.pyx"; +static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous"; +static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import"; +static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)"; +static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd"; +static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported"; +static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous"; +static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import"; +static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short."; +static PyObject *__pyx_kp_u_Format_string_allocated_too_shor; +static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2; +static PyObject *__pyx_n_s_ImportError; +static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor; +static PyObject *__pyx_n_s_RuntimeError; +static PyObject *__pyx_n_s_ValueError; +static PyObject *__pyx_n_s_c; +static PyObject *__pyx_n_s_cline_in_traceback; +static PyObject *__pyx_n_s_colors; +static PyObject *__pyx_n_s_depth_buffer; +static PyObject *__pyx_n_s_get_normal; +static PyObject *__pyx_n_s_get_normal_core; +static PyObject *__pyx_n_s_h; +static PyObject *__pyx_n_s_image; +static PyObject *__pyx_n_s_import; +static PyObject *__pyx_n_s_main; +static PyObject *__pyx_n_s_mesh_core_cython; +static PyObject *__pyx_kp_s_mesh_core_cython_pyx; +static PyObject *__pyx_n_s_name; +static PyObject *__pyx_kp_u_ndarray_is_not_C_contiguous; +static PyObject *__pyx_kp_u_ndarray_is_not_Fortran_contiguou; +static PyObject *__pyx_n_s_normal; +static PyObject *__pyx_n_s_np; +static PyObject *__pyx_n_s_ntri; +static PyObject *__pyx_n_s_numpy; +static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to; +static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor; +static PyObject *__pyx_n_s_nver; +static PyObject *__pyx_n_s_range; +static PyObject *__pyx_n_s_render_colors_core; +static PyObject *__pyx_n_s_test; +static PyObject *__pyx_n_s_tri_normal; +static PyObject *__pyx_n_s_triangles; +static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd; +static PyObject *__pyx_n_s_ver_normal; +static PyObject *__pyx_n_s_vertices; +static PyObject *__pyx_n_s_w; +static PyObject *__pyx_pf_16mesh_core_cython_get_normal_core(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_normal, PyArrayObject *__pyx_v_tri_normal, PyArrayObject *__pyx_v_triangles, int __pyx_v_ntri); /* proto */ +static PyObject *__pyx_pf_16mesh_core_cython_2render_colors_core(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_image, PyArrayObject *__pyx_v_vertices, PyArrayObject *__pyx_v_triangles, PyArrayObject *__pyx_v_colors, PyArrayObject *__pyx_v_depth_buffer, int __pyx_v_nver, int __pyx_v_ntri, int __pyx_v_h, int __pyx_v_w, int __pyx_v_c); /* proto */ +static PyObject *__pyx_pf_16mesh_core_cython_4get_normal(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_ver_normal, PyArrayObject *__pyx_v_vertices, PyArrayObject *__pyx_v_triangles, int __pyx_v_nver, int __pyx_v_ntri); /* proto */ +static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */ +static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */ +static PyObject *__pyx_tuple_; +static PyObject *__pyx_tuple__2; +static PyObject *__pyx_tuple__3; +static PyObject *__pyx_tuple__4; +static PyObject *__pyx_tuple__5; +static PyObject *__pyx_tuple__6; +static PyObject *__pyx_tuple__7; +static PyObject *__pyx_tuple__8; +static PyObject *__pyx_tuple__10; +static PyObject *__pyx_tuple__12; +static PyObject *__pyx_codeobj__9; +static PyObject *__pyx_codeobj__11; +static PyObject *__pyx_codeobj__13; +/* Late includes */ + +/* "mesh_core_cython.pyx":29 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_16mesh_core_cython_1get_normal_core(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_16mesh_core_cython_1get_normal_core = {"get_normal_core", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_16mesh_core_cython_1get_normal_core, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_16mesh_core_cython_1get_normal_core(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyArrayObject *__pyx_v_normal = 0; + PyArrayObject *__pyx_v_tri_normal = 0; + PyArrayObject *__pyx_v_triangles = 0; + int __pyx_v_ntri; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_normal_core (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_normal,&__pyx_n_s_tri_normal,&__pyx_n_s_triangles,&__pyx_n_s_ntri,0}; + PyObject* values[4] = {0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_normal)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_tri_normal)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal_core", 1, 4, 4, 1); __PYX_ERR(0, 29, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_triangles)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal_core", 1, 4, 4, 2); __PYX_ERR(0, 29, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_ntri)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal_core", 1, 4, 4, 3); __PYX_ERR(0, 29, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "get_normal_core") < 0)) __PYX_ERR(0, 29, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 4) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + } + __pyx_v_normal = ((PyArrayObject *)values[0]); + __pyx_v_tri_normal = ((PyArrayObject *)values[1]); + __pyx_v_triangles = ((PyArrayObject *)values[2]); + __pyx_v_ntri = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_ntri == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 32, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("get_normal_core", 1, 4, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 29, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mesh_core_cython.get_normal_core", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_normal), __pyx_ptype_5numpy_ndarray, 0, "normal", 0))) __PYX_ERR(0, 29, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_tri_normal), __pyx_ptype_5numpy_ndarray, 0, "tri_normal", 0))) __PYX_ERR(0, 30, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_triangles), __pyx_ptype_5numpy_ndarray, 0, "triangles", 0))) __PYX_ERR(0, 31, __pyx_L1_error) + __pyx_r = __pyx_pf_16mesh_core_cython_get_normal_core(__pyx_self, __pyx_v_normal, __pyx_v_tri_normal, __pyx_v_triangles, __pyx_v_ntri); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_16mesh_core_cython_get_normal_core(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_normal, PyArrayObject *__pyx_v_tri_normal, PyArrayObject *__pyx_v_triangles, int __pyx_v_ntri) { + __Pyx_LocalBuf_ND __pyx_pybuffernd_normal; + __Pyx_Buffer __pyx_pybuffer_normal; + __Pyx_LocalBuf_ND __pyx_pybuffernd_tri_normal; + __Pyx_Buffer __pyx_pybuffer_tri_normal; + __Pyx_LocalBuf_ND __pyx_pybuffernd_triangles; + __Pyx_Buffer __pyx_pybuffer_triangles; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_normal_core", 0); + __pyx_pybuffer_normal.pybuffer.buf = NULL; + __pyx_pybuffer_normal.refcount = 0; + __pyx_pybuffernd_normal.data = NULL; + __pyx_pybuffernd_normal.rcbuffer = &__pyx_pybuffer_normal; + __pyx_pybuffer_tri_normal.pybuffer.buf = NULL; + __pyx_pybuffer_tri_normal.refcount = 0; + __pyx_pybuffernd_tri_normal.data = NULL; + __pyx_pybuffernd_tri_normal.rcbuffer = &__pyx_pybuffer_tri_normal; + __pyx_pybuffer_triangles.pybuffer.buf = NULL; + __pyx_pybuffer_triangles.refcount = 0; + __pyx_pybuffernd_triangles.data = NULL; + __pyx_pybuffernd_triangles.rcbuffer = &__pyx_pybuffer_triangles; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_normal.rcbuffer->pybuffer, (PyObject*)__pyx_v_normal, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 29, __pyx_L1_error) + } + __pyx_pybuffernd_normal.diminfo[0].strides = __pyx_pybuffernd_normal.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_normal.diminfo[0].shape = __pyx_pybuffernd_normal.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_normal.diminfo[1].strides = __pyx_pybuffernd_normal.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_normal.diminfo[1].shape = __pyx_pybuffernd_normal.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_tri_normal.rcbuffer->pybuffer, (PyObject*)__pyx_v_tri_normal, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 29, __pyx_L1_error) + } + __pyx_pybuffernd_tri_normal.diminfo[0].strides = __pyx_pybuffernd_tri_normal.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_tri_normal.diminfo[0].shape = __pyx_pybuffernd_tri_normal.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_tri_normal.diminfo[1].strides = __pyx_pybuffernd_tri_normal.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_tri_normal.diminfo[1].shape = __pyx_pybuffernd_tri_normal.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer, (PyObject*)__pyx_v_triangles, &__Pyx_TypeInfo_int, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 29, __pyx_L1_error) + } + __pyx_pybuffernd_triangles.diminfo[0].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_triangles.diminfo[0].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_triangles.diminfo[1].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_triangles.diminfo[1].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[1]; + + /* "mesh_core_cython.pyx":34 + * int ntri + * ): + * _get_normal_core( # <<<<<<<<<<<<<< + * np.PyArray_DATA(normal), np.PyArray_DATA(tri_normal), np.PyArray_DATA(triangles), + * ntri + */ + _get_normal_core(((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_normal))), ((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_tri_normal))), ((int *)PyArray_DATA(((PyArrayObject *)__pyx_v_triangles))), __pyx_v_ntri); + + /* "mesh_core_cython.pyx":29 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + { PyObject *__pyx_type, *__pyx_value, *__pyx_tb; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_tri_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);} + __Pyx_AddTraceback("mesh_core_cython.get_normal_core", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + goto __pyx_L2; + __pyx_L0:; + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_tri_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __pyx_L2:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mesh_core_cython.pyx":41 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_16mesh_core_cython_3render_colors_core(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_16mesh_core_cython_3render_colors_core = {"render_colors_core", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_16mesh_core_cython_3render_colors_core, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_16mesh_core_cython_3render_colors_core(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyArrayObject *__pyx_v_image = 0; + PyArrayObject *__pyx_v_vertices = 0; + PyArrayObject *__pyx_v_triangles = 0; + PyArrayObject *__pyx_v_colors = 0; + PyArrayObject *__pyx_v_depth_buffer = 0; + int __pyx_v_nver; + int __pyx_v_ntri; + int __pyx_v_h; + int __pyx_v_w; + int __pyx_v_c; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("render_colors_core (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_image,&__pyx_n_s_vertices,&__pyx_n_s_triangles,&__pyx_n_s_colors,&__pyx_n_s_depth_buffer,&__pyx_n_s_nver,&__pyx_n_s_ntri,&__pyx_n_s_h,&__pyx_n_s_w,&__pyx_n_s_c,0}; + PyObject* values[10] = {0,0,0,0,0,0,0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 10: values[9] = PyTuple_GET_ITEM(__pyx_args, 9); + CYTHON_FALLTHROUGH; + case 9: values[8] = PyTuple_GET_ITEM(__pyx_args, 8); + CYTHON_FALLTHROUGH; + case 8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7); + CYTHON_FALLTHROUGH; + case 7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6); + CYTHON_FALLTHROUGH; + case 6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + CYTHON_FALLTHROUGH; + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_image)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_vertices)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 1); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_triangles)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 2); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_colors)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 3); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_depth_buffer)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 4); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 5: + if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nver)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 5); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 6: + if (likely((values[6] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_ntri)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 6); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 7: + if (likely((values[7] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_h)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 7); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 8: + if (likely((values[8] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_w)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 8); __PYX_ERR(0, 41, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 9: + if (likely((values[9] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_c)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, 9); __PYX_ERR(0, 41, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "render_colors_core") < 0)) __PYX_ERR(0, 41, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 10) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + values[6] = PyTuple_GET_ITEM(__pyx_args, 6); + values[7] = PyTuple_GET_ITEM(__pyx_args, 7); + values[8] = PyTuple_GET_ITEM(__pyx_args, 8); + values[9] = PyTuple_GET_ITEM(__pyx_args, 9); + } + __pyx_v_image = ((PyArrayObject *)values[0]); + __pyx_v_vertices = ((PyArrayObject *)values[1]); + __pyx_v_triangles = ((PyArrayObject *)values[2]); + __pyx_v_colors = ((PyArrayObject *)values[3]); + __pyx_v_depth_buffer = ((PyArrayObject *)values[4]); + __pyx_v_nver = __Pyx_PyInt_As_int(values[5]); if (unlikely((__pyx_v_nver == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error) + __pyx_v_ntri = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_ntri == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 46, __pyx_L3_error) + __pyx_v_h = __Pyx_PyInt_As_int(values[7]); if (unlikely((__pyx_v_h == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 47, __pyx_L3_error) + __pyx_v_w = __Pyx_PyInt_As_int(values[8]); if (unlikely((__pyx_v_w == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 47, __pyx_L3_error) + __pyx_v_c = __Pyx_PyInt_As_int(values[9]); if (unlikely((__pyx_v_c == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 47, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("render_colors_core", 1, 10, 10, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 41, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mesh_core_cython.render_colors_core", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_image), __pyx_ptype_5numpy_ndarray, 0, "image", 0))) __PYX_ERR(0, 41, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vertices), __pyx_ptype_5numpy_ndarray, 0, "vertices", 0))) __PYX_ERR(0, 42, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_triangles), __pyx_ptype_5numpy_ndarray, 0, "triangles", 0))) __PYX_ERR(0, 43, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_colors), __pyx_ptype_5numpy_ndarray, 0, "colors", 0))) __PYX_ERR(0, 44, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_depth_buffer), __pyx_ptype_5numpy_ndarray, 0, "depth_buffer", 0))) __PYX_ERR(0, 45, __pyx_L1_error) + __pyx_r = __pyx_pf_16mesh_core_cython_2render_colors_core(__pyx_self, __pyx_v_image, __pyx_v_vertices, __pyx_v_triangles, __pyx_v_colors, __pyx_v_depth_buffer, __pyx_v_nver, __pyx_v_ntri, __pyx_v_h, __pyx_v_w, __pyx_v_c); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_16mesh_core_cython_2render_colors_core(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_image, PyArrayObject *__pyx_v_vertices, PyArrayObject *__pyx_v_triangles, PyArrayObject *__pyx_v_colors, PyArrayObject *__pyx_v_depth_buffer, int __pyx_v_nver, int __pyx_v_ntri, int __pyx_v_h, int __pyx_v_w, int __pyx_v_c) { + __Pyx_LocalBuf_ND __pyx_pybuffernd_colors; + __Pyx_Buffer __pyx_pybuffer_colors; + __Pyx_LocalBuf_ND __pyx_pybuffernd_depth_buffer; + __Pyx_Buffer __pyx_pybuffer_depth_buffer; + __Pyx_LocalBuf_ND __pyx_pybuffernd_image; + __Pyx_Buffer __pyx_pybuffer_image; + __Pyx_LocalBuf_ND __pyx_pybuffernd_triangles; + __Pyx_Buffer __pyx_pybuffer_triangles; + __Pyx_LocalBuf_ND __pyx_pybuffernd_vertices; + __Pyx_Buffer __pyx_pybuffer_vertices; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("render_colors_core", 0); + __pyx_pybuffer_image.pybuffer.buf = NULL; + __pyx_pybuffer_image.refcount = 0; + __pyx_pybuffernd_image.data = NULL; + __pyx_pybuffernd_image.rcbuffer = &__pyx_pybuffer_image; + __pyx_pybuffer_vertices.pybuffer.buf = NULL; + __pyx_pybuffer_vertices.refcount = 0; + __pyx_pybuffernd_vertices.data = NULL; + __pyx_pybuffernd_vertices.rcbuffer = &__pyx_pybuffer_vertices; + __pyx_pybuffer_triangles.pybuffer.buf = NULL; + __pyx_pybuffer_triangles.refcount = 0; + __pyx_pybuffernd_triangles.data = NULL; + __pyx_pybuffernd_triangles.rcbuffer = &__pyx_pybuffer_triangles; + __pyx_pybuffer_colors.pybuffer.buf = NULL; + __pyx_pybuffer_colors.refcount = 0; + __pyx_pybuffernd_colors.data = NULL; + __pyx_pybuffernd_colors.rcbuffer = &__pyx_pybuffer_colors; + __pyx_pybuffer_depth_buffer.pybuffer.buf = NULL; + __pyx_pybuffer_depth_buffer.refcount = 0; + __pyx_pybuffernd_depth_buffer.data = NULL; + __pyx_pybuffernd_depth_buffer.rcbuffer = &__pyx_pybuffer_depth_buffer; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_image.rcbuffer->pybuffer, (PyObject*)__pyx_v_image, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 3, 0, __pyx_stack) == -1)) __PYX_ERR(0, 41, __pyx_L1_error) + } + __pyx_pybuffernd_image.diminfo[0].strides = __pyx_pybuffernd_image.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_image.diminfo[0].shape = __pyx_pybuffernd_image.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_image.diminfo[1].strides = __pyx_pybuffernd_image.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_image.diminfo[1].shape = __pyx_pybuffernd_image.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_image.diminfo[2].strides = __pyx_pybuffernd_image.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_image.diminfo[2].shape = __pyx_pybuffernd_image.rcbuffer->pybuffer.shape[2]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer, (PyObject*)__pyx_v_vertices, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 41, __pyx_L1_error) + } + __pyx_pybuffernd_vertices.diminfo[0].strides = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_vertices.diminfo[0].shape = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_vertices.diminfo[1].strides = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_vertices.diminfo[1].shape = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer, (PyObject*)__pyx_v_triangles, &__Pyx_TypeInfo_int, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 41, __pyx_L1_error) + } + __pyx_pybuffernd_triangles.diminfo[0].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_triangles.diminfo[0].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_triangles.diminfo[1].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_triangles.diminfo[1].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_colors.rcbuffer->pybuffer, (PyObject*)__pyx_v_colors, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 41, __pyx_L1_error) + } + __pyx_pybuffernd_colors.diminfo[0].strides = __pyx_pybuffernd_colors.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_colors.diminfo[0].shape = __pyx_pybuffernd_colors.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_colors.diminfo[1].strides = __pyx_pybuffernd_colors.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_colors.diminfo[1].shape = __pyx_pybuffernd_colors.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer, (PyObject*)__pyx_v_depth_buffer, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 41, __pyx_L1_error) + } + __pyx_pybuffernd_depth_buffer.diminfo[0].strides = __pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_depth_buffer.diminfo[0].shape = __pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_depth_buffer.diminfo[1].strides = __pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_depth_buffer.diminfo[1].shape = __pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer.shape[1]; + + /* "mesh_core_cython.pyx":49 + * int h, int w, int c + * ): + * _render_colors_core( # <<<<<<<<<<<<<< + * np.PyArray_DATA(image), np.PyArray_DATA(vertices), np.PyArray_DATA(triangles), + * np.PyArray_DATA(colors), + */ + _render_colors_core(((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_image))), ((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_vertices))), ((int *)PyArray_DATA(((PyArrayObject *)__pyx_v_triangles))), ((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_colors))), ((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_depth_buffer))), __pyx_v_nver, __pyx_v_ntri, __pyx_v_h, __pyx_v_w, __pyx_v_c); + + /* "mesh_core_cython.pyx":41 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + { PyObject *__pyx_type, *__pyx_value, *__pyx_tb; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_colors.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_image.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer); + __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);} + __Pyx_AddTraceback("mesh_core_cython.render_colors_core", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + goto __pyx_L2; + __pyx_L0:; + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_colors.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_depth_buffer.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_image.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer); + __pyx_L2:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "mesh_core_cython.pyx":59 + * @cython.boundscheck(False) # turn off bounds-checking for entire function + * @cython.wraparound(False) # turn off negative index wrapping for entire function + * def get_normal(np.ndarray[float, ndim=2, mode = "c"] ver_normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_16mesh_core_cython_5get_normal(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_16mesh_core_cython_5get_normal = {"get_normal", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_16mesh_core_cython_5get_normal, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_16mesh_core_cython_5get_normal(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + PyArrayObject *__pyx_v_ver_normal = 0; + PyArrayObject *__pyx_v_vertices = 0; + PyArrayObject *__pyx_v_triangles = 0; + int __pyx_v_nver; + int __pyx_v_ntri; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_normal (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_ver_normal,&__pyx_n_s_vertices,&__pyx_n_s_triangles,&__pyx_n_s_nver,&__pyx_n_s_ntri,0}; + PyObject* values[5] = {0,0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + CYTHON_FALLTHROUGH; + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + CYTHON_FALLTHROUGH; + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + CYTHON_FALLTHROUGH; + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + CYTHON_FALLTHROUGH; + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + CYTHON_FALLTHROUGH; + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_ver_normal)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + CYTHON_FALLTHROUGH; + case 1: + if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_vertices)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal", 1, 5, 5, 1); __PYX_ERR(0, 59, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 2: + if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_triangles)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal", 1, 5, 5, 2); __PYX_ERR(0, 59, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 3: + if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_nver)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal", 1, 5, 5, 3); __PYX_ERR(0, 59, __pyx_L3_error) + } + CYTHON_FALLTHROUGH; + case 4: + if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_ntri)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("get_normal", 1, 5, 5, 4); __PYX_ERR(0, 59, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "get_normal") < 0)) __PYX_ERR(0, 59, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 5) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + } + __pyx_v_ver_normal = ((PyArrayObject *)values[0]); + __pyx_v_vertices = ((PyArrayObject *)values[1]); + __pyx_v_triangles = ((PyArrayObject *)values[2]); + __pyx_v_nver = __Pyx_PyInt_As_int(values[3]); if (unlikely((__pyx_v_nver == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 62, __pyx_L3_error) + __pyx_v_ntri = __Pyx_PyInt_As_int(values[4]); if (unlikely((__pyx_v_ntri == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 62, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("get_normal", 1, 5, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 59, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("mesh_core_cython.get_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_ver_normal), __pyx_ptype_5numpy_ndarray, 0, "ver_normal", 0))) __PYX_ERR(0, 59, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_vertices), __pyx_ptype_5numpy_ndarray, 0, "vertices", 0))) __PYX_ERR(0, 60, __pyx_L1_error) + if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_triangles), __pyx_ptype_5numpy_ndarray, 0, "triangles", 0))) __PYX_ERR(0, 61, __pyx_L1_error) + __pyx_r = __pyx_pf_16mesh_core_cython_4get_normal(__pyx_self, __pyx_v_ver_normal, __pyx_v_vertices, __pyx_v_triangles, __pyx_v_nver, __pyx_v_ntri); + + /* function exit code */ + goto __pyx_L0; + __pyx_L1_error:; + __pyx_r = NULL; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_16mesh_core_cython_4get_normal(CYTHON_UNUSED PyObject *__pyx_self, PyArrayObject *__pyx_v_ver_normal, PyArrayObject *__pyx_v_vertices, PyArrayObject *__pyx_v_triangles, int __pyx_v_nver, int __pyx_v_ntri) { + __Pyx_LocalBuf_ND __pyx_pybuffernd_triangles; + __Pyx_Buffer __pyx_pybuffer_triangles; + __Pyx_LocalBuf_ND __pyx_pybuffernd_ver_normal; + __Pyx_Buffer __pyx_pybuffer_ver_normal; + __Pyx_LocalBuf_ND __pyx_pybuffernd_vertices; + __Pyx_Buffer __pyx_pybuffer_vertices; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_normal", 0); + __pyx_pybuffer_ver_normal.pybuffer.buf = NULL; + __pyx_pybuffer_ver_normal.refcount = 0; + __pyx_pybuffernd_ver_normal.data = NULL; + __pyx_pybuffernd_ver_normal.rcbuffer = &__pyx_pybuffer_ver_normal; + __pyx_pybuffer_vertices.pybuffer.buf = NULL; + __pyx_pybuffer_vertices.refcount = 0; + __pyx_pybuffernd_vertices.data = NULL; + __pyx_pybuffernd_vertices.rcbuffer = &__pyx_pybuffer_vertices; + __pyx_pybuffer_triangles.pybuffer.buf = NULL; + __pyx_pybuffer_triangles.refcount = 0; + __pyx_pybuffernd_triangles.data = NULL; + __pyx_pybuffernd_triangles.rcbuffer = &__pyx_pybuffer_triangles; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_ver_normal.rcbuffer->pybuffer, (PyObject*)__pyx_v_ver_normal, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 59, __pyx_L1_error) + } + __pyx_pybuffernd_ver_normal.diminfo[0].strides = __pyx_pybuffernd_ver_normal.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_ver_normal.diminfo[0].shape = __pyx_pybuffernd_ver_normal.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_ver_normal.diminfo[1].strides = __pyx_pybuffernd_ver_normal.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_ver_normal.diminfo[1].shape = __pyx_pybuffernd_ver_normal.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer, (PyObject*)__pyx_v_vertices, &__Pyx_TypeInfo_float, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 59, __pyx_L1_error) + } + __pyx_pybuffernd_vertices.diminfo[0].strides = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_vertices.diminfo[0].shape = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_vertices.diminfo[1].strides = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_vertices.diminfo[1].shape = __pyx_pybuffernd_vertices.rcbuffer->pybuffer.shape[1]; + { + __Pyx_BufFmt_StackElem __pyx_stack[1]; + if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer, (PyObject*)__pyx_v_triangles, &__Pyx_TypeInfo_int, PyBUF_FORMAT| PyBUF_C_CONTIGUOUS, 2, 0, __pyx_stack) == -1)) __PYX_ERR(0, 59, __pyx_L1_error) + } + __pyx_pybuffernd_triangles.diminfo[0].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_triangles.diminfo[0].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_triangles.diminfo[1].strides = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_triangles.diminfo[1].shape = __pyx_pybuffernd_triangles.rcbuffer->pybuffer.shape[1]; + + /* "mesh_core_cython.pyx":63 + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + * int nver, int ntri): + * _get_normal( # <<<<<<<<<<<<<< + * np.PyArray_DATA(ver_normal), np.PyArray_DATA(vertices), np.PyArray_DATA(triangles), + * nver, ntri) + */ + _get_normal(((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_ver_normal))), ((float *)PyArray_DATA(((PyArrayObject *)__pyx_v_vertices))), ((int *)PyArray_DATA(((PyArrayObject *)__pyx_v_triangles))), __pyx_v_nver, __pyx_v_ntri); + + /* "mesh_core_cython.pyx":59 + * @cython.boundscheck(False) # turn off bounds-checking for entire function + * @cython.wraparound(False) # turn off negative index wrapping for entire function + * def get_normal(np.ndarray[float, ndim=2, mode = "c"] ver_normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + + /* function exit code */ + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + { PyObject *__pyx_type, *__pyx_value, *__pyx_tb; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_ver_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer); + __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);} + __Pyx_AddTraceback("mesh_core_cython.get_normal", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + goto __pyx_L2; + __pyx_L0:; + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_triangles.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_ver_normal.rcbuffer->pybuffer); + __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_vertices.rcbuffer->pybuffer); + __pyx_L2:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":258 + * # experimental exception made for __getbuffer__ and __releasebuffer__ + * # -- the details of this may change. + * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< + * # This implementation of getbuffer is geared towards Cython + * # requirements, and does not yet fulfill the PEP. + */ + +/* Python wrapper */ +static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/ +static CYTHON_UNUSED int __pyx_pw_5numpy_7ndarray_1__getbuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_r; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__getbuffer__ (wrapper)", 0); + __pyx_r = __pyx_pf_5numpy_7ndarray___getbuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info), ((int)__pyx_v_flags)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags) { + int __pyx_v_i; + int __pyx_v_ndim; + int __pyx_v_endian_detector; + int __pyx_v_little_endian; + int __pyx_v_t; + char *__pyx_v_f; + PyArray_Descr *__pyx_v_descr = 0; + int __pyx_v_offset; + int __pyx_r; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + int __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + int __pyx_t_5; + int __pyx_t_6; + PyArray_Descr *__pyx_t_7; + PyObject *__pyx_t_8 = NULL; + char *__pyx_t_9; + if (__pyx_v_info == NULL) { + PyErr_SetString(PyExc_BufferError, "PyObject_GetBuffer: view==NULL argument is obsolete"); + return -1; + } + __Pyx_RefNannySetupContext("__getbuffer__", 0); + __pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None); + __Pyx_GIVEREF(__pyx_v_info->obj); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":265 + * + * cdef int i, ndim + * cdef int endian_detector = 1 # <<<<<<<<<<<<<< + * cdef bint little_endian = ((&endian_detector)[0] != 0) + * + */ + __pyx_v_endian_detector = 1; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":266 + * cdef int i, ndim + * cdef int endian_detector = 1 + * cdef bint little_endian = ((&endian_detector)[0] != 0) # <<<<<<<<<<<<<< + * + * ndim = PyArray_NDIM(self) + */ + __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":268 + * cdef bint little_endian = ((&endian_detector)[0] != 0) + * + * ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<< + * + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) + */ + __pyx_v_ndim = PyArray_NDIM(__pyx_v_self); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":270 + * ndim = PyArray_NDIM(self) + * + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): + * raise ValueError(u"ndarray is not C contiguous") + */ + __pyx_t_2 = (((__pyx_v_flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L4_bool_binop_done; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":271 + * + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): # <<<<<<<<<<<<<< + * raise ValueError(u"ndarray is not C contiguous") + * + */ + __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_C_CONTIGUOUS) != 0)) != 0); + __pyx_t_1 = __pyx_t_2; + __pyx_L4_bool_binop_done:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":270 + * ndim = PyArray_NDIM(self) + * + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): + * raise ValueError(u"ndarray is not C contiguous") + */ + if (unlikely(__pyx_t_1)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":272 + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): + * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 272, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":270 + * ndim = PyArray_NDIM(self) + * + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): + * raise ValueError(u"ndarray is not C contiguous") + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":274 + * raise ValueError(u"ndarray is not C contiguous") + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): + * raise ValueError(u"ndarray is not Fortran contiguous") + */ + __pyx_t_2 = (((__pyx_v_flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L7_bool_binop_done; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":275 + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): # <<<<<<<<<<<<<< + * raise ValueError(u"ndarray is not Fortran contiguous") + * + */ + __pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_ARRAY_F_CONTIGUOUS) != 0)) != 0); + __pyx_t_1 = __pyx_t_2; + __pyx_L7_bool_binop_done:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":274 + * raise ValueError(u"ndarray is not C contiguous") + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): + * raise ValueError(u"ndarray is not Fortran contiguous") + */ + if (unlikely(__pyx_t_1)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":276 + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): + * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< + * + * info.buf = PyArray_DATA(self) + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 276, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":274 + * raise ValueError(u"ndarray is not C contiguous") + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<< + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): + * raise ValueError(u"ndarray is not Fortran contiguous") + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":278 + * raise ValueError(u"ndarray is not Fortran contiguous") + * + * info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<< + * info.ndim = ndim + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + */ + __pyx_v_info->buf = PyArray_DATA(__pyx_v_self); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":279 + * + * info.buf = PyArray_DATA(self) + * info.ndim = ndim # <<<<<<<<<<<<<< + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + * # Allocate new buffer for strides and shape info. + */ + __pyx_v_info->ndim = __pyx_v_ndim; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":280 + * info.buf = PyArray_DATA(self) + * info.ndim = ndim + * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< + * # Allocate new buffer for strides and shape info. + * # This is allocated as one block, strides first. + */ + __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":283 + * # Allocate new buffer for strides and shape info. + * # This is allocated as one block, strides first. + * info.strides = PyObject_Malloc(sizeof(Py_ssize_t) * 2 * ndim) # <<<<<<<<<<<<<< + * info.shape = info.strides + ndim + * for i in range(ndim): + */ + __pyx_v_info->strides = ((Py_ssize_t *)PyObject_Malloc((((sizeof(Py_ssize_t)) * 2) * ((size_t)__pyx_v_ndim)))); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":284 + * # This is allocated as one block, strides first. + * info.strides = PyObject_Malloc(sizeof(Py_ssize_t) * 2 * ndim) + * info.shape = info.strides + ndim # <<<<<<<<<<<<<< + * for i in range(ndim): + * info.strides[i] = PyArray_STRIDES(self)[i] + */ + __pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":285 + * info.strides = PyObject_Malloc(sizeof(Py_ssize_t) * 2 * ndim) + * info.shape = info.strides + ndim + * for i in range(ndim): # <<<<<<<<<<<<<< + * info.strides[i] = PyArray_STRIDES(self)[i] + * info.shape[i] = PyArray_DIMS(self)[i] + */ + __pyx_t_4 = __pyx_v_ndim; + __pyx_t_5 = __pyx_t_4; + for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) { + __pyx_v_i = __pyx_t_6; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":286 + * info.shape = info.strides + ndim + * for i in range(ndim): + * info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<< + * info.shape[i] = PyArray_DIMS(self)[i] + * else: + */ + (__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":287 + * for i in range(ndim): + * info.strides[i] = PyArray_STRIDES(self)[i] + * info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<< + * else: + * info.strides = PyArray_STRIDES(self) + */ + (__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]); + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":280 + * info.buf = PyArray_DATA(self) + * info.ndim = ndim + * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< + * # Allocate new buffer for strides and shape info. + * # This is allocated as one block, strides first. + */ + goto __pyx_L9; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":289 + * info.shape[i] = PyArray_DIMS(self)[i] + * else: + * info.strides = PyArray_STRIDES(self) # <<<<<<<<<<<<<< + * info.shape = PyArray_DIMS(self) + * info.suboffsets = NULL + */ + /*else*/ { + __pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self)); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":290 + * else: + * info.strides = PyArray_STRIDES(self) + * info.shape = PyArray_DIMS(self) # <<<<<<<<<<<<<< + * info.suboffsets = NULL + * info.itemsize = PyArray_ITEMSIZE(self) + */ + __pyx_v_info->shape = ((Py_ssize_t *)PyArray_DIMS(__pyx_v_self)); + } + __pyx_L9:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":291 + * info.strides = PyArray_STRIDES(self) + * info.shape = PyArray_DIMS(self) + * info.suboffsets = NULL # <<<<<<<<<<<<<< + * info.itemsize = PyArray_ITEMSIZE(self) + * info.readonly = not PyArray_ISWRITEABLE(self) + */ + __pyx_v_info->suboffsets = NULL; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":292 + * info.shape = PyArray_DIMS(self) + * info.suboffsets = NULL + * info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<< + * info.readonly = not PyArray_ISWRITEABLE(self) + * + */ + __pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":293 + * info.suboffsets = NULL + * info.itemsize = PyArray_ITEMSIZE(self) + * info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<< + * + * cdef int t + */ + __pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0)); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":296 + * + * cdef int t + * cdef char* f = NULL # <<<<<<<<<<<<<< + * cdef dtype descr = PyArray_DESCR(self) + * cdef int offset + */ + __pyx_v_f = NULL; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":297 + * cdef int t + * cdef char* f = NULL + * cdef dtype descr = PyArray_DESCR(self) # <<<<<<<<<<<<<< + * cdef int offset + * + */ + __pyx_t_7 = PyArray_DESCR(__pyx_v_self); + __pyx_t_3 = ((PyObject *)__pyx_t_7); + __Pyx_INCREF(__pyx_t_3); + __pyx_v_descr = ((PyArray_Descr *)__pyx_t_3); + __pyx_t_3 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":300 + * cdef int offset + * + * info.obj = self # <<<<<<<<<<<<<< + * + * if not PyDataType_HASFIELDS(descr): + */ + __Pyx_INCREF(((PyObject *)__pyx_v_self)); + __Pyx_GIVEREF(((PyObject *)__pyx_v_self)); + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); + __pyx_v_info->obj = ((PyObject *)__pyx_v_self); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":302 + * info.obj = self + * + * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or + */ + __pyx_t_1 = ((!(PyDataType_HASFIELDS(__pyx_v_descr) != 0)) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":303 + * + * if not PyDataType_HASFIELDS(descr): + * t = descr.type_num # <<<<<<<<<<<<<< + * if ((descr.byteorder == c'>' and little_endian) or + * (descr.byteorder == c'<' and not little_endian)): + */ + __pyx_t_4 = __pyx_v_descr->type_num; + __pyx_v_t = __pyx_t_4; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":304 + * if not PyDataType_HASFIELDS(descr): + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + __pyx_t_2 = ((__pyx_v_descr->byteorder == '>') != 0); + if (!__pyx_t_2) { + goto __pyx_L15_next_or; + } else { + } + __pyx_t_2 = (__pyx_v_little_endian != 0); + if (!__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L14_bool_binop_done; + } + __pyx_L15_next_or:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":305 + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or + * (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< + * raise ValueError(u"Non-native byte order not supported") + * if t == NPY_BYTE: f = "b" + */ + __pyx_t_2 = ((__pyx_v_descr->byteorder == '<') != 0); + if (__pyx_t_2) { + } else { + __pyx_t_1 = __pyx_t_2; + goto __pyx_L14_bool_binop_done; + } + __pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0); + __pyx_t_1 = __pyx_t_2; + __pyx_L14_bool_binop_done:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":304 + * if not PyDataType_HASFIELDS(descr): + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + if (unlikely(__pyx_t_1)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":306 + * if ((descr.byteorder == c'>' and little_endian) or + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< + * if t == NPY_BYTE: f = "b" + * elif t == NPY_UBYTE: f = "B" + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 306, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 306, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":304 + * if not PyDataType_HASFIELDS(descr): + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":307 + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + * if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<< + * elif t == NPY_UBYTE: f = "B" + * elif t == NPY_SHORT: f = "h" + */ + switch (__pyx_v_t) { + case NPY_BYTE: + __pyx_v_f = ((char *)"b"); + break; + case NPY_UBYTE: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":308 + * raise ValueError(u"Non-native byte order not supported") + * if t == NPY_BYTE: f = "b" + * elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<< + * elif t == NPY_SHORT: f = "h" + * elif t == NPY_USHORT: f = "H" + */ + __pyx_v_f = ((char *)"B"); + break; + case NPY_SHORT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":309 + * if t == NPY_BYTE: f = "b" + * elif t == NPY_UBYTE: f = "B" + * elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<< + * elif t == NPY_USHORT: f = "H" + * elif t == NPY_INT: f = "i" + */ + __pyx_v_f = ((char *)"h"); + break; + case NPY_USHORT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":310 + * elif t == NPY_UBYTE: f = "B" + * elif t == NPY_SHORT: f = "h" + * elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<< + * elif t == NPY_INT: f = "i" + * elif t == NPY_UINT: f = "I" + */ + __pyx_v_f = ((char *)"H"); + break; + case NPY_INT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":311 + * elif t == NPY_SHORT: f = "h" + * elif t == NPY_USHORT: f = "H" + * elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<< + * elif t == NPY_UINT: f = "I" + * elif t == NPY_LONG: f = "l" + */ + __pyx_v_f = ((char *)"i"); + break; + case NPY_UINT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":312 + * elif t == NPY_USHORT: f = "H" + * elif t == NPY_INT: f = "i" + * elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<< + * elif t == NPY_LONG: f = "l" + * elif t == NPY_ULONG: f = "L" + */ + __pyx_v_f = ((char *)"I"); + break; + case NPY_LONG: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":313 + * elif t == NPY_INT: f = "i" + * elif t == NPY_UINT: f = "I" + * elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<< + * elif t == NPY_ULONG: f = "L" + * elif t == NPY_LONGLONG: f = "q" + */ + __pyx_v_f = ((char *)"l"); + break; + case NPY_ULONG: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":314 + * elif t == NPY_UINT: f = "I" + * elif t == NPY_LONG: f = "l" + * elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<< + * elif t == NPY_LONGLONG: f = "q" + * elif t == NPY_ULONGLONG: f = "Q" + */ + __pyx_v_f = ((char *)"L"); + break; + case NPY_LONGLONG: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":315 + * elif t == NPY_LONG: f = "l" + * elif t == NPY_ULONG: f = "L" + * elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<< + * elif t == NPY_ULONGLONG: f = "Q" + * elif t == NPY_FLOAT: f = "f" + */ + __pyx_v_f = ((char *)"q"); + break; + case NPY_ULONGLONG: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":316 + * elif t == NPY_ULONG: f = "L" + * elif t == NPY_LONGLONG: f = "q" + * elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<< + * elif t == NPY_FLOAT: f = "f" + * elif t == NPY_DOUBLE: f = "d" + */ + __pyx_v_f = ((char *)"Q"); + break; + case NPY_FLOAT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":317 + * elif t == NPY_LONGLONG: f = "q" + * elif t == NPY_ULONGLONG: f = "Q" + * elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<< + * elif t == NPY_DOUBLE: f = "d" + * elif t == NPY_LONGDOUBLE: f = "g" + */ + __pyx_v_f = ((char *)"f"); + break; + case NPY_DOUBLE: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":318 + * elif t == NPY_ULONGLONG: f = "Q" + * elif t == NPY_FLOAT: f = "f" + * elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<< + * elif t == NPY_LONGDOUBLE: f = "g" + * elif t == NPY_CFLOAT: f = "Zf" + */ + __pyx_v_f = ((char *)"d"); + break; + case NPY_LONGDOUBLE: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":319 + * elif t == NPY_FLOAT: f = "f" + * elif t == NPY_DOUBLE: f = "d" + * elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<< + * elif t == NPY_CFLOAT: f = "Zf" + * elif t == NPY_CDOUBLE: f = "Zd" + */ + __pyx_v_f = ((char *)"g"); + break; + case NPY_CFLOAT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":320 + * elif t == NPY_DOUBLE: f = "d" + * elif t == NPY_LONGDOUBLE: f = "g" + * elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<< + * elif t == NPY_CDOUBLE: f = "Zd" + * elif t == NPY_CLONGDOUBLE: f = "Zg" + */ + __pyx_v_f = ((char *)"Zf"); + break; + case NPY_CDOUBLE: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":321 + * elif t == NPY_LONGDOUBLE: f = "g" + * elif t == NPY_CFLOAT: f = "Zf" + * elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<< + * elif t == NPY_CLONGDOUBLE: f = "Zg" + * elif t == NPY_OBJECT: f = "O" + */ + __pyx_v_f = ((char *)"Zd"); + break; + case NPY_CLONGDOUBLE: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":322 + * elif t == NPY_CFLOAT: f = "Zf" + * elif t == NPY_CDOUBLE: f = "Zd" + * elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<< + * elif t == NPY_OBJECT: f = "O" + * else: + */ + __pyx_v_f = ((char *)"Zg"); + break; + case NPY_OBJECT: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":323 + * elif t == NPY_CDOUBLE: f = "Zd" + * elif t == NPY_CLONGDOUBLE: f = "Zg" + * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<< + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) + */ + __pyx_v_f = ((char *)"O"); + break; + default: + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":325 + * elif t == NPY_OBJECT: f = "O" + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< + * info.format = f + * return + */ + __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 325, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_8 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 325, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 325, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 325, __pyx_L1_error) + break; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":326 + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) + * info.format = f # <<<<<<<<<<<<<< + * return + * else: + */ + __pyx_v_info->format = __pyx_v_f; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":327 + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) + * info.format = f + * return # <<<<<<<<<<<<<< + * else: + * info.format = PyObject_Malloc(_buffer_format_string_len) + */ + __pyx_r = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":302 + * info.obj = self + * + * if not PyDataType_HASFIELDS(descr): # <<<<<<<<<<<<<< + * t = descr.type_num + * if ((descr.byteorder == c'>' and little_endian) or + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":329 + * return + * else: + * info.format = PyObject_Malloc(_buffer_format_string_len) # <<<<<<<<<<<<<< + * info.format[0] = c'^' # Native data types, manual alignment + * offset = 0 + */ + /*else*/ { + __pyx_v_info->format = ((char *)PyObject_Malloc(0xFF)); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":330 + * else: + * info.format = PyObject_Malloc(_buffer_format_string_len) + * info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<< + * offset = 0 + * f = _util_dtypestring(descr, info.format + 1, + */ + (__pyx_v_info->format[0]) = '^'; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":331 + * info.format = PyObject_Malloc(_buffer_format_string_len) + * info.format[0] = c'^' # Native data types, manual alignment + * offset = 0 # <<<<<<<<<<<<<< + * f = _util_dtypestring(descr, info.format + 1, + * info.format + _buffer_format_string_len, + */ + __pyx_v_offset = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":332 + * info.format[0] = c'^' # Native data types, manual alignment + * offset = 0 + * f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<< + * info.format + _buffer_format_string_len, + * &offset) + */ + __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(1, 332, __pyx_L1_error) + __pyx_v_f = __pyx_t_9; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":335 + * info.format + _buffer_format_string_len, + * &offset) + * f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<< + * + * def __releasebuffer__(ndarray self, Py_buffer* info): + */ + (__pyx_v_f[0]) = '\x00'; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":258 + * # experimental exception made for __getbuffer__ and __releasebuffer__ + * # -- the details of this may change. + * def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<< + * # This implementation of getbuffer is geared towards Cython + * # requirements, and does not yet fulfill the PEP. + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("numpy.ndarray.__getbuffer__", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + if (__pyx_v_info->obj != NULL) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + goto __pyx_L2; + __pyx_L0:; + if (__pyx_v_info->obj == Py_None) { + __Pyx_GOTREF(__pyx_v_info->obj); + __Pyx_DECREF(__pyx_v_info->obj); __pyx_v_info->obj = 0; + } + __pyx_L2:; + __Pyx_XDECREF((PyObject *)__pyx_v_descr); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":337 + * f[0] = c'\0' # Terminate format string + * + * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< + * if PyArray_HASFIELDS(self): + * PyObject_Free(info.format) + */ + +/* Python wrapper */ +static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info); /*proto*/ +static CYTHON_UNUSED void __pyx_pw_5numpy_7ndarray_3__releasebuffer__(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__releasebuffer__ (wrapper)", 0); + __pyx_pf_5numpy_7ndarray_2__releasebuffer__(((PyArrayObject *)__pyx_v_self), ((Py_buffer *)__pyx_v_info)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info) { + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("__releasebuffer__", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":338 + * + * def __releasebuffer__(ndarray self, Py_buffer* info): + * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< + * PyObject_Free(info.format) + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + */ + __pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":339 + * def __releasebuffer__(ndarray self, Py_buffer* info): + * if PyArray_HASFIELDS(self): + * PyObject_Free(info.format) # <<<<<<<<<<<<<< + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + * PyObject_Free(info.strides) + */ + PyObject_Free(__pyx_v_info->format); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":338 + * + * def __releasebuffer__(ndarray self, Py_buffer* info): + * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<< + * PyObject_Free(info.format) + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":340 + * if PyArray_HASFIELDS(self): + * PyObject_Free(info.format) + * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< + * PyObject_Free(info.strides) + * # info.shape was stored after info.strides in the same block + */ + __pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":341 + * PyObject_Free(info.format) + * if sizeof(npy_intp) != sizeof(Py_ssize_t): + * PyObject_Free(info.strides) # <<<<<<<<<<<<<< + * # info.shape was stored after info.strides in the same block + * + */ + PyObject_Free(__pyx_v_info->strides); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":340 + * if PyArray_HASFIELDS(self): + * PyObject_Free(info.format) + * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<< + * PyObject_Free(info.strides) + * # info.shape was stored after info.strides in the same block + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":337 + * f[0] = c'\0' # Terminate format string + * + * def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<< + * if PyArray_HASFIELDS(self): + * PyObject_Free(info.format) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":821 + * ctypedef npy_cdouble complex_t + * + * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(1, a) + * + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__pyx_v_a) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":822 + * + * cdef inline object PyArray_MultiIterNew1(a): + * return PyArray_MultiIterNew(1, a) # <<<<<<<<<<<<<< + * + * cdef inline object PyArray_MultiIterNew2(a, b): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 822, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":821 + * ctypedef npy_cdouble complex_t + * + * cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(1, a) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("numpy.PyArray_MultiIterNew1", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":824 + * return PyArray_MultiIterNew(1, a) + * + * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(2, a, b) + * + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__pyx_v_a, PyObject *__pyx_v_b) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":825 + * + * cdef inline object PyArray_MultiIterNew2(a, b): + * return PyArray_MultiIterNew(2, a, b) # <<<<<<<<<<<<<< + * + * cdef inline object PyArray_MultiIterNew3(a, b, c): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 825, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":824 + * return PyArray_MultiIterNew(1, a) + * + * cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(2, a, b) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("numpy.PyArray_MultiIterNew2", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":827 + * return PyArray_MultiIterNew(2, a, b) + * + * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(3, a, b, c) + * + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":828 + * + * cdef inline object PyArray_MultiIterNew3(a, b, c): + * return PyArray_MultiIterNew(3, a, b, c) # <<<<<<<<<<<<<< + * + * cdef inline object PyArray_MultiIterNew4(a, b, c, d): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 828, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":827 + * return PyArray_MultiIterNew(2, a, b) + * + * cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(3, a, b, c) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("numpy.PyArray_MultiIterNew3", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":830 + * return PyArray_MultiIterNew(3, a, b, c) + * + * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(4, a, b, c, d) + * + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":831 + * + * cdef inline object PyArray_MultiIterNew4(a, b, c, d): + * return PyArray_MultiIterNew(4, a, b, c, d) # <<<<<<<<<<<<<< + * + * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 831, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":830 + * return PyArray_MultiIterNew(3, a, b, c) + * + * cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(4, a, b, c, d) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("numpy.PyArray_MultiIterNew4", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":833 + * return PyArray_MultiIterNew(4, a, b, c, d) + * + * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(5, a, b, c, d, e) + * + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__pyx_v_a, PyObject *__pyx_v_b, PyObject *__pyx_v_c, PyObject *__pyx_v_d, PyObject *__pyx_v_e) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":834 + * + * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): + * return PyArray_MultiIterNew(5, a, b, c, d, e) # <<<<<<<<<<<<<< + * + * cdef inline tuple PyDataType_SHAPE(dtype d): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 834, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":833 + * return PyArray_MultiIterNew(4, a, b, c, d) + * + * cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<< + * return PyArray_MultiIterNew(5, a, b, c, d, e) + * + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("numpy.PyArray_MultiIterNew5", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":836 + * return PyArray_MultiIterNew(5, a, b, c, d, e) + * + * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< + * if PyDataType_HASSUBARRAY(d): + * return d.subarray.shape + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyDataType_SHAPE(PyArray_Descr *__pyx_v_d) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("PyDataType_SHAPE", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":837 + * + * cdef inline tuple PyDataType_SHAPE(dtype d): + * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< + * return d.subarray.shape + * else: + */ + __pyx_t_1 = (PyDataType_HASSUBARRAY(__pyx_v_d) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":838 + * cdef inline tuple PyDataType_SHAPE(dtype d): + * if PyDataType_HASSUBARRAY(d): + * return d.subarray.shape # <<<<<<<<<<<<<< + * else: + * return () + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject*)__pyx_v_d->subarray->shape)); + __pyx_r = ((PyObject*)__pyx_v_d->subarray->shape); + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":837 + * + * cdef inline tuple PyDataType_SHAPE(dtype d): + * if PyDataType_HASSUBARRAY(d): # <<<<<<<<<<<<<< + * return d.subarray.shape + * else: + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":840 + * return d.subarray.shape + * else: + * return () # <<<<<<<<<<<<<< + * + * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_empty_tuple); + __pyx_r = __pyx_empty_tuple; + goto __pyx_L0; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":836 + * return PyArray_MultiIterNew(5, a, b, c, d, e) + * + * cdef inline tuple PyDataType_SHAPE(dtype d): # <<<<<<<<<<<<<< + * if PyDataType_HASSUBARRAY(d): + * return d.subarray.shape + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":842 + * return () + * + * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< + * # Recursive utility function used in __getbuffer__ to get format + * # string. The new location in the format string is returned. + */ + +static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx_v_descr, char *__pyx_v_f, char *__pyx_v_end, int *__pyx_v_offset) { + PyArray_Descr *__pyx_v_child = 0; + int __pyx_v_endian_detector; + int __pyx_v_little_endian; + PyObject *__pyx_v_fields = 0; + PyObject *__pyx_v_childname = NULL; + PyObject *__pyx_v_new_offset = NULL; + PyObject *__pyx_v_t = NULL; + char *__pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + Py_ssize_t __pyx_t_2; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_t_7; + long __pyx_t_8; + char *__pyx_t_9; + __Pyx_RefNannySetupContext("_util_dtypestring", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":847 + * + * cdef dtype child + * cdef int endian_detector = 1 # <<<<<<<<<<<<<< + * cdef bint little_endian = ((&endian_detector)[0] != 0) + * cdef tuple fields + */ + __pyx_v_endian_detector = 1; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":848 + * cdef dtype child + * cdef int endian_detector = 1 + * cdef bint little_endian = ((&endian_detector)[0] != 0) # <<<<<<<<<<<<<< + * cdef tuple fields + * + */ + __pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":851 + * cdef tuple fields + * + * for childname in descr.names: # <<<<<<<<<<<<<< + * fields = descr.fields[childname] + * child, new_offset = fields + */ + if (unlikely(__pyx_v_descr->names == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); + __PYX_ERR(1, 851, __pyx_L1_error) + } + __pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; + for (;;) { + if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 851, __pyx_L1_error) + #else + __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 851, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + #endif + __Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3); + __pyx_t_3 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":852 + * + * for childname in descr.names: + * fields = descr.fields[childname] # <<<<<<<<<<<<<< + * child, new_offset = fields + * + */ + if (unlikely(__pyx_v_descr->fields == Py_None)) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); + __PYX_ERR(1, 852, __pyx_L1_error) + } + __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 852, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(1, 852, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3)); + __pyx_t_3 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":853 + * for childname in descr.names: + * fields = descr.fields[childname] + * child, new_offset = fields # <<<<<<<<<<<<<< + * + * if (end - f) - (new_offset - offset[0]) < 15: + */ + if (likely(__pyx_v_fields != Py_None)) { + PyObject* sequence = __pyx_v_fields; + Py_ssize_t size = __Pyx_PySequence_SIZE(sequence); + if (unlikely(size != 2)) { + if (size > 2) __Pyx_RaiseTooManyValuesError(2); + else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size); + __PYX_ERR(1, 853, __pyx_L1_error) + } + #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 1); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + #else + __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 853, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 853, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + #endif + } else { + __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 853, __pyx_L1_error) + } + if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(1, 853, __pyx_L1_error) + __Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3)); + __pyx_t_3 = 0; + __Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4); + __pyx_t_4 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":855 + * child, new_offset = fields + * + * if (end - f) - (new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") + * + */ + __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 855, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 855, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 855, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0); + if (unlikely(__pyx_t_6)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":856 + * + * if (end - f) - (new_offset - offset[0]) < 15: + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< + * + * if ((child.byteorder == c'>' and little_endian) or + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 856, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 856, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":855 + * child, new_offset = fields + * + * if (end - f) - (new_offset - offset[0]) < 15: # <<<<<<<<<<<<<< + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") + * + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":858 + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") + * + * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (child.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + __pyx_t_7 = ((__pyx_v_child->byteorder == '>') != 0); + if (!__pyx_t_7) { + goto __pyx_L8_next_or; + } else { + } + __pyx_t_7 = (__pyx_v_little_endian != 0); + if (!__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L7_bool_binop_done; + } + __pyx_L8_next_or:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":859 + * + * if ((child.byteorder == c'>' and little_endian) or + * (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<< + * raise ValueError(u"Non-native byte order not supported") + * # One could encode it in the format string and have Cython + */ + __pyx_t_7 = ((__pyx_v_child->byteorder == '<') != 0); + if (__pyx_t_7) { + } else { + __pyx_t_6 = __pyx_t_7; + goto __pyx_L7_bool_binop_done; + } + __pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0); + __pyx_t_6 = __pyx_t_7; + __pyx_L7_bool_binop_done:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":858 + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") + * + * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (child.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + if (unlikely(__pyx_t_6)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":860 + * if ((child.byteorder == c'>' and little_endian) or + * (child.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< + * # One could encode it in the format string and have Cython + * # complain instead, BUT: < and > in format strings also imply + */ + __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 860, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __PYX_ERR(1, 860, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":858 + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") + * + * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<< + * (child.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":870 + * + * # Output padding bytes + * while offset[0] < new_offset: # <<<<<<<<<<<<<< + * f[0] = 120 # "x"; pad byte + * f += 1 + */ + while (1) { + __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 870, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 870, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 870, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (!__pyx_t_6) break; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":871 + * # Output padding bytes + * while offset[0] < new_offset: + * f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<< + * f += 1 + * offset[0] += 1 + */ + (__pyx_v_f[0]) = 0x78; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":872 + * while offset[0] < new_offset: + * f[0] = 120 # "x"; pad byte + * f += 1 # <<<<<<<<<<<<<< + * offset[0] += 1 + * + */ + __pyx_v_f = (__pyx_v_f + 1); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":873 + * f[0] = 120 # "x"; pad byte + * f += 1 + * offset[0] += 1 # <<<<<<<<<<<<<< + * + * offset[0] += child.itemsize + */ + __pyx_t_8 = 0; + (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1); + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":875 + * offset[0] += 1 + * + * offset[0] += child.itemsize # <<<<<<<<<<<<<< + * + * if not PyDataType_HASFIELDS(child): + */ + __pyx_t_8 = 0; + (__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":877 + * offset[0] += child.itemsize + * + * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< + * t = child.type_num + * if end - f < 5: + */ + __pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0); + if (__pyx_t_6) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":878 + * + * if not PyDataType_HASFIELDS(child): + * t = child.type_num # <<<<<<<<<<<<<< + * if end - f < 5: + * raise RuntimeError(u"Format string allocated too short.") + */ + __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 878, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4); + __pyx_t_4 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":879 + * if not PyDataType_HASFIELDS(child): + * t = child.type_num + * if end - f < 5: # <<<<<<<<<<<<<< + * raise RuntimeError(u"Format string allocated too short.") + * + */ + __pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0); + if (unlikely(__pyx_t_6)) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":880 + * t = child.type_num + * if end - f < 5: + * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< + * + * # Until ticket #99 is fixed, use integers to avoid warnings + */ + __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 880, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 880, __pyx_L1_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":879 + * if not PyDataType_HASFIELDS(child): + * t = child.type_num + * if end - f < 5: # <<<<<<<<<<<<<< + * raise RuntimeError(u"Format string allocated too short.") + * + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":883 + * + * # Until ticket #99 is fixed, use integers to avoid warnings + * if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<< + * elif t == NPY_UBYTE: f[0] = 66 #"B" + * elif t == NPY_SHORT: f[0] = 104 #"h" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 883, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 883, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 883, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 98; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":884 + * # Until ticket #99 is fixed, use integers to avoid warnings + * if t == NPY_BYTE: f[0] = 98 #"b" + * elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<< + * elif t == NPY_SHORT: f[0] = 104 #"h" + * elif t == NPY_USHORT: f[0] = 72 #"H" + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 884, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 884, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 884, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 66; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":885 + * if t == NPY_BYTE: f[0] = 98 #"b" + * elif t == NPY_UBYTE: f[0] = 66 #"B" + * elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<< + * elif t == NPY_USHORT: f[0] = 72 #"H" + * elif t == NPY_INT: f[0] = 105 #"i" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 885, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 885, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 885, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x68; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":886 + * elif t == NPY_UBYTE: f[0] = 66 #"B" + * elif t == NPY_SHORT: f[0] = 104 #"h" + * elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<< + * elif t == NPY_INT: f[0] = 105 #"i" + * elif t == NPY_UINT: f[0] = 73 #"I" + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 886, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 886, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 886, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 72; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":887 + * elif t == NPY_SHORT: f[0] = 104 #"h" + * elif t == NPY_USHORT: f[0] = 72 #"H" + * elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<< + * elif t == NPY_UINT: f[0] = 73 #"I" + * elif t == NPY_LONG: f[0] = 108 #"l" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 887, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 887, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 887, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x69; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":888 + * elif t == NPY_USHORT: f[0] = 72 #"H" + * elif t == NPY_INT: f[0] = 105 #"i" + * elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<< + * elif t == NPY_LONG: f[0] = 108 #"l" + * elif t == NPY_ULONG: f[0] = 76 #"L" + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 888, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 888, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 888, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 73; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":889 + * elif t == NPY_INT: f[0] = 105 #"i" + * elif t == NPY_UINT: f[0] = 73 #"I" + * elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<< + * elif t == NPY_ULONG: f[0] = 76 #"L" + * elif t == NPY_LONGLONG: f[0] = 113 #"q" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 889, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 889, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 889, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x6C; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":890 + * elif t == NPY_UINT: f[0] = 73 #"I" + * elif t == NPY_LONG: f[0] = 108 #"l" + * elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<< + * elif t == NPY_LONGLONG: f[0] = 113 #"q" + * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 890, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 890, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 890, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 76; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":891 + * elif t == NPY_LONG: f[0] = 108 #"l" + * elif t == NPY_ULONG: f[0] = 76 #"L" + * elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<< + * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" + * elif t == NPY_FLOAT: f[0] = 102 #"f" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 891, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 891, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 891, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x71; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":892 + * elif t == NPY_ULONG: f[0] = 76 #"L" + * elif t == NPY_LONGLONG: f[0] = 113 #"q" + * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<< + * elif t == NPY_FLOAT: f[0] = 102 #"f" + * elif t == NPY_DOUBLE: f[0] = 100 #"d" + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 892, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 892, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 892, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 81; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":893 + * elif t == NPY_LONGLONG: f[0] = 113 #"q" + * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" + * elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<< + * elif t == NPY_DOUBLE: f[0] = 100 #"d" + * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 893, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 893, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 893, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x66; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":894 + * elif t == NPY_ULONGLONG: f[0] = 81 #"Q" + * elif t == NPY_FLOAT: f[0] = 102 #"f" + * elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<< + * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" + * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 894, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 894, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 894, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x64; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":895 + * elif t == NPY_FLOAT: f[0] = 102 #"f" + * elif t == NPY_DOUBLE: f[0] = 100 #"d" + * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<< + * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf + * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 895, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 895, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 895, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 0x67; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":896 + * elif t == NPY_DOUBLE: f[0] = 100 #"d" + * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" + * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<< + * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd + * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 896, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 896, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 896, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 90; + (__pyx_v_f[1]) = 0x66; + __pyx_v_f = (__pyx_v_f + 1); + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":897 + * elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" + * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf + * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<< + * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg + * elif t == NPY_OBJECT: f[0] = 79 #"O" + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 897, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 897, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 897, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 90; + (__pyx_v_f[1]) = 0x64; + __pyx_v_f = (__pyx_v_f + 1); + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":898 + * elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf + * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd + * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<< + * elif t == NPY_OBJECT: f[0] = 79 #"O" + * else: + */ + __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 898, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 898, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 898, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + if (__pyx_t_6) { + (__pyx_v_f[0]) = 90; + (__pyx_v_f[1]) = 0x67; + __pyx_v_f = (__pyx_v_f + 1); + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":899 + * elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd + * elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg + * elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<< + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) + */ + __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 899, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 899, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 899, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + if (likely(__pyx_t_6)) { + (__pyx_v_f[0]) = 79; + goto __pyx_L15; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":901 + * elif t == NPY_OBJECT: f[0] = 79 #"O" + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<< + * f += 1 + * else: + */ + /*else*/ { + __pyx_t_3 = __Pyx_PyUnicode_FormatSafe(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 901, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 901, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __PYX_ERR(1, 901, __pyx_L1_error) + } + __pyx_L15:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":902 + * else: + * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) + * f += 1 # <<<<<<<<<<<<<< + * else: + * # Cython ignores struct boundary information ("T{...}"), + */ + __pyx_v_f = (__pyx_v_f + 1); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":877 + * offset[0] += child.itemsize + * + * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<< + * t = child.type_num + * if end - f < 5: + */ + goto __pyx_L13; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":906 + * # Cython ignores struct boundary information ("T{...}"), + * # so don't output it + * f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<< + * return f + * + */ + /*else*/ { + __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == ((char *)NULL))) __PYX_ERR(1, 906, __pyx_L1_error) + __pyx_v_f = __pyx_t_9; + } + __pyx_L13:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":851 + * cdef tuple fields + * + * for childname in descr.names: # <<<<<<<<<<<<<< + * fields = descr.fields[childname] + * child, new_offset = fields + */ + } + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":907 + * # so don't output it + * f = _util_dtypestring(child, f, end, offset) + * return f # <<<<<<<<<<<<<< + * + * + */ + __pyx_r = __pyx_v_f; + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":842 + * return () + * + * cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<< + * # Recursive utility function used in __getbuffer__ to get format + * # string. The new location in the format string is returned. + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("numpy._util_dtypestring", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF((PyObject *)__pyx_v_child); + __Pyx_XDECREF(__pyx_v_fields); + __Pyx_XDECREF(__pyx_v_childname); + __Pyx_XDECREF(__pyx_v_new_offset); + __Pyx_XDECREF(__pyx_v_t); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1022 + * int _import_umath() except -1 + * + * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< + * Py_INCREF(base) # important to do this before stealing the reference below! + * PyArray_SetBaseObject(arr, base) + */ + +static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_arr, PyObject *__pyx_v_base) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("set_array_base", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1023 + * + * cdef inline void set_array_base(ndarray arr, object base): + * Py_INCREF(base) # important to do this before stealing the reference below! # <<<<<<<<<<<<<< + * PyArray_SetBaseObject(arr, base) + * + */ + Py_INCREF(__pyx_v_base); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1024 + * cdef inline void set_array_base(ndarray arr, object base): + * Py_INCREF(base) # important to do this before stealing the reference below! + * PyArray_SetBaseObject(arr, base) # <<<<<<<<<<<<<< + * + * cdef inline object get_array_base(ndarray arr): + */ + (void)(PyArray_SetBaseObject(__pyx_v_arr, __pyx_v_base)); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1022 + * int _import_umath() except -1 + * + * cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<< + * Py_INCREF(base) # important to do this before stealing the reference below! + * PyArray_SetBaseObject(arr, base) + */ + + /* function exit code */ + __Pyx_RefNannyFinishContext(); +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1026 + * PyArray_SetBaseObject(arr, base) + * + * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< + * base = PyArray_BASE(arr) + * if base is NULL: + */ + +static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__pyx_v_arr) { + PyObject *__pyx_v_base; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + __Pyx_RefNannySetupContext("get_array_base", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1027 + * + * cdef inline object get_array_base(ndarray arr): + * base = PyArray_BASE(arr) # <<<<<<<<<<<<<< + * if base is NULL: + * return None + */ + __pyx_v_base = PyArray_BASE(__pyx_v_arr); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1028 + * cdef inline object get_array_base(ndarray arr): + * base = PyArray_BASE(arr) + * if base is NULL: # <<<<<<<<<<<<<< + * return None + * return base + */ + __pyx_t_1 = ((__pyx_v_base == NULL) != 0); + if (__pyx_t_1) { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1029 + * base = PyArray_BASE(arr) + * if base is NULL: + * return None # <<<<<<<<<<<<<< + * return base + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1028 + * cdef inline object get_array_base(ndarray arr): + * base = PyArray_BASE(arr) + * if base is NULL: # <<<<<<<<<<<<<< + * return None + * return base + */ + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1030 + * if base is NULL: + * return None + * return base # <<<<<<<<<<<<<< + * + * # Versions of the import_* functions which are more suitable for + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)__pyx_v_base)); + __pyx_r = ((PyObject *)__pyx_v_base); + goto __pyx_L0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1026 + * PyArray_SetBaseObject(arr, base) + * + * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<< + * base = PyArray_BASE(arr) + * if base is NULL: + */ + + /* function exit code */ + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1034 + * # Versions of the import_* functions which are more suitable for + * # Cython code. + * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< + * try: + * _import_array() + */ + +static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("import_array", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1035 + * # Cython code. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1036 + * cdef inline int import_array() except -1: + * try: + * _import_array() # <<<<<<<<<<<<<< + * except Exception: + * raise ImportError("numpy.core.multiarray failed to import") + */ + __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1036, __pyx_L3_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1035 + * # Cython code. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1037 + * try: + * _import_array() + * except Exception: # <<<<<<<<<<<<<< + * raise ImportError("numpy.core.multiarray failed to import") + * + */ + __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); + if (__pyx_t_4) { + __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1037, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_7); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1038 + * _import_array() + * except Exception: + * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< + * + * cdef inline int import_umath() except -1: + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1038, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(1, 1038, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + __pyx_L5_except_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1035 + * # Cython code. + * cdef inline int import_array() except -1: + * try: # <<<<<<<<<<<<<< + * _import_array() + * except Exception: + */ + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L8_try_end:; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1034 + * # Versions of the import_* functions which are more suitable for + * # Cython code. + * cdef inline int import_array() except -1: # <<<<<<<<<<<<<< + * try: + * _import_array() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1040 + * raise ImportError("numpy.core.multiarray failed to import") + * + * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< + * try: + * _import_umath() + */ + +static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("import_umath", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1041 + * + * cdef inline int import_umath() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1042 + * cdef inline int import_umath() except -1: + * try: + * _import_umath() # <<<<<<<<<<<<<< + * except Exception: + * raise ImportError("numpy.core.umath failed to import") + */ + __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1042, __pyx_L3_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1041 + * + * cdef inline int import_umath() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1043 + * try: + * _import_umath() + * except Exception: # <<<<<<<<<<<<<< + * raise ImportError("numpy.core.umath failed to import") + * + */ + __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); + if (__pyx_t_4) { + __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1043, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_7); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1044 + * _import_umath() + * except Exception: + * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< + * + * cdef inline int import_ufunc() except -1: + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1044, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(1, 1044, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + __pyx_L5_except_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1041 + * + * cdef inline int import_umath() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L8_try_end:; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1040 + * raise ImportError("numpy.core.multiarray failed to import") + * + * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<< + * try: + * _import_umath() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1046 + * raise ImportError("numpy.core.umath failed to import") + * + * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< + * try: + * _import_umath() + */ + +static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) { + int __pyx_r; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + int __pyx_t_4; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + __Pyx_RefNannySetupContext("import_ufunc", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1047 + * + * cdef inline int import_ufunc() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + { + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); + __Pyx_XGOTREF(__pyx_t_1); + __Pyx_XGOTREF(__pyx_t_2); + __Pyx_XGOTREF(__pyx_t_3); + /*try:*/ { + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1048 + * cdef inline int import_ufunc() except -1: + * try: + * _import_umath() # <<<<<<<<<<<<<< + * except Exception: + * raise ImportError("numpy.core.umath failed to import") + */ + __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 1048, __pyx_L3_error) + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1047 + * + * cdef inline int import_ufunc() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + } + __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + goto __pyx_L8_try_end; + __pyx_L3_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1049 + * try: + * _import_umath() + * except Exception: # <<<<<<<<<<<<<< + * raise ImportError("numpy.core.umath failed to import") + */ + __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0]))); + if (__pyx_t_4) { + __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); + if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1049, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_5); + __Pyx_GOTREF(__pyx_t_6); + __Pyx_GOTREF(__pyx_t_7); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1050 + * _import_umath() + * except Exception: + * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< + */ + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1050, __pyx_L5_except_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_Raise(__pyx_t_8, 0, 0, 0); + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __PYX_ERR(1, 1050, __pyx_L5_except_error) + } + goto __pyx_L5_except_error; + __pyx_L5_except_error:; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1047 + * + * cdef inline int import_ufunc() except -1: + * try: # <<<<<<<<<<<<<< + * _import_umath() + * except Exception: + */ + __Pyx_XGIVEREF(__pyx_t_1); + __Pyx_XGIVEREF(__pyx_t_2); + __Pyx_XGIVEREF(__pyx_t_3); + __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); + goto __pyx_L1_error; + __pyx_L8_try_end:; + } + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1046 + * raise ImportError("numpy.core.umath failed to import") + * + * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< + * try: + * _import_umath() + */ + + /* function exit code */ + __pyx_r = 0; + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = -1; + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyMethodDef __pyx_methods[] = { + {0, 0, 0, 0} +}; + +#if PY_MAJOR_VERSION >= 3 +#if CYTHON_PEP489_MULTI_PHASE_INIT +static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ +static int __pyx_pymod_exec_mesh_core_cython(PyObject* module); /*proto*/ +static PyModuleDef_Slot __pyx_moduledef_slots[] = { + {Py_mod_create, (void*)__pyx_pymod_create}, + {Py_mod_exec, (void*)__pyx_pymod_exec_mesh_core_cython}, + {0, NULL} +}; +#endif + +static struct PyModuleDef __pyx_moduledef = { + PyModuleDef_HEAD_INIT, + "mesh_core_cython", + 0, /* m_doc */ + #if CYTHON_PEP489_MULTI_PHASE_INIT + 0, /* m_size */ + #else + -1, /* m_size */ + #endif + __pyx_methods /* m_methods */, + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_moduledef_slots, /* m_slots */ + #else + NULL, /* m_reload */ + #endif + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif +#ifndef CYTHON_SMALL_CODE +#if defined(__clang__) + #define CYTHON_SMALL_CODE +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define CYTHON_SMALL_CODE __attribute__((cold)) +#else + #define CYTHON_SMALL_CODE +#endif +#endif + +static __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0}, + {&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0}, + {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1}, + {&__pyx_kp_u_Non_native_byte_order_not_suppor, __pyx_k_Non_native_byte_order_not_suppor, sizeof(__pyx_k_Non_native_byte_order_not_suppor), 0, 1, 0, 0}, + {&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1}, + {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, + {&__pyx_n_s_c, __pyx_k_c, sizeof(__pyx_k_c), 0, 0, 1, 1}, + {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, + {&__pyx_n_s_colors, __pyx_k_colors, sizeof(__pyx_k_colors), 0, 0, 1, 1}, + {&__pyx_n_s_depth_buffer, __pyx_k_depth_buffer, sizeof(__pyx_k_depth_buffer), 0, 0, 1, 1}, + {&__pyx_n_s_get_normal, __pyx_k_get_normal, sizeof(__pyx_k_get_normal), 0, 0, 1, 1}, + {&__pyx_n_s_get_normal_core, __pyx_k_get_normal_core, sizeof(__pyx_k_get_normal_core), 0, 0, 1, 1}, + {&__pyx_n_s_h, __pyx_k_h, sizeof(__pyx_k_h), 0, 0, 1, 1}, + {&__pyx_n_s_image, __pyx_k_image, sizeof(__pyx_k_image), 0, 0, 1, 1}, + {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_mesh_core_cython, __pyx_k_mesh_core_cython, sizeof(__pyx_k_mesh_core_cython), 0, 0, 1, 1}, + {&__pyx_kp_s_mesh_core_cython_pyx, __pyx_k_mesh_core_cython_pyx, sizeof(__pyx_k_mesh_core_cython_pyx), 0, 0, 1, 0}, + {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, + {&__pyx_kp_u_ndarray_is_not_C_contiguous, __pyx_k_ndarray_is_not_C_contiguous, sizeof(__pyx_k_ndarray_is_not_C_contiguous), 0, 1, 0, 0}, + {&__pyx_kp_u_ndarray_is_not_Fortran_contiguou, __pyx_k_ndarray_is_not_Fortran_contiguou, sizeof(__pyx_k_ndarray_is_not_Fortran_contiguou), 0, 1, 0, 0}, + {&__pyx_n_s_normal, __pyx_k_normal, sizeof(__pyx_k_normal), 0, 0, 1, 1}, + {&__pyx_n_s_np, __pyx_k_np, sizeof(__pyx_k_np), 0, 0, 1, 1}, + {&__pyx_n_s_ntri, __pyx_k_ntri, sizeof(__pyx_k_ntri), 0, 0, 1, 1}, + {&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1}, + {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0}, + {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0}, + {&__pyx_n_s_nver, __pyx_k_nver, sizeof(__pyx_k_nver), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_render_colors_core, __pyx_k_render_colors_core, sizeof(__pyx_k_render_colors_core), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_tri_normal, __pyx_k_tri_normal, sizeof(__pyx_k_tri_normal), 0, 0, 1, 1}, + {&__pyx_n_s_triangles, __pyx_k_triangles, sizeof(__pyx_k_triangles), 0, 0, 1, 1}, + {&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0}, + {&__pyx_n_s_ver_normal, __pyx_k_ver_normal, sizeof(__pyx_k_ver_normal), 0, 0, 1, 1}, + {&__pyx_n_s_vertices, __pyx_k_vertices, sizeof(__pyx_k_vertices), 0, 0, 1, 1}, + {&__pyx_n_s_w, __pyx_k_w, sizeof(__pyx_k_w), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} +}; +static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(1, 272, __pyx_L1_error) + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(1, 285, __pyx_L1_error) + __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(1, 856, __pyx_L1_error) + __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 1038, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":272 + * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS)): + * raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<< + * + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) + */ + __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple_)) __PYX_ERR(1, 272, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":276 + * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) + * and not PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS)): + * raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<< + * + * info.buf = PyArray_DATA(self) + */ + __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(1, 276, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__2); + __Pyx_GIVEREF(__pyx_tuple__2); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":306 + * if ((descr.byteorder == c'>' and little_endian) or + * (descr.byteorder == c'<' and not little_endian)): + * raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<< + * if t == NPY_BYTE: f = "b" + * elif t == NPY_UBYTE: f = "B" + */ + __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(1, 306, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":856 + * + * if (end - f) - (new_offset - offset[0]) < 15: + * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<< + * + * if ((child.byteorder == c'>' and little_endian) or + */ + __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(1, 856, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__4); + __Pyx_GIVEREF(__pyx_tuple__4); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":880 + * t = child.type_num + * if end - f < 5: + * raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<< + * + * # Until ticket #99 is fixed, use integers to avoid warnings + */ + __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(1, 880, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__5); + __Pyx_GIVEREF(__pyx_tuple__5); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1038 + * _import_array() + * except Exception: + * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<< + * + * cdef inline int import_umath() except -1: + */ + __pyx_tuple__6 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(1, 1038, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__6); + __Pyx_GIVEREF(__pyx_tuple__6); + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1044 + * _import_umath() + * except Exception: + * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<< + * + * cdef inline int import_ufunc() except -1: + */ + __pyx_tuple__7 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__7)) __PYX_ERR(1, 1044, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__7); + __Pyx_GIVEREF(__pyx_tuple__7); + + /* "mesh_core_cython.pyx":29 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_tuple__8 = PyTuple_Pack(4, __pyx_n_s_normal, __pyx_n_s_tri_normal, __pyx_n_s_triangles, __pyx_n_s_ntri); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__8); + __Pyx_GIVEREF(__pyx_tuple__8); + __pyx_codeobj__9 = (PyObject*)__Pyx_PyCode_New(4, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__8, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_mesh_core_cython_pyx, __pyx_n_s_get_normal_core, 29, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__9)) __PYX_ERR(0, 29, __pyx_L1_error) + + /* "mesh_core_cython.pyx":41 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_tuple__10 = PyTuple_Pack(10, __pyx_n_s_image, __pyx_n_s_vertices, __pyx_n_s_triangles, __pyx_n_s_colors, __pyx_n_s_depth_buffer, __pyx_n_s_nver, __pyx_n_s_ntri, __pyx_n_s_h, __pyx_n_s_w, __pyx_n_s_c); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__10); + __Pyx_GIVEREF(__pyx_tuple__10); + __pyx_codeobj__11 = (PyObject*)__Pyx_PyCode_New(10, 0, 10, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__10, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_mesh_core_cython_pyx, __pyx_n_s_render_colors_core, 41, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__11)) __PYX_ERR(0, 41, __pyx_L1_error) + + /* "mesh_core_cython.pyx":59 + * @cython.boundscheck(False) # turn off bounds-checking for entire function + * @cython.wraparound(False) # turn off negative index wrapping for entire function + * def get_normal(np.ndarray[float, ndim=2, mode = "c"] ver_normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_tuple__12 = PyTuple_Pack(5, __pyx_n_s_ver_normal, __pyx_n_s_vertices, __pyx_n_s_triangles, __pyx_n_s_nver, __pyx_n_s_ntri); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__12); + __Pyx_GIVEREF(__pyx_tuple__12); + __pyx_codeobj__13 = (PyObject*)__Pyx_PyCode_New(5, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__12, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_mesh_core_cython_pyx, __pyx_n_s_get_normal, 59, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__13)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { + if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + return 0; + __pyx_L1_error:; + return -1; +} + +static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ +static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ + +static int __Pyx_modinit_global_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); + /*--- Global init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_variable_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); + /*--- Variable export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_export_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); + /*--- Function export code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_init_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); + /*--- Type init code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_type_import_code(void) { + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); + /*--- Type import code ---*/ + __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_7cpython_4type_type = __Pyx_ImportType(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "type", + #if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000 + sizeof(PyTypeObject), + #else + sizeof(PyHeapTypeObject), + #endif + __Pyx_ImportType_CheckSize_Warn); + if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(2, 9, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyImport_ImportModule("numpy"); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 206, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_ptype_5numpy_dtype = __Pyx_ImportType(__pyx_t_1, "numpy", "dtype", sizeof(PyArray_Descr), __Pyx_ImportType_CheckSize_Ignore); + if (!__pyx_ptype_5numpy_dtype) __PYX_ERR(1, 206, __pyx_L1_error) + __pyx_ptype_5numpy_flatiter = __Pyx_ImportType(__pyx_t_1, "numpy", "flatiter", sizeof(PyArrayIterObject), __Pyx_ImportType_CheckSize_Warn); + if (!__pyx_ptype_5numpy_flatiter) __PYX_ERR(1, 229, __pyx_L1_error) + __pyx_ptype_5numpy_broadcast = __Pyx_ImportType(__pyx_t_1, "numpy", "broadcast", sizeof(PyArrayMultiIterObject), __Pyx_ImportType_CheckSize_Warn); + if (!__pyx_ptype_5numpy_broadcast) __PYX_ERR(1, 233, __pyx_L1_error) + __pyx_ptype_5numpy_ndarray = __Pyx_ImportType(__pyx_t_1, "numpy", "ndarray", sizeof(PyArrayObject), __Pyx_ImportType_CheckSize_Ignore); + if (!__pyx_ptype_5numpy_ndarray) __PYX_ERR(1, 242, __pyx_L1_error) + __pyx_ptype_5numpy_ufunc = __Pyx_ImportType(__pyx_t_1, "numpy", "ufunc", sizeof(PyUFuncObject), __Pyx_ImportType_CheckSize_Warn); + if (!__pyx_ptype_5numpy_ufunc) __PYX_ERR(1, 918, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_modinit_variable_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); + /*--- Variable import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + +static int __Pyx_modinit_function_import_code(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); + /*--- Function import code ---*/ + __Pyx_RefNannyFinishContext(); + return 0; +} + + +#if PY_MAJOR_VERSION < 3 +#ifdef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC void +#else +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#endif +#else +#ifdef CYTHON_NO_PYINIT_EXPORT +#define __Pyx_PyMODINIT_FUNC PyObject * +#else +#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC +#endif +#endif + + +#if PY_MAJOR_VERSION < 3 +__Pyx_PyMODINIT_FUNC initmesh_core_cython(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC initmesh_core_cython(void) +#else +__Pyx_PyMODINIT_FUNC PyInit_mesh_core_cython(void) CYTHON_SMALL_CODE; /*proto*/ +__Pyx_PyMODINIT_FUNC PyInit_mesh_core_cython(void) +#if CYTHON_PEP489_MULTI_PHASE_INIT +{ + return PyModuleDef_Init(&__pyx_moduledef); +} +static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { + #if PY_VERSION_HEX >= 0x030700A1 + static PY_INT64_T main_interpreter_id = -1; + PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); + if (main_interpreter_id == -1) { + main_interpreter_id = current_id; + return (unlikely(current_id == -1)) ? -1 : 0; + } else if (unlikely(main_interpreter_id != current_id)) + #else + static PyInterpreterState *main_interpreter = NULL; + PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; + if (!main_interpreter) { + main_interpreter = current_interpreter; + } else if (unlikely(main_interpreter != current_interpreter)) + #endif + { + PyErr_SetString( + PyExc_ImportError, + "Interpreter change detected - this module can only be loaded into one interpreter per process."); + return -1; + } + return 0; +} +static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) { + PyObject *value = PyObject_GetAttrString(spec, from_name); + int result = 0; + if (likely(value)) { + if (allow_none || value != Py_None) { + result = PyDict_SetItemString(moddict, to_name, value); + } + Py_DECREF(value); + } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } else { + result = -1; + } + return result; +} +static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, CYTHON_UNUSED PyModuleDef *def) { + PyObject *module = NULL, *moddict, *modname; + if (__Pyx_check_single_interpreter()) + return NULL; + if (__pyx_m) + return __Pyx_NewRef(__pyx_m); + modname = PyObject_GetAttrString(spec, "name"); + if (unlikely(!modname)) goto bad; + module = PyModule_NewObject(modname); + Py_DECREF(modname); + if (unlikely(!module)) goto bad; + moddict = PyModule_GetDict(module); + if (unlikely(!moddict)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; + if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; + return module; +bad: + Py_XDECREF(module); + return NULL; +} + + +static CYTHON_SMALL_CODE int __pyx_pymod_exec_mesh_core_cython(PyObject *__pyx_pyinit_module) +#endif +#endif +{ + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + __Pyx_RefNannyDeclarations + #if CYTHON_PEP489_MULTI_PHASE_INIT + if (__pyx_m) { + if (__pyx_m == __pyx_pyinit_module) return 0; + PyErr_SetString(PyExc_RuntimeError, "Module 'mesh_core_cython' has already been imported. Re-initialisation is not supported."); + return -1; + } + #elif PY_MAJOR_VERSION >= 3 + if (__pyx_m) return __Pyx_NewRef(__pyx_m); + #endif + #if CYTHON_REFNANNY +__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); +if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); +} +#endif + __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit_mesh_core_cython(void)", 0); + if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pxy_PyFrame_Initialize_Offsets + __Pxy_PyFrame_Initialize_Offsets(); + #endif + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_AsyncGen_USED + if (__pyx_AsyncGen_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + #ifdef WITH_THREAD /* Python build with threading support? */ + PyEval_InitThreads(); + #endif + #endif + /*--- Module creation code ---*/ + #if CYTHON_PEP489_MULTI_PHASE_INIT + __pyx_m = __pyx_pyinit_module; + Py_INCREF(__pyx_m); + #else + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("mesh_core_cython", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + #endif + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_COMPILING_IN_PYPY + Py_INCREF(__pyx_b); + #endif + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_mesh_core_cython) { + if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "mesh_core_cython")) { + if (unlikely(PyDict_SetItemString(modules, "mesh_core_cython", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global type/function init code ---*/ + (void)__Pyx_modinit_global_init_code(); + (void)__Pyx_modinit_variable_export_code(); + (void)__Pyx_modinit_function_export_code(); + (void)__Pyx_modinit_type_init_code(); + if (unlikely(__Pyx_modinit_type_import_code() != 0)) goto __pyx_L1_error; + (void)__Pyx_modinit_variable_import_code(); + (void)__Pyx_modinit_function_import_code(); + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "mesh_core_cython.pyx":1 + * import numpy as np # <<<<<<<<<<<<<< + * cimport numpy as np + * from libcpp.string cimport string + */ + __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mesh_core_cython.pyx":7 + * + * # use the Numpy-C-API from Cython + * np.import_array() # <<<<<<<<<<<<<< + * + * # cdefine the signature of our c function + */ + __pyx_t_2 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 7, __pyx_L1_error) + + /* "mesh_core_cython.pyx":29 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_16mesh_core_cython_1get_normal_core, NULL, __pyx_n_s_mesh_core_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_normal_core, __pyx_t_1) < 0) __PYX_ERR(0, 29, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mesh_core_cython.pyx":41 + * @cython.boundscheck(False) + * @cython.wraparound(False) + * def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_16mesh_core_cython_3render_colors_core, NULL, __pyx_n_s_mesh_core_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 41, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_render_colors_core, __pyx_t_1) < 0) __PYX_ERR(0, 41, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mesh_core_cython.pyx":59 + * @cython.boundscheck(False) # turn off bounds-checking for entire function + * @cython.wraparound(False) # turn off negative index wrapping for entire function + * def get_normal(np.ndarray[float, ndim=2, mode = "c"] ver_normal not None, # <<<<<<<<<<<<<< + * np.ndarray[float, ndim=2, mode = "c"] vertices not None, + * np.ndarray[int, ndim=2, mode="c"] triangles not None, + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_16mesh_core_cython_5get_normal, NULL, __pyx_n_s_mesh_core_cython); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_normal, __pyx_t_1) < 0) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "mesh_core_cython.pyx":1 + * import numpy as np # <<<<<<<<<<<<<< + * cimport numpy as np + * from libcpp.string cimport string + */ + __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "../../../../../../lustre/liujihao/.local/lib/python3.6/site-packages/Cython/Includes/numpy/__init__.pxd":1046 + * raise ImportError("numpy.core.umath failed to import") + * + * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<< + * try: + * _import_umath() + */ + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + if (__pyx_m) { + if (__pyx_d) { + __Pyx_AddTraceback("init mesh_core_cython", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + Py_CLEAR(__pyx_m); + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init mesh_core_cython"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if CYTHON_PEP489_MULTI_PHASE_INIT + return (__pyx_m != NULL) ? 0 : -1; + #elif PY_MAJOR_VERSION >= 3 + return __pyx_m; + #else + return; + #endif +} + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule(modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, "RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* RaiseDoubleKeywords */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + continue; + } + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = (**name == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +/* ArgTypeTest */ +static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) +{ + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + else if (exact) { + #if PY_MAJOR_VERSION == 2 + if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; + #endif + } + else { + if (likely(__Pyx_TypeCheck(obj, type))) return 1; + } + PyErr_Format(PyExc_TypeError, + "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)", + name, type->tp_name, Py_TYPE(obj)->tp_name); + return 0; +} + +/* IsLittleEndian */ +static CYTHON_INLINE int __Pyx_Is_Little_Endian(void) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } S; + S.u32 = 0x01020304; + return S.u8[0] == 4; +} + +/* BufferFormatCheck */ +static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx, + __Pyx_BufFmt_StackElem* stack, + __Pyx_TypeInfo* type) { + stack[0].field = &ctx->root; + stack[0].parent_offset = 0; + ctx->root.type = type; + ctx->root.name = "buffer dtype"; + ctx->root.offset = 0; + ctx->head = stack; + ctx->head->field = &ctx->root; + ctx->fmt_offset = 0; + ctx->head->parent_offset = 0; + ctx->new_packmode = '@'; + ctx->enc_packmode = '@'; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->is_complex = 0; + ctx->is_valid_array = 0; + ctx->struct_alignment = 0; + while (type->typegroup == 'S') { + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = 0; + type = type->fields->type; + } +} +static int __Pyx_BufFmt_ParseNumber(const char** ts) { + int count; + const char* t = *ts; + if (*t < '0' || *t > '9') { + return -1; + } else { + count = *t++ - '0'; + while (*t >= '0' && *t <= '9') { + count *= 10; + count += *t++ - '0'; + } + } + *ts = t; + return count; +} +static int __Pyx_BufFmt_ExpectNumber(const char **ts) { + int number = __Pyx_BufFmt_ParseNumber(ts); + if (number == -1) + PyErr_Format(PyExc_ValueError,\ + "Does not understand character buffer dtype format string ('%c')", **ts); + return number; +} +static void __Pyx_BufFmt_RaiseUnexpectedChar(char ch) { + PyErr_Format(PyExc_ValueError, + "Unexpected format string character: '%c'", ch); +} +static const char* __Pyx_BufFmt_DescribeTypeChar(char ch, int is_complex) { + switch (ch) { + case 'c': return "'char'"; + case 'b': return "'signed char'"; + case 'B': return "'unsigned char'"; + case 'h': return "'short'"; + case 'H': return "'unsigned short'"; + case 'i': return "'int'"; + case 'I': return "'unsigned int'"; + case 'l': return "'long'"; + case 'L': return "'unsigned long'"; + case 'q': return "'long long'"; + case 'Q': return "'unsigned long long'"; + case 'f': return (is_complex ? "'complex float'" : "'float'"); + case 'd': return (is_complex ? "'complex double'" : "'double'"); + case 'g': return (is_complex ? "'complex long double'" : "'long double'"); + case 'T': return "a struct"; + case 'O': return "Python object"; + case 'P': return "a pointer"; + case 's': case 'p': return "a string"; + case 0: return "end"; + default: return "unparseable format string"; + } +} +static size_t __Pyx_BufFmt_TypeCharToStandardSize(char ch, int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return 2; + case 'i': case 'I': case 'l': case 'L': return 4; + case 'q': case 'Q': return 8; + case 'f': return (is_complex ? 8 : 4); + case 'd': return (is_complex ? 16 : 8); + case 'g': { + PyErr_SetString(PyExc_ValueError, "Python does not define a standard format string size for long double ('g').."); + return 0; + } + case 'O': case 'P': return sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static size_t __Pyx_BufFmt_TypeCharToNativeSize(char ch, int is_complex) { + switch (ch) { + case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(short); + case 'i': case 'I': return sizeof(int); + case 'l': case 'L': return sizeof(long); + #ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(PY_LONG_LONG); + #endif + case 'f': return sizeof(float) * (is_complex ? 2 : 1); + case 'd': return sizeof(double) * (is_complex ? 2 : 1); + case 'g': return sizeof(long double) * (is_complex ? 2 : 1); + case 'O': case 'P': return sizeof(void*); + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +typedef struct { char c; short x; } __Pyx_st_short; +typedef struct { char c; int x; } __Pyx_st_int; +typedef struct { char c; long x; } __Pyx_st_long; +typedef struct { char c; float x; } __Pyx_st_float; +typedef struct { char c; double x; } __Pyx_st_double; +typedef struct { char c; long double x; } __Pyx_st_longdouble; +typedef struct { char c; void *x; } __Pyx_st_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { char c; PY_LONG_LONG x; } __Pyx_st_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToAlignment(char ch, CYTHON_UNUSED int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_st_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_st_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_st_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_st_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_st_float) - sizeof(float); + case 'd': return sizeof(__Pyx_st_double) - sizeof(double); + case 'g': return sizeof(__Pyx_st_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_st_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +/* These are for computing the padding at the end of the struct to align + on the first member of the struct. This will probably the same as above, + but we don't have any guarantees. + */ +typedef struct { short x; char c; } __Pyx_pad_short; +typedef struct { int x; char c; } __Pyx_pad_int; +typedef struct { long x; char c; } __Pyx_pad_long; +typedef struct { float x; char c; } __Pyx_pad_float; +typedef struct { double x; char c; } __Pyx_pad_double; +typedef struct { long double x; char c; } __Pyx_pad_longdouble; +typedef struct { void *x; char c; } __Pyx_pad_void_p; +#ifdef HAVE_LONG_LONG +typedef struct { PY_LONG_LONG x; char c; } __Pyx_pad_longlong; +#endif +static size_t __Pyx_BufFmt_TypeCharToPadding(char ch, CYTHON_UNUSED int is_complex) { + switch (ch) { + case '?': case 'c': case 'b': case 'B': case 's': case 'p': return 1; + case 'h': case 'H': return sizeof(__Pyx_pad_short) - sizeof(short); + case 'i': case 'I': return sizeof(__Pyx_pad_int) - sizeof(int); + case 'l': case 'L': return sizeof(__Pyx_pad_long) - sizeof(long); +#ifdef HAVE_LONG_LONG + case 'q': case 'Q': return sizeof(__Pyx_pad_longlong) - sizeof(PY_LONG_LONG); +#endif + case 'f': return sizeof(__Pyx_pad_float) - sizeof(float); + case 'd': return sizeof(__Pyx_pad_double) - sizeof(double); + case 'g': return sizeof(__Pyx_pad_longdouble) - sizeof(long double); + case 'P': case 'O': return sizeof(__Pyx_pad_void_p) - sizeof(void*); + default: + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } +} +static char __Pyx_BufFmt_TypeCharToGroup(char ch, int is_complex) { + switch (ch) { + case 'c': + return 'H'; + case 'b': case 'h': case 'i': + case 'l': case 'q': case 's': case 'p': + return 'I'; + case 'B': case 'H': case 'I': case 'L': case 'Q': + return 'U'; + case 'f': case 'd': case 'g': + return (is_complex ? 'C' : 'R'); + case 'O': + return 'O'; + case 'P': + return 'P'; + default: { + __Pyx_BufFmt_RaiseUnexpectedChar(ch); + return 0; + } + } +} +static void __Pyx_BufFmt_RaiseExpected(__Pyx_BufFmt_Context* ctx) { + if (ctx->head == NULL || ctx->head->field == &ctx->root) { + const char* expected; + const char* quote; + if (ctx->head == NULL) { + expected = "end"; + quote = ""; + } else { + expected = ctx->head->field->type->name; + quote = "'"; + } + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected %s%s%s but got %s", + quote, expected, quote, + __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex)); + } else { + __Pyx_StructField* field = ctx->head->field; + __Pyx_StructField* parent = (ctx->head - 1)->field; + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch, expected '%s' but got %s in '%s.%s'", + field->type->name, __Pyx_BufFmt_DescribeTypeChar(ctx->enc_type, ctx->is_complex), + parent->type->name, field->name); + } +} +static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) { + char group; + size_t size, offset, arraysize = 1; + if (ctx->enc_type == 0) return 0; + if (ctx->head->field->type->arraysize[0]) { + int i, ndim = 0; + if (ctx->enc_type == 's' || ctx->enc_type == 'p') { + ctx->is_valid_array = ctx->head->field->type->ndim == 1; + ndim = 1; + if (ctx->enc_count != ctx->head->field->type->arraysize[0]) { + PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %zu", + ctx->head->field->type->arraysize[0], ctx->enc_count); + return -1; + } + } + if (!ctx->is_valid_array) { + PyErr_Format(PyExc_ValueError, "Expected %d dimensions, got %d", + ctx->head->field->type->ndim, ndim); + return -1; + } + for (i = 0; i < ctx->head->field->type->ndim; i++) { + arraysize *= ctx->head->field->type->arraysize[i]; + } + ctx->is_valid_array = 0; + ctx->enc_count = 1; + } + group = __Pyx_BufFmt_TypeCharToGroup(ctx->enc_type, ctx->is_complex); + do { + __Pyx_StructField* field = ctx->head->field; + __Pyx_TypeInfo* type = field->type; + if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') { + size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex); + } else { + size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex); + } + if (ctx->enc_packmode == '@') { + size_t align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex); + size_t align_mod_offset; + if (align_at == 0) return -1; + align_mod_offset = ctx->fmt_offset % align_at; + if (align_mod_offset > 0) ctx->fmt_offset += align_at - align_mod_offset; + if (ctx->struct_alignment == 0) + ctx->struct_alignment = __Pyx_BufFmt_TypeCharToPadding(ctx->enc_type, + ctx->is_complex); + } + if (type->size != size || type->typegroup != group) { + if (type->typegroup == 'C' && type->fields != NULL) { + size_t parent_offset = ctx->head->parent_offset + field->offset; + ++ctx->head; + ctx->head->field = type->fields; + ctx->head->parent_offset = parent_offset; + continue; + } + if ((type->typegroup == 'H' || group == 'H') && type->size == size) { + } else { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + } + offset = ctx->head->parent_offset + field->offset; + if (ctx->fmt_offset != offset) { + PyErr_Format(PyExc_ValueError, + "Buffer dtype mismatch; next field is at offset %" CYTHON_FORMAT_SSIZE_T "d but %" CYTHON_FORMAT_SSIZE_T "d expected", + (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset); + return -1; + } + ctx->fmt_offset += size; + if (arraysize) + ctx->fmt_offset += (arraysize - 1) * size; + --ctx->enc_count; + while (1) { + if (field == &ctx->root) { + ctx->head = NULL; + if (ctx->enc_count != 0) { + __Pyx_BufFmt_RaiseExpected(ctx); + return -1; + } + break; + } + ctx->head->field = ++field; + if (field->type == NULL) { + --ctx->head; + field = ctx->head->field; + continue; + } else if (field->type->typegroup == 'S') { + size_t parent_offset = ctx->head->parent_offset + field->offset; + if (field->type->fields->type == NULL) continue; + field = field->type->fields; + ++ctx->head; + ctx->head->field = field; + ctx->head->parent_offset = parent_offset; + break; + } else { + break; + } + } + } while (ctx->enc_count); + ctx->enc_type = 0; + ctx->is_complex = 0; + return 0; +} +static PyObject * +__pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp) +{ + const char *ts = *tsp; + int i = 0, number; + int ndim = ctx->head->field->type->ndim; +; + ++ts; + if (ctx->new_count != 1) { + PyErr_SetString(PyExc_ValueError, + "Cannot handle repeated arrays in format string"); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + while (*ts && *ts != ')') { + switch (*ts) { + case ' ': case '\f': case '\r': case '\n': case '\t': case '\v': continue; + default: break; + } + number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return NULL; + if (i < ndim && (size_t) number != ctx->head->field->type->arraysize[i]) + return PyErr_Format(PyExc_ValueError, + "Expected a dimension of size %zu, got %d", + ctx->head->field->type->arraysize[i], number); + if (*ts != ',' && *ts != ')') + return PyErr_Format(PyExc_ValueError, + "Expected a comma in format string, got '%c'", *ts); + if (*ts == ',') ts++; + i++; + } + if (i != ndim) + return PyErr_Format(PyExc_ValueError, "Expected %d dimension(s), got %d", + ctx->head->field->type->ndim, i); + if (!*ts) { + PyErr_SetString(PyExc_ValueError, + "Unexpected end of format string, expected ')'"); + return NULL; + } + ctx->is_valid_array = 1; + ctx->new_count = 1; + *tsp = ++ts; + return Py_None; +} +static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) { + int got_Z = 0; + while (1) { + switch(*ts) { + case 0: + if (ctx->enc_type != 0 && ctx->head == NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + if (ctx->head != NULL) { + __Pyx_BufFmt_RaiseExpected(ctx); + return NULL; + } + return ts; + case ' ': + case '\r': + case '\n': + ++ts; + break; + case '<': + if (!__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '>': + case '!': + if (__Pyx_Is_Little_Endian()) { + PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler"); + return NULL; + } + ctx->new_packmode = '='; + ++ts; + break; + case '=': + case '@': + case '^': + ctx->new_packmode = *ts++; + break; + case 'T': + { + const char* ts_after_sub; + size_t i, struct_count = ctx->new_count; + size_t struct_alignment = ctx->struct_alignment; + ctx->new_count = 1; + ++ts; + if (*ts != '{') { + PyErr_SetString(PyExc_ValueError, "Buffer acquisition: Expected '{' after 'T'"); + return NULL; + } + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + ctx->enc_count = 0; + ctx->struct_alignment = 0; + ++ts; + ts_after_sub = ts; + for (i = 0; i != struct_count; ++i) { + ts_after_sub = __Pyx_BufFmt_CheckString(ctx, ts); + if (!ts_after_sub) return NULL; + } + ts = ts_after_sub; + if (struct_alignment) ctx->struct_alignment = struct_alignment; + } + break; + case '}': + { + size_t alignment = ctx->struct_alignment; + ++ts; + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_type = 0; + if (alignment && ctx->fmt_offset % alignment) { + ctx->fmt_offset += alignment - (ctx->fmt_offset % alignment); + } + } + return ts; + case 'x': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->fmt_offset += ctx->new_count; + ctx->new_count = 1; + ctx->enc_count = 0; + ctx->enc_type = 0; + ctx->enc_packmode = ctx->new_packmode; + ++ts; + break; + case 'Z': + got_Z = 1; + ++ts; + if (*ts != 'f' && *ts != 'd' && *ts != 'g') { + __Pyx_BufFmt_RaiseUnexpectedChar('Z'); + return NULL; + } + CYTHON_FALLTHROUGH; + case 'c': case 'b': case 'B': case 'h': case 'H': case 'i': case 'I': + case 'l': case 'L': case 'q': case 'Q': + case 'f': case 'd': case 'g': + case 'O': case 'p': + if (ctx->enc_type == *ts && got_Z == ctx->is_complex && + ctx->enc_packmode == ctx->new_packmode) { + ctx->enc_count += ctx->new_count; + ctx->new_count = 1; + got_Z = 0; + ++ts; + break; + } + CYTHON_FALLTHROUGH; + case 's': + if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL; + ctx->enc_count = ctx->new_count; + ctx->enc_packmode = ctx->new_packmode; + ctx->enc_type = *ts; + ctx->is_complex = got_Z; + ++ts; + ctx->new_count = 1; + got_Z = 0; + break; + case ':': + ++ts; + while(*ts != ':') ++ts; + ++ts; + break; + case '(': + if (!__pyx_buffmt_parse_array(ctx, &ts)) return NULL; + break; + default: + { + int number = __Pyx_BufFmt_ExpectNumber(&ts); + if (number == -1) return NULL; + ctx->new_count = (size_t)number; + } + } + } +} + +/* BufferGetAndValidate */ + static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) { + if (unlikely(info->buf == NULL)) return; + if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL; + __Pyx_ReleaseBuffer(info); +} +static void __Pyx_ZeroBuffer(Py_buffer* buf) { + buf->buf = NULL; + buf->obj = NULL; + buf->strides = __Pyx_zeros; + buf->shape = __Pyx_zeros; + buf->suboffsets = __Pyx_minusones; +} +static int __Pyx__GetBufferAndValidate( + Py_buffer* buf, PyObject* obj, __Pyx_TypeInfo* dtype, int flags, + int nd, int cast, __Pyx_BufFmt_StackElem* stack) +{ + buf->buf = NULL; + if (unlikely(__Pyx_GetBuffer(obj, buf, flags) == -1)) { + __Pyx_ZeroBuffer(buf); + return -1; + } + if (unlikely(buf->ndim != nd)) { + PyErr_Format(PyExc_ValueError, + "Buffer has wrong number of dimensions (expected %d, got %d)", + nd, buf->ndim); + goto fail; + } + if (!cast) { + __Pyx_BufFmt_Context ctx; + __Pyx_BufFmt_Init(&ctx, stack, dtype); + if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail; + } + if (unlikely((size_t)buf->itemsize != dtype->size)) { + PyErr_Format(PyExc_ValueError, + "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "d byte%s) does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "d byte%s)", + buf->itemsize, (buf->itemsize > 1) ? "s" : "", + dtype->name, (Py_ssize_t)dtype->size, (dtype->size > 1) ? "s" : ""); + goto fail; + } + if (buf->suboffsets == NULL) buf->suboffsets = __Pyx_minusones; + return 0; +fail:; + __Pyx_SafeReleaseBuffer(buf); + return -1; +} + +/* PyErrFetchRestore */ + #if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->curexc_type; + tmp_value = tstate->curexc_value; + tmp_tb = tstate->curexc_traceback; + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + *type = tstate->curexc_type; + *value = tstate->curexc_value; + *tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +} +#endif + +/* PyObjectGetAttrStr */ + #if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#endif + +/* GetBuiltinName */ + static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); + if (unlikely(!result)) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* PyObjectCall */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = func->ob_type->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* RaiseException */ + #if PY_MAJOR_VERSION < 3 +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, + CYTHON_UNUSED PyObject *cause) { + __Pyx_PyThreadState_declare + Py_XINCREF(type); + if (!value || value == Py_None) + value = NULL; + else + Py_INCREF(value); + if (!tb || tb == Py_None) + tb = NULL; + else { + Py_INCREF(tb); + if (!PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + } + if (PyType_Check(type)) { +#if CYTHON_COMPILING_IN_PYPY + if (!value) { + Py_INCREF(Py_None); + value = Py_None; + } +#endif + PyErr_NormalizeException(&type, &value, &tb); + } else { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + value = type; + type = (PyObject*) Py_TYPE(type); + Py_INCREF(type); + if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto raise_error; + } + } + __Pyx_PyThreadState_assign + __Pyx_ErrRestore(type, value, tb); + return; +raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return; +} +#else +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + PyObject* owned_instance = NULL; + if (tb == Py_None) { + tb = 0; + } else if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto bad; + } + if (value == Py_None) + value = 0; + if (PyExceptionInstance_Check(type)) { + if (value) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto bad; + } + value = type; + type = (PyObject*) Py_TYPE(value); + } else if (PyExceptionClass_Check(type)) { + PyObject *instance_class = NULL; + if (value && PyExceptionInstance_Check(value)) { + instance_class = (PyObject*) Py_TYPE(value); + if (instance_class != type) { + int is_subclass = PyObject_IsSubclass(instance_class, type); + if (!is_subclass) { + instance_class = NULL; + } else if (unlikely(is_subclass == -1)) { + goto bad; + } else { + type = instance_class; + } + } + } + if (!instance_class) { + PyObject *args; + if (!value) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } else + args = PyTuple_Pack(1, value); + if (!args) + goto bad; + owned_instance = PyObject_Call(type, args, NULL); + Py_DECREF(args); + if (!owned_instance) + goto bad; + value = owned_instance; + if (!PyExceptionInstance_Check(value)) { + PyErr_Format(PyExc_TypeError, + "calling %R should have returned an instance of " + "BaseException, not %R", + type, Py_TYPE(value)); + goto bad; + } + } + } else { + PyErr_SetString(PyExc_TypeError, + "raise: exception class must be a subclass of BaseException"); + goto bad; + } + if (cause) { + PyObject *fixed_cause; + if (cause == Py_None) { + fixed_cause = NULL; + } else if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); + if (tb) { +#if CYTHON_COMPILING_IN_PYPY + PyObject *tmp_type, *tmp_value, *tmp_tb; + PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); + Py_INCREF(tb); + PyErr_Restore(tmp_type, tmp_value, tb); + Py_XDECREF(tmp_tb); +#else + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject* tmp_tb = tstate->curexc_traceback; + if (tb != tmp_tb) { + Py_INCREF(tb); + tstate->curexc_traceback = tb; + Py_XDECREF(tmp_tb); + } +#endif + } +bad: + Py_XDECREF(owned_instance); + return; +} +#endif + +/* PyCFunctionFastCall */ + #if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { + PyCFunctionObject *func = (PyCFunctionObject*)func_obj; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + int flags = PyCFunction_GET_FLAGS(func); + assert(PyCFunction_Check(func)); + assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* _PyCFunction_FastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { + return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); + } else { + return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); + } +} +#endif + +/* PyFunctionFastCall */ + #if CYTHON_FAST_PYCALL +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = __Pyx_PyFrame_GetLocalsplus(f); + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { + return NULL; + } + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif +#endif + +/* PyObjectCallMethO */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { + PyObject *self, *result; + PyCFunction cfunc; + cfunc = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = cfunc(self, arg); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* PyObjectCallOneArg */ + #if CYTHON_COMPILING_IN_CPYTHON +static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_New(1); + if (unlikely(!args)) return NULL; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, arg); + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { +#if CYTHON_FAST_PYCALL + if (PyFunction_Check(func)) { + return __Pyx_PyFunction_FastCall(func, &arg, 1); + } +#endif + if (likely(PyCFunction_Check(func))) { + if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { + return __Pyx_PyObject_CallMethO(func, arg); +#if CYTHON_FAST_PYCCALL + } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) { + return __Pyx_PyCFunction_FastCall(func, &arg, 1); +#endif + } + } + return __Pyx__PyObject_CallOneArg(func, arg); +} +#else +static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { + PyObject *result; + PyObject *args = PyTuple_Pack(1, arg); + if (unlikely(!args)) return NULL; + result = __Pyx_PyObject_Call(func, args, NULL); + Py_DECREF(args); + return result; +} +#endif + +/* DictGetItem */ + #if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY +static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { + PyObject *value; + value = PyDict_GetItemWithError(d, key); + if (unlikely(!value)) { + if (!PyErr_Occurred()) { + if (unlikely(PyTuple_Check(key))) { + PyObject* args = PyTuple_Pack(1, key); + if (likely(args)) { + PyErr_SetObject(PyExc_KeyError, args); + Py_DECREF(args); + } + } else { + PyErr_SetObject(PyExc_KeyError, key); + } + } + return NULL; + } + Py_INCREF(value); + return value; +} +#endif + +/* RaiseTooManyValuesToUnpack */ + static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) { + PyErr_Format(PyExc_ValueError, + "too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected); +} + +/* RaiseNeedMoreValuesToUnpack */ + static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) { + PyErr_Format(PyExc_ValueError, + "need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack", + index, (index == 1) ? "" : "s"); +} + +/* RaiseNoneIterError */ + static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) { + PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); +} + +/* ExtTypeTest */ + static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { + if (unlikely(!type)) { + PyErr_SetString(PyExc_SystemError, "Missing type object"); + return 0; + } + if (likely(__Pyx_TypeCheck(obj, type))) + return 1; + PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", + Py_TYPE(obj)->tp_name, type->tp_name); + return 0; +} + +/* GetTopmostException */ + #if CYTHON_USE_EXC_INFO_STACK +static _PyErr_StackItem * +__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) +{ + _PyErr_StackItem *exc_info = tstate->exc_info; + while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && + exc_info->previous_item != NULL) + { + exc_info = exc_info->previous_item; + } + return exc_info; +} +#endif + +/* SaveResetException */ + #if CYTHON_FAST_THREAD_STATE +static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); + *type = exc_info->exc_type; + *value = exc_info->exc_value; + *tb = exc_info->exc_traceback; + #else + *type = tstate->exc_type; + *value = tstate->exc_value; + *tb = tstate->exc_traceback; + #endif + Py_XINCREF(*type); + Py_XINCREF(*value); + Py_XINCREF(*tb); +} +static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { + PyObject *tmp_type, *tmp_value, *tmp_tb; + #if CYTHON_USE_EXC_INFO_STACK + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = type; + exc_info->exc_value = value; + exc_info->exc_traceback = tb; + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} +#endif + +/* PyErrExceptionMatches */ + #if CYTHON_FAST_THREAD_STATE +static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; icurexc_type; + if (exc_type == err) return 1; + if (unlikely(!exc_type)) return 0; + if (unlikely(PyTuple_Check(err))) + return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); + return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); +} +#endif + +/* GetException */ + #if CYTHON_FAST_THREAD_STATE +static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) +#else +static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) +#endif +{ + PyObject *local_type, *local_value, *local_tb; +#if CYTHON_FAST_THREAD_STATE + PyObject *tmp_type, *tmp_value, *tmp_tb; + local_type = tstate->curexc_type; + local_value = tstate->curexc_value; + local_tb = tstate->curexc_traceback; + tstate->curexc_type = 0; + tstate->curexc_value = 0; + tstate->curexc_traceback = 0; +#else + PyErr_Fetch(&local_type, &local_value, &local_tb); +#endif + PyErr_NormalizeException(&local_type, &local_value, &local_tb); +#if CYTHON_FAST_THREAD_STATE + if (unlikely(tstate->curexc_type)) +#else + if (unlikely(PyErr_Occurred())) +#endif + goto bad; + #if PY_MAJOR_VERSION >= 3 + if (local_tb) { + if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) + goto bad; + } + #endif + Py_XINCREF(local_tb); + Py_XINCREF(local_type); + Py_XINCREF(local_value); + *type = local_type; + *value = local_value; + *tb = local_tb; +#if CYTHON_FAST_THREAD_STATE + #if CYTHON_USE_EXC_INFO_STACK + { + _PyErr_StackItem *exc_info = tstate->exc_info; + tmp_type = exc_info->exc_type; + tmp_value = exc_info->exc_value; + tmp_tb = exc_info->exc_traceback; + exc_info->exc_type = local_type; + exc_info->exc_value = local_value; + exc_info->exc_traceback = local_tb; + } + #else + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = local_type; + tstate->exc_value = local_value; + tstate->exc_traceback = local_tb; + #endif + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +#else + PyErr_SetExcInfo(local_type, local_value, local_tb); +#endif + return 0; +bad: + *type = 0; + *value = 0; + *tb = 0; + Py_XDECREF(local_type); + Py_XDECREF(local_value); + Py_XDECREF(local_tb); + return -1; +} + +/* TypeImport */ + #ifndef __PYX_HAVE_RT_ImportType +#define __PYX_HAVE_RT_ImportType +static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, const char *class_name, + size_t size, enum __Pyx_ImportType_CheckSize check_size) +{ + PyObject *result = 0; + char warning[200]; + Py_ssize_t basicsize; +#ifdef Py_LIMITED_API + PyObject *py_basicsize; +#endif + result = PyObject_GetAttrString(module, class_name); + if (!result) + goto bad; + if (!PyType_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + module_name, class_name); + goto bad; + } +#ifndef Py_LIMITED_API + basicsize = ((PyTypeObject *)result)->tp_basicsize; +#else + py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); + if (!py_basicsize) + goto bad; + basicsize = PyLong_AsSsize_t(py_basicsize); + Py_DECREF(py_basicsize); + py_basicsize = 0; + if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) + goto bad; +#endif + if ((size_t)basicsize < size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + goto bad; + } + if (check_size == __Pyx_ImportType_CheckSize_Error && (size_t)basicsize != size) { + PyErr_Format(PyExc_ValueError, + "%.200s.%.200s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + goto bad; + } + else if (check_size == __Pyx_ImportType_CheckSize_Warn && (size_t)basicsize > size) { + PyOS_snprintf(warning, sizeof(warning), + "%s.%s size changed, may indicate binary incompatibility. " + "Expected %zd from C header, got %zd from PyObject", + module_name, class_name, size, basicsize); + if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; + } + return (PyTypeObject *)result; +bad: + Py_XDECREF(result); + return NULL; +} +#endif + +/* Import */ + static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { + PyObject *empty_list = 0; + PyObject *module = 0; + PyObject *global_dict = 0; + PyObject *empty_dict = 0; + PyObject *list; + #if PY_MAJOR_VERSION < 3 + PyObject *py_import; + py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); + if (!py_import) + goto bad; + #endif + if (from_list) + list = from_list; + else { + empty_list = PyList_New(0); + if (!empty_list) + goto bad; + list = empty_list; + } + global_dict = PyModule_GetDict(__pyx_m); + if (!global_dict) + goto bad; + empty_dict = PyDict_New(); + if (!empty_dict) + goto bad; + { + #if PY_MAJOR_VERSION >= 3 + if (level == -1) { + if (strchr(__Pyx_MODULE_NAME, '.')) { + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, 1); + if (!module) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + goto bad; + PyErr_Clear(); + } + } + level = 0; + } + #endif + if (!module) { + #if PY_MAJOR_VERSION < 3 + PyObject *py_level = PyInt_FromLong(level); + if (!py_level) + goto bad; + module = PyObject_CallFunctionObjArgs(py_import, + name, global_dict, empty_dict, list, py_level, (PyObject *)NULL); + Py_DECREF(py_level); + #else + module = PyImport_ImportModuleLevelObject( + name, global_dict, empty_dict, list, level); + #endif + } + } +bad: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(py_import); + #endif + Py_XDECREF(empty_list); + Py_XDECREF(empty_dict); + return module; +} + +/* PyDictVersioning */ + #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; +} +static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { + PyObject **dictptr = NULL; + Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; + if (offset) { +#if CYTHON_COMPILING_IN_CPYTHON + dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); +#else + dictptr = _PyObject_GetDictPtr(obj); +#endif + } + return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; +} +static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { + PyObject *dict = Py_TYPE(obj)->tp_dict; + if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) + return 0; + return obj_dict_version == __Pyx_get_object_dict_version(obj); +} +#endif + +/* CLineInTraceback */ + #ifndef CYTHON_CLINE_IN_TRACEBACK +static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { + PyObject *use_cline; + PyObject *ptype, *pvalue, *ptraceback; +#if CYTHON_COMPILING_IN_CPYTHON + PyObject **cython_runtime_dict; +#endif + if (unlikely(!__pyx_cython_runtime)) { + return c_line; + } + __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); +#if CYTHON_COMPILING_IN_CPYTHON + cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); + if (likely(cython_runtime_dict)) { + __PYX_PY_DICT_LOOKUP_IF_MODIFIED( + use_cline, *cython_runtime_dict, + __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) + } else +#endif + { + PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); + if (use_cline_obj) { + use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; + Py_DECREF(use_cline_obj); + } else { + PyErr_Clear(); + use_cline = NULL; + } + } + if (!use_cline) { + c_line = 0; + PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); + } + else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { + c_line = 0; + } + __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); + return c_line; +} +#endif + +/* CodeObjectCache */ + static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} + +/* AddTraceback */ + #include "compile.h" +#include "frameobject.h" +#include "traceback.h" +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyObject *py_srcfile = 0; + PyObject *py_funcname = 0; + #if PY_MAJOR_VERSION < 3 + py_srcfile = PyString_FromString(filename); + #else + py_srcfile = PyUnicode_FromString(filename); + #endif + if (!py_srcfile) goto bad; + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + #else + py_funcname = PyUnicode_FromString(funcname); + #endif + } + if (!py_funcname) goto bad; + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + Py_DECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_srcfile); + Py_XDECREF(py_funcname); + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + PyThreadState *tstate = __Pyx_PyThreadState_Current; + if (c_line) { + c_line = __Pyx_CLineForTraceback(tstate, c_line); + } + py_code = __pyx_find_code_object(c_line ? -c_line : py_line); + if (!py_code) { + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) goto bad; + __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); + } + py_frame = PyFrame_New( + tstate, /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +#if PY_MAJOR_VERSION < 3 +static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { + if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags); + if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) return __pyx_pw_5numpy_7ndarray_1__getbuffer__(obj, view, flags); + PyErr_Format(PyExc_TypeError, "'%.200s' does not have the buffer interface", Py_TYPE(obj)->tp_name); + return -1; +} +static void __Pyx_ReleaseBuffer(Py_buffer *view) { + PyObject *obj = view->obj; + if (!obj) return; + if (PyObject_CheckBuffer(obj)) { + PyBuffer_Release(view); + return; + } + if ((0)) {} + else if (__Pyx_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); + view->obj = NULL; + Py_DECREF(obj); +} +#endif + + + /* CIntFromPyVerify */ + #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* Declarations */ + #if CYTHON_CCOMPLEX + #ifdef __cplusplus + static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) { + return ::std::complex< float >(x, y); + } + #else + static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) { + return x + y*(__pyx_t_float_complex)_Complex_I; + } + #endif +#else + static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) { + __pyx_t_float_complex z; + z.real = x; + z.imag = y; + return z; + } +#endif + +/* Arithmetic */ + #if CYTHON_CCOMPLEX +#else + static CYTHON_INLINE int __Pyx_c_eq_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + return (a.real == b.real) && (a.imag == b.imag); + } + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sum_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + __pyx_t_float_complex z; + z.real = a.real + b.real; + z.imag = a.imag + b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_diff_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + __pyx_t_float_complex z; + z.real = a.real - b.real; + z.imag = a.imag - b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prod_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + __pyx_t_float_complex z; + z.real = a.real * b.real - a.imag * b.imag; + z.imag = a.real * b.imag + a.imag * b.real; + return z; + } + #if 1 + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + if (b.imag == 0) { + return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.real); + } else if (fabsf(b.real) >= fabsf(b.imag)) { + if (b.real == 0 && b.imag == 0) { + return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.imag); + } else { + float r = b.imag / b.real; + float s = (float)(1.0) / (b.real + b.imag * r); + return __pyx_t_float_complex_from_parts( + (a.real + a.imag * r) * s, (a.imag - a.real * r) * s); + } + } else { + float r = b.real / b.imag; + float s = (float)(1.0) / (b.imag + b.real * r); + return __pyx_t_float_complex_from_parts( + (a.real * r + a.imag) * s, (a.imag * r - a.real) * s); + } + } + #else + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + if (b.imag == 0) { + return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.real); + } else { + float denom = b.real * b.real + b.imag * b.imag; + return __pyx_t_float_complex_from_parts( + (a.real * b.real + a.imag * b.imag) / denom, + (a.imag * b.real - a.real * b.imag) / denom); + } + } + #endif + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_neg_float(__pyx_t_float_complex a) { + __pyx_t_float_complex z; + z.real = -a.real; + z.imag = -a.imag; + return z; + } + static CYTHON_INLINE int __Pyx_c_is_zero_float(__pyx_t_float_complex a) { + return (a.real == 0) && (a.imag == 0); + } + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conj_float(__pyx_t_float_complex a) { + __pyx_t_float_complex z; + z.real = a.real; + z.imag = -a.imag; + return z; + } + #if 1 + static CYTHON_INLINE float __Pyx_c_abs_float(__pyx_t_float_complex z) { + #if !defined(HAVE_HYPOT) || defined(_MSC_VER) + return sqrtf(z.real*z.real + z.imag*z.imag); + #else + return hypotf(z.real, z.imag); + #endif + } + static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_pow_float(__pyx_t_float_complex a, __pyx_t_float_complex b) { + __pyx_t_float_complex z; + float r, lnr, theta, z_r, z_theta; + if (b.imag == 0 && b.real == (int)b.real) { + if (b.real < 0) { + float denom = a.real * a.real + a.imag * a.imag; + a.real = a.real / denom; + a.imag = -a.imag / denom; + b.real = -b.real; + } + switch ((int)b.real) { + case 0: + z.real = 1; + z.imag = 0; + return z; + case 1: + return a; + case 2: + z = __Pyx_c_prod_float(a, a); + return __Pyx_c_prod_float(a, a); + case 3: + z = __Pyx_c_prod_float(a, a); + return __Pyx_c_prod_float(z, a); + case 4: + z = __Pyx_c_prod_float(a, a); + return __Pyx_c_prod_float(z, z); + } + } + if (a.imag == 0) { + if (a.real == 0) { + return a; + } else if (b.imag == 0) { + z.real = powf(a.real, b.real); + z.imag = 0; + return z; + } else if (a.real > 0) { + r = a.real; + theta = 0; + } else { + r = -a.real; + theta = atan2f(0.0, -1.0); + } + } else { + r = __Pyx_c_abs_float(a); + theta = atan2f(a.imag, a.real); + } + lnr = logf(r); + z_r = expf(lnr * b.real - theta * b.imag); + z_theta = theta * b.real + lnr * b.imag; + z.real = z_r * cosf(z_theta); + z.imag = z_r * sinf(z_theta); + return z; + } + #endif +#endif + +/* Declarations */ + #if CYTHON_CCOMPLEX + #ifdef __cplusplus + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + return ::std::complex< double >(x, y); + } + #else + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + return x + y*(__pyx_t_double_complex)_Complex_I; + } + #endif +#else + static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) { + __pyx_t_double_complex z; + z.real = x; + z.imag = y; + return z; + } +#endif + +/* Arithmetic */ + #if CYTHON_CCOMPLEX +#else + static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + return (a.real == b.real) && (a.imag == b.imag); + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real + b.real; + z.imag = a.imag + b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real - b.real; + z.imag = a.imag - b.imag; + return z; + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + z.real = a.real * b.real - a.imag * b.imag; + z.imag = a.real * b.imag + a.imag * b.real; + return z; + } + #if 1 + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + if (b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real); + } else if (fabs(b.real) >= fabs(b.imag)) { + if (b.real == 0 && b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.imag); + } else { + double r = b.imag / b.real; + double s = (double)(1.0) / (b.real + b.imag * r); + return __pyx_t_double_complex_from_parts( + (a.real + a.imag * r) * s, (a.imag - a.real * r) * s); + } + } else { + double r = b.real / b.imag; + double s = (double)(1.0) / (b.imag + b.real * r); + return __pyx_t_double_complex_from_parts( + (a.real * r + a.imag) * s, (a.imag * r - a.real) * s); + } + } + #else + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + if (b.imag == 0) { + return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real); + } else { + double denom = b.real * b.real + b.imag * b.imag; + return __pyx_t_double_complex_from_parts( + (a.real * b.real + a.imag * b.imag) / denom, + (a.imag * b.real - a.real * b.imag) / denom); + } + } + #endif + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex a) { + __pyx_t_double_complex z; + z.real = -a.real; + z.imag = -a.imag; + return z; + } + static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex a) { + return (a.real == 0) && (a.imag == 0); + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex a) { + __pyx_t_double_complex z; + z.real = a.real; + z.imag = -a.imag; + return z; + } + #if 1 + static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex z) { + #if !defined(HAVE_HYPOT) || defined(_MSC_VER) + return sqrt(z.real*z.real + z.imag*z.imag); + #else + return hypot(z.real, z.imag); + #endif + } + static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex a, __pyx_t_double_complex b) { + __pyx_t_double_complex z; + double r, lnr, theta, z_r, z_theta; + if (b.imag == 0 && b.real == (int)b.real) { + if (b.real < 0) { + double denom = a.real * a.real + a.imag * a.imag; + a.real = a.real / denom; + a.imag = -a.imag / denom; + b.real = -b.real; + } + switch ((int)b.real) { + case 0: + z.real = 1; + z.imag = 0; + return z; + case 1: + return a; + case 2: + z = __Pyx_c_prod_double(a, a); + return __Pyx_c_prod_double(a, a); + case 3: + z = __Pyx_c_prod_double(a, a); + return __Pyx_c_prod_double(z, a); + case 4: + z = __Pyx_c_prod_double(a, a); + return __Pyx_c_prod_double(z, z); + } + } + if (a.imag == 0) { + if (a.real == 0) { + return a; + } else if (b.imag == 0) { + z.real = pow(a.real, b.real); + z.imag = 0; + return z; + } else if (a.real > 0) { + r = a.real; + theta = 0; + } else { + r = -a.real; + theta = atan2(0.0, -1.0); + } + } else { + r = __Pyx_c_abs_double(a); + theta = atan2(a.imag, a.real); + } + lnr = log(r); + z_r = exp(lnr * b.real - theta * b.imag); + z_theta = theta * b.real + lnr * b.imag; + z.real = z_r * cos(z_theta); + z.imag = z_r * sin(z_theta); + return z; + } + #endif +#endif + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { + const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(int) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(int) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(int) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(int), + little, !is_unsigned); + } +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) { + const enum NPY_TYPES neg_one = (enum NPY_TYPES) ((enum NPY_TYPES) 0 - (enum NPY_TYPES) 1), const_zero = (enum NPY_TYPES) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(enum NPY_TYPES) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(enum NPY_TYPES) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES), + little, !is_unsigned); + } +} + +/* CIntFromPy */ + static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { + const int neg_one = (int) ((int) 0 - (int) 1), const_zero = (int) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(int) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(int) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) + case -2: + if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } +#endif + if (sizeof(int) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + int val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (int) -1; + } + } else { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { + const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); + } +} + +/* CIntFromPy */ + static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { + const long neg_one = (long) ((long) 0 - (long) 1), const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) + case -2: + if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (long) -1; + } + } else { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* FastTypeChecks */ + #if CYTHON_COMPILING_IN_CPYTHON +static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { + while (a) { + a = a->tp_base; + if (a == b) + return 1; + } + return b == &PyBaseObject_Type; +} +static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { + PyObject *mro; + if (a == b) return 1; + mro = a->tp_mro; + if (likely(mro)) { + Py_ssize_t i, n; + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + return __Pyx_InBases(a, b); +} +#if PY_MAJOR_VERSION == 2 +static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { + PyObject *exception, *value, *tb; + int res; + __Pyx_PyThreadState_declare + __Pyx_PyThreadState_assign + __Pyx_ErrFetch(&exception, &value, &tb); + res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + if (!res) { + res = PyObject_IsSubclass(err, exc_type2); + if (unlikely(res == -1)) { + PyErr_WriteUnraisable(err); + res = 0; + } + } + __Pyx_ErrRestore(exception, value, tb); + return res; +} +#else +static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { + int res = exc_type1 ? __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type1) : 0; + if (!res) { + res = __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); + } + return res; +} +#endif +static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { + Py_ssize_t i, n; + assert(PyExceptionClass_Check(exc_type)); + n = PyTuple_GET_SIZE(tuple); +#if PY_MAJOR_VERSION >= 3 + for (i=0; ip) { + #if PY_MAJOR_VERSION < 3 + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + #else + if (t->is_unicode | t->is_str) { + if (t->intern) { + *t->p = PyUnicode_InternFromString(t->s); + } else if (t->encoding) { + *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); + } else { + *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); + } + } else { + *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); + } + #endif + if (!*t->p) + return -1; + if (PyObject_Hash(*t->p) == -1) + return -1; + ++t; + } + return 0; +} + +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); +} +static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +#if !CYTHON_PEP393_ENABLED +static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +} +#else +static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { + if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (likely(PyUnicode_IS_ASCII(o))) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +} +#endif +#endif +static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { + return __Pyx_PyUnicode_AsStringAndSize(o, length); + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { + int retval; + if (unlikely(!x)) return -1; + retval = __Pyx_PyObject_IsTrue(x); + Py_DECREF(x); + return retval; +} +static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(result)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(result)->tp_name)) { + Py_DECREF(result); + return NULL; + } + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type %.200s)", + type_name, type_name, Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x) || PyLong_Check(x))) +#else + if (likely(PyLong_Check(x))) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = m->nb_int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = m->nb_long(x); + } + #else + if (likely(m && m->nb_int)) { + name = "int"; + res = m->nb_int(x); + } + #endif +#else + if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { + res = PyNumber_Int(x); + } +#endif + if (likely(res)) { +#if PY_MAJOR_VERSION < 3 + if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { +#else + if (unlikely(!PyLong_CheckExact(res))) { +#endif + return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(b); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)b)->ob_digit; + const Py_ssize_t size = Py_SIZE(b); + if (likely(__Pyx_sst_abs(size) <= 1)) { + ival = likely(size) ? digits[0] : 0; + if (size == -1) ival = -ival; + return ival; + } else { + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { + return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +#endif /* Py_PYTHON_H */ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.pyx b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.pyx new file mode 100644 index 0000000000..7d9e5a76e5 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/mesh_core_cython.pyx @@ -0,0 +1,65 @@ +import numpy as np +cimport numpy as np +from libcpp.string cimport string +cimport cython + +# use the Numpy-C-API from Cython +np.import_array() + +# cdefine the signature of our c function +cdef extern from "mesh_core.h": + void _render_colors_core( + float* image, float* vertices, int* triangles, + float* colors, + float* depth_buffer, + int nver, int ntri, + int h, int w, int c + ) + + void _get_normal_core( + float* normal, float* tri_normal, int* triangles, + int ntri + ) + + void _get_normal(float *ver_normal, float *vertices, int *triangles, int nver, int ntri) + + +@cython.boundscheck(False) +@cython.wraparound(False) +def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, + np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, + np.ndarray[int, ndim=2, mode="c"] triangles not None, + int ntri + ): + _get_normal_core( + np.PyArray_DATA(normal), np.PyArray_DATA(tri_normal), np.PyArray_DATA(triangles), + ntri + ) + +@cython.boundscheck(False) +@cython.wraparound(False) +def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, + np.ndarray[float, ndim=2, mode = "c"] vertices not None, + np.ndarray[int, ndim=2, mode="c"] triangles not None, + np.ndarray[float, ndim=2, mode = "c"] colors not None, + np.ndarray[float, ndim=2, mode = "c"] depth_buffer not None, + int nver, int ntri, + int h, int w, int c + ): + _render_colors_core( + np.PyArray_DATA(image), np.PyArray_DATA(vertices), np.PyArray_DATA(triangles), + np.PyArray_DATA(colors), + np.PyArray_DATA(depth_buffer), + nver, ntri, + h, w, c + ) + +@cython.boundscheck(False) # turn off bounds-checking for entire function +@cython.wraparound(False) # turn off negative index wrapping for entire function +def get_normal(np.ndarray[float, ndim=2, mode = "c"] ver_normal not None, + np.ndarray[float, ndim=2, mode = "c"] vertices not None, + np.ndarray[int, ndim=2, mode="c"] triangles not None, + int nver, int ntri): + _get_normal( + np.PyArray_DATA(ver_normal), np.PyArray_DATA(vertices), np.PyArray_DATA(triangles), + nver, ntri) \ No newline at end of file diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/readme.md b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/readme.md new file mode 100644 index 0000000000..5d959a45f8 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/readme.md @@ -0,0 +1,6 @@ +### Cython compiling +``` +python3 setup.py build_ext -i +``` + +The `mesh_core_cython.*.so` will be generated. The specific name depends on your system. \ No newline at end of file diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/setup.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/setup.py new file mode 100644 index 0000000000..f58aa5b041 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/cython/setup.py @@ -0,0 +1,19 @@ +''' +python setup.py build_ext -i +to compile +''' + +# setup.py +from distutils.core import setup, Extension +# from Cython.Build import cythonize +from Cython.Distutils import build_ext +import numpy + +setup( + name='mesh_core_cython', + cmdclass={'build_ext': build_ext}, + ext_modules=[Extension("mesh_core_cython", + sources=["mesh_core_cython.pyx", "mesh_core.cpp"], + language='c++', + include_dirs=[numpy.get_include()])], +) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/ddfa.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/ddfa.py new file mode 100644 index 0000000000..7138268c37 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/ddfa.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path as osp +from pathlib import Path +import numpy as np + +import torch +import torch.utils.data as data +import cv2 +import argparse +from .io import _numpy_to_tensor, _load_cpu +from .params import std_size, w_exp_base, w_shp_base, u_base, w_shp, param_std, param_mean, u, w_exp +from .estimate_pose import P2sRt + + +def _parse_param(param): + """Work for both numpy and tensor""" + p_ = param[:12].reshape(3, -1) + p = p_[:, :3] + offset = p_[:, -1].reshape(3, 1) + alpha_shp = param[12:52].reshape(-1, 1) + alpha_exp = param[52:].reshape(-1, 1) + return p, offset, alpha_shp, alpha_exp + + +def reconstruct_vertex(param, whitening=True, dense=False, transform=True, align_pose=False): + """Whitening param -> 3d vertex, based on the 3dmm param: u_base, w_shp, w_exp + dense: if True, return dense vertex, else return 68 sparse landmarks. All dense or sparse vertex is transformed to + image coordinate space, but without alignment caused by face cropping. + transform: whether transform to image space + """ + if len(param) == 12: + param = np.concatenate((param, [0] * 50)) + if whitening: + if len(param) == 62: + param = param * param_std + param_mean + else: + param = np.concatenate((param[:11], [0], param[11:])) + param = param * param_std + param_mean + if align_pose: + print('align param') + Ps = param[:12].reshape(3, -1) + s, R, t3d = P2sRt(Ps) + Ps[:, :3] = np.identity(3) * s + param[:12] = Ps.reshape(-1) + + p, offset, alpha_shp, alpha_exp = _parse_param(param) + + if dense: + vertex = p @ (u + w_shp @ alpha_shp + w_exp @ alpha_exp).reshape(3, -1, order='F') + offset + + if transform: + # transform to image coordinate space + vertex[1, :] = std_size + 1 - vertex[1, :] + else: + """For 68 pts""" + vertex = p @ (u_base + w_shp_base @ alpha_shp + w_exp_base @ alpha_exp).reshape(3, -1, order='F') + offset + + if transform: + # transform to image coordinate space + vertex[1, :] = std_size + 1 - vertex[1, :] + + return vertex + + +def img_loader(path): + return cv2.imread(path, cv2.IMREAD_COLOR) + + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected') + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +class ToTensorGjz(object): + def __call__(self, pic): + if isinstance(pic, np.ndarray): + img = torch.from_numpy(pic.transpose((2, 0, 1))) + return img.float() + + def __repr__(self): + return self.__class__.__name__ + '()' + + +class NormalizeGjz(object): + def __init__(self, mean, std): + self.mean = mean + self.std = std + + def __call__(self, tensor): + tensor.sub_(self.mean).div_(self.std) + return tensor + + +class DDFADataset(data.Dataset): + def __init__(self, root, filelists, param_fp, transform=None, **kargs): + self.root = root + self.transform = transform + self.lines = Path(filelists).read_text().strip().split('\n') + self.params = _numpy_to_tensor(_load_cpu(param_fp)) + self.img_loader = img_loader + + def _target_loader(self, index): + target = self.params[index] + + return target + + def __getitem__(self, index): + path = osp.join(self.root, self.lines[index]) + img = self.img_loader(path) + + target = self._target_loader(index) + + if self.transform is not None: + img = self.transform(img) + return img, target + + def __len__(self): + return len(self.lines) + + +class DDFATestDataset(data.Dataset): + def __init__(self, filelists, root='', transform=None): + self.root = root + self.transform = transform + self.lines = Path(filelists).read_text().strip().split('\n') + + def __getitem__(self, index): + path = osp.join(self.root, self.lines[index]) + img = img_loader(path) + + if self.transform is not None: + img = self.transform(img) + return img + + def __len__(self): + return len(self.lines) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/estimate_pose.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/estimate_pose.py new file mode 100644 index 0000000000..3f40232aae --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/estimate_pose.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +Reference: https://github.com/YadiraF/PRNet/blob/master/utils/estimate_pose.py +""" + +from math import cos, sin, atan2, asin +import numpy as np +from .params import param_mean, param_std + + +def parse_pose(param): + param = param * param_std + param_mean + Ps = param[:12].reshape(3, -1) # camera matrix + # R = P[:, :3] + s, R, t3d = P2sRt(Ps) + R.tofile('pose.txt', sep=' ') + P = np.concatenate((R, t3d.reshape(3, -1)), axis=1) # without scale + # P = Ps / s + pose = matrix2angle(R) # yaw, pitch, roll + # offset = p_[:, -1].reshape(3, 1) + return P, pose + + +def matrix2angle(R): + ''' compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf + Args: + R: (3,3). rotation matrix + Returns: + x: yaw + y: pitch + z: roll + ''' + # assert(isRotationMatrix(R)) + + if R[2, 0] != 1 and R[2, 0] != -1: + x = -asin(max(-1, min(R[2, 0], 1))) + y = atan2(R[2, 1] / cos(x), R[2, 2] / cos(x)) + z = atan2(R[1, 0] / cos(x), R[0, 0] / cos(x)) + + else: # Gimbal lock + z = 0 # can be anything + if R[2, 0] == -1: + x = np.pi / 2 + y = z + atan2(R[0, 1], R[0, 2]) + else: + x = -np.pi / 2 + y = -z + atan2(-R[0, 1], -R[0, 2]) + + return x, y, z + + +def angle2matrix(angles): + ''' get rotation matrix from three rotation angles(radian). The same as in 3DDFA. + Args: + angles: [3,]. x, y, z angles + x: yaw. + y: pitch. + z: roll. + Returns: + R: 3x3. rotation matrix. + ''' + # x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2]) + # x, y, z = angles[0], angles[1], angles[2] + y, x, z = angles[0], angles[1], angles[2] + + # x + Rx = np.array([[1, 0, 0], + [0, cos(x), -sin(x)], + [0, sin(x), cos(x)]]) + # y + Ry = np.array([[cos(y), 0, sin(y)], + [0, 1, 0], + [-sin(y), 0, cos(y)]]) + # z + Rz = np.array([[cos(z), -sin(z), 0], + [sin(z), cos(z), 0], + [0, 0, 1]]) + R = Rz.dot(Ry).dot(Rx) + return R.astype(np.float32) + + +def P2sRt(P): + ''' decompositing camera matrix P. + Args: + P: (3, 4). Affine Camera Matrix. + Returns: + s: scale factor. + R: (3, 3). rotation matrix. + t2d: (2,). 2d translation. + ''' + t3d = P[:, 3] + R1 = P[0:1, :3] + R2 = P[1:2, :3] + s = (np.linalg.norm(R1) + np.linalg.norm(R2)) / 2.0 + r1 = R1 / np.linalg.norm(R1) + r2 = R2 / np.linalg.norm(R2) + r3 = np.cross(r1, r2) + + R = np.concatenate((r1, r2, r3), 0) + return s, R, t3d + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/inference.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/inference.py new file mode 100644 index 0000000000..fa2f1b0875 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/inference.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import numpy as np +from math import sqrt +import scipy.io as sio +import matplotlib.pyplot as plt +from .ddfa import reconstruct_vertex +from .estimate_pose import matrix2angle, angle2matrix, P2sRt + +__author__ = 'cleardusk' +__all__ = ['matrix2angle', 'angle2matrix'] + + +def get_5lmk_from_68lmk(lmk68): + left_eye = lmk68[36:42, :].mean(axis=0) + right_eye = lmk68[42:48, :].mean(axis=0) + nose = lmk68[33, :] + left_mouse = lmk68[48, :] + right_mouse = lmk68[54, :] + lmk5 = [left_eye, right_eye, nose, left_mouse, right_mouse] + return np.concatenate(lmk5) + + +def get_suffix(filename): + """a.jpg -> jpg""" + pos = filename.rfind('.') + if pos == -1: + return '' + return filename[pos:] + + +def crop_img(img, roi_box): + h, w = img.shape[:2] + + sx, sy, ex, ey = [int(round(_)) for _ in roi_box] + dh, dw = ey - sy, ex - sx + if len(img.shape) == 3: + res = np.zeros((dh, dw, 3), dtype=np.uint8) + else: + res = np.zeros((dh, dw), dtype=np.uint8) + if sx < 0: + sx, dsx = 0, -sx + else: + dsx = 0 + + if ex > w: + ex, dex = w, dw - (ex - w) + else: + dex = dw + + if sy < 0: + sy, dsy = 0, -sy + else: + dsy = 0 + + if ey > h: + ey, dey = h, dh - (ey - h) + else: + dey = dh + + res[dsy:dey, dsx:dex] = img[sy:ey, sx:ex] + return res + + +def calc_hypotenuse(pts): + bbox = [min(pts[0, :]), min(pts[1, :]), max(pts[0, :]), max(pts[1, :])] + center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2] + radius = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) / 2 + bbox = [center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius] + llength = sqrt((bbox[2] - bbox[0]) ** 2 + (bbox[3] - bbox[1]) ** 2) + return llength / 3 + + +def parse_roi_box_from_landmark(pts): + """calc roi box from landmark""" + bbox = [min(pts[0, :]), min(pts[1, :]), max(pts[0, :]), max(pts[1, :])] + center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2] + radius = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) / 2 + bbox = [center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius] + + llength = sqrt((bbox[2] - bbox[0]) ** 2 + (bbox[3] - bbox[1]) ** 2) + center_x = (bbox[2] + bbox[0]) / 2 + center_y = (bbox[3] + bbox[1]) / 2 + + roi_box = [0] * 4 + roi_box[0] = center_x - llength / 2 + roi_box[1] = center_y - llength / 2 + roi_box[2] = roi_box[0] + llength + roi_box[3] = roi_box[1] + llength + + return roi_box + + +def parse_roi_box_from_bbox(bbox): + left, top, right, bottom = bbox + old_size = (right - left + bottom - top) / 2 + center_x = right - (right - left) / 2.0 + center_y = bottom - (bottom - top) / 2.0 + old_size * 0.14 + size = int(old_size * 1.58) + roi_box = [0] * 4 + roi_box[0] = center_x - size / 2 + roi_box[1] = center_y - size / 2 + roi_box[2] = roi_box[0] + size + roi_box[3] = roi_box[1] + size + return roi_box + + +def dump_to_ply(vertex, tri, wfp): + header = """ply + format ascii 1.0 + element vertex {} + property float x + property float y + property float z + element face {} + property list uchar int vertex_indices + end_header""" + + n_vertex = vertex.shape[1] + n_face = tri.shape[1] + header = header.format(n_vertex, n_face) + + with open(wfp, 'w') as f: + f.write(header + '\n') + for i in range(n_vertex): + x, y, z = vertex[:, i] + f.write('{:.4f} {:.4f} {:.4f}\n'.format(x, y, z)) + for i in range(n_face): + idx1, idx2, idx3 = tri[:, i] + f.write('3 {} {} {}\n'.format(idx1 - 1, idx2 - 1, idx3 - 1)) + print('Dump tp {}'.format(wfp)) + + +def dump_vertex(vertex, wfp): + sio.savemat(wfp, {'vertex': vertex}) + print('Dump to {}'.format(wfp)) + + +def _predict_vertices(param, roi_bbox, dense, transform=True, align_pose=False): + vertex = reconstruct_vertex(param, dense=dense, align_pose=align_pose) + sx, sy, ex, ey = roi_bbox + scale_x = (ex - sx) / 120 + scale_y = (ey - sy) / 120 + vertex[0, :] = vertex[0, :] * scale_x + sx + vertex[1, :] = vertex[1, :] * scale_y + sy + + s = (scale_x + scale_y) / 2 + vertex[2, :] *= s + + return vertex + + +def predict_68pts(param, roi_box, align_pose=False): + return _predict_vertices(param, roi_box, dense=False, align_pose=align_pose) + + +def predict_dense(param, roi_box, align_pose=False): + return _predict_vertices(param, roi_box, dense=True, align_pose=align_pose) + + +def get_aligned_param(param): + Ps = param[:12].reshape(3, -1) + s, R, t3d = P2sRt(Ps) + Ps[:, :3] = np.identity(3) * s + # t3d = t3d.reshape(3, -1) + # p = p_[:, :3] + # offset = p_[:, -1].reshape(3, 1) + # print(R) + # angles = matrix2angle(R) # yaw, pitch, roll + # angles = [x, y, z] + # if 'yaw' in change_axis: + # angles[0] = 0 + # if 'pitch' in change_axis: + # angles[1] = 0 + # if 'roll' in change_axis: + # angles[2] = 0 + # p = angle2matrix(angles) + # print(p) + # new_p_ = np.concatenate((p, t3d), axis=1).reshape(-1) + param[:12] = Ps.reshape(-1) + return param + + +def draw_landmarks(img, pts, style='fancy', wfp=None, show_flg=False, **kwargs): + """Draw landmarks using matplotlib""" + height, width = img.shape[:2] + plt.figure(figsize=(12, height / width * 12)) + plt.imshow(img[:, :, ::-1]) + plt.subplots_adjust(left=0, right=1, top=1, bottom=0) + plt.axis('off') + + if not type(pts) in [tuple, list]: + pts = [pts] + for i in range(len(pts)): + if style == 'simple': + plt.plot(pts[i][0, :], pts[i][1, :], 'o', markersize=4, color='g') + + elif style == 'fancy': + alpha = 0.8 + markersize = 4 + lw = 1.5 + color = kwargs.get('color', 'w') + markeredgecolor = kwargs.get('markeredgecolor', 'black') + + nums = [0, 17, 22, 27, 31, 36, 42, 48, 60, 68] + + # close eyes and mouths + def plot_close(i1, i2): + return plt.plot([pts[i][0, i1], pts[i][0, i2]], [pts[i][1, i1], pts[i][1, i2]], color=color, lw=lw, + alpha=alpha - 0.1) + + plot_close(41, 36) + plot_close(47, 42) + plot_close(59, 48) + plot_close(67, 60) + + for ind in range(len(nums) - 1): + l, r = nums[ind], nums[ind + 1] + plt.plot(pts[i][0, l:r], pts[i][1, l:r], color=color, lw=lw, alpha=alpha - 0.1) + + plt.plot(pts[i][0, l:r], pts[i][1, l:r], marker='o', linestyle='None', markersize=markersize, + color=color, + markeredgecolor=markeredgecolor, alpha=alpha) + + if wfp is not None: + plt.savefig(wfp, dpi=200) + print('Save visualization result to {}'.format(wfp)) + if show_flg: + plt.show() + + +def get_colors(image, vertices): + [h, w, _] = image.shape + vertices[0, :] = np.minimum(np.maximum(vertices[0, :], 0), w - 1) # x + vertices[1, :] = np.minimum(np.maximum(vertices[1, :], 0), h - 1) # y + ind = np.round(vertices).astype(np.int32) + colors = image[ind[1, :], ind[0, :], :] # n x 3 + + return colors + + +def write_obj_with_colors(obj_name, vertices, triangles, colors): + triangles = triangles.copy() # meshlab start with 1 + + if obj_name.split('.')[-1] != 'obj': + obj_name = obj_name + '.obj' + + # write obj + with open(obj_name, 'w') as f: + # write vertices & colors + for i in range(vertices.shape[1]): + s = 'v {:.4f} {:.4f} {:.4f} {} {} {}\n'.format(vertices[1, i], vertices[0, i], vertices[2, i], colors[i, 2], + colors[i, 1], colors[i, 0]) + f.write(s) + + # write f: ver ind/ uv ind + for i in range(triangles.shape[1]): + s = 'f {} {} {}\n'.format(triangles[0, i], triangles[1, i], triangles[2, i]) + f.write(s) + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/io.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/io.py new file mode 100644 index 0000000000..71b446989a --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/io.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import numpy as np +import torch +import pickle +import scipy.io as sio + + +def mkdir(d): + """only works on *nix system""" + if not os.path.isdir(d) and not os.path.exists(d): + os.system('mkdir -p {}'.format(d)) + + +def _get_suffix(filename): + """a.jpg -> jpg""" + pos = filename.rfind('.') + if pos == -1: + return '' + return filename[pos + 1:] + + +def _load(fp): + suffix = _get_suffix(fp) + if suffix == 'npy': + return np.load(fp) + elif suffix == 'pkl': + return pickle.load(open(fp, 'rb')) + + +def _dump(wfp, obj): + suffix = _get_suffix(wfp) + if suffix == 'npy': + np.save(wfp, obj) + elif suffix == 'pkl': + pickle.dump(obj, open(wfp, 'wb')) + else: + raise Exception('Unknown Type: {}'.format(suffix)) + + +def _load_tensor(fp, mode='cpu'): + if mode.lower() == 'cpu': + return torch.from_numpy(_load(fp)) + elif mode.lower() == 'gpu': + return torch.from_numpy(_load(fp)).cuda() + + +def _tensor_to_cuda(x): + if x.is_cuda: + return x + else: + return x.cuda() + + +def _load_gpu(fp): + return torch.from_numpy(_load(fp)).cuda() + + +def load_bfm(model_path): + suffix = _get_suffix(model_path) + if suffix == 'mat': + C = sio.loadmat(model_path) + model = C['model_refine'] + model = model[0, 0] + + model_new = {} + w_shp = model['w'].astype(np.float32) + model_new['w_shp_sim'] = w_shp[:, :40] + w_exp = model['w_exp'].astype(np.float32) + model_new['w_exp_sim'] = w_exp[:, :10] + + u_shp = model['mu_shape'] + u_exp = model['mu_exp'] + u = (u_shp + u_exp).astype(np.float32) + model_new['mu'] = u + model_new['tri'] = model['tri'].astype(np.int32) - 1 + + # flatten it, pay attention to index value + keypoints = model['keypoints'].astype(np.int32) - 1 + keypoints = np.concatenate((3 * keypoints, 3 * keypoints + 1, 3 * keypoints + 2), axis=0) + + model_new['keypoints'] = keypoints.T.flatten() + + # + w = np.concatenate((w_shp, w_exp), axis=1) + w_base = w[keypoints] + w_norm = np.linalg.norm(w, axis=0) + w_base_norm = np.linalg.norm(w_base, axis=0) + + dim = w_shp.shape[0] // 3 + u_base = u[keypoints].reshape(-1, 1) + w_shp_base = w_shp[keypoints] + w_exp_base = w_exp[keypoints] + + model_new['w_norm'] = w_norm + model_new['w_base_norm'] = w_base_norm + model_new['dim'] = dim + model_new['u_base'] = u_base + model_new['w_shp_base'] = w_shp_base + model_new['w_exp_base'] = w_exp_base + + _dump(model_path.replace('.mat', '.pkl'), model_new) + return model_new + else: + return _load(model_path) + + +_load_cpu = _load + + +def _numpy_to_tensor(x): + return torch.from_numpy(x) + + +def _tensor_to_numpy(x): + return x.cpu() + + +def _numpy_to_cuda(x): + return _tensor_to_cuda(torch.from_numpy(x)) + + +def _cuda_to_tensor(x): + return x.cpu() + + +def _cuda_to_numpy(x): + return x.cpu().numpy() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/lighting.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/lighting.py new file mode 100644 index 0000000000..1f89d76b52 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/lighting.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import path_helper +import numpy as np +from utils import render +from utils.cython import mesh_core_cython + +__all__ = ['path_helper'] + + +def _norm(arr): + return arr / np.sqrt(np.sum(arr ** 2, axis=1))[:, None] + + +def norm_vertices(vertices): + vertices -= vertices.min(0)[None, :] + vertices /= vertices.max() + vertices *= 2 + vertices -= vertices.max(0)[None, :] / 2 + return vertices + + +def convert_type(obj): + if isinstance(obj, tuple) or isinstance(obj, list): + return np.array(obj, dtype=np.float32)[None, :] + return obj + + +class RenderPipeline(object): + def __init__(self, **kwargs): + self.intensity_ambient = convert_type(kwargs.get('intensity_ambient', 0.3)) + self.intensity_directional = convert_type(kwargs.get('intensity_directional', 0.6)) + self.intensity_specular = convert_type(kwargs.get('intensity_specular', 0.9)) + self.specular_exp = kwargs.get('specular_exp', 5) + self.color_ambient = convert_type(kwargs.get('color_ambient', (1, 1, 1))) + self.color_directional = convert_type(kwargs.get('color_directional', (1, 1, 1))) + self.light_pos = convert_type(kwargs.get('light_pos', (0, 0, 1))) + self.view_pos = convert_type(kwargs.get('view_pos', (0, 0, 1))) + + def update_light_pos(self, light_pos): + self.light_pos = convert_type(light_pos) + + def __call__(self, vertices, triangles, background): + height, width = background.shape[:2] + + # 1. compute triangle/face normals and vertex normals + # ## Old style: very slow + # normal = np.zeros((vertices.shape[0], 3), dtype=np.float32) + # # surface_count = np.zeros((vertices.shape[0], 1)) + # for i in range(triangles.shape[0]): + # i1, i2, i3 = triangles[i, :] + # v1, v2, v3 = vertices[[i1, i2, i3], :] + # surface_normal = np.cross(v2 - v1, v3 - v1) + # normal[[i1, i2, i3], :] += surface_normal + # # surface_count[[i1, i2, i3], :] += 1 + # + # # normal /= surface_count + # # normal /= np.linalg.norm(normal, axis=1, keepdims=True) + # normal = _norm(normal) + + # Cython style + normal = np.zeros((vertices.shape[0], 3), dtype=np.float32) + mesh_core_cython.get_normal(normal, vertices, triangles, vertices.shape[0], triangles.shape[0]) + + # 2. lighting + color = np.zeros_like(vertices, dtype=np.float32) + # ambient component + if self.intensity_ambient > 0: + color += self.intensity_ambient * self.color_ambient + + vertices_n = norm_vertices(vertices.copy()) + if self.intensity_directional > 0: + # diffuse component + direction = _norm(self.light_pos - vertices_n) + cos = np.sum(normal * direction, axis=1)[:, None] + # cos = np.clip(cos, 0, 1) + # todo: check below + color += self.intensity_directional * (self.color_directional * np.clip(cos, 0, 1)) + + # specular component + if self.intensity_specular > 0: + v2v = _norm(self.view_pos - vertices_n) + reflection = 2 * cos * normal - direction + spe = np.sum((v2v * reflection) ** self.specular_exp, axis=1)[:, None] + spe = np.where(cos != 0, np.clip(spe, 0, 1), np.zeros_like(spe)) + color += self.intensity_specular * self.color_directional * np.clip(spe, 0, 1) + color = np.clip(color, 0, 1) + + # 2. rasterization, [0, 1] + render_img = render.crender_colors(vertices, triangles, color, height, width, BG=background) + render_img = (render_img * 255).astype(np.uint8) + return render_img + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/paf.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/paf.py new file mode 100644 index 0000000000..f7c6ee8ca8 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/paf.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import numpy as np +from .ddfa import _parse_param +from .params import u_filter, w_filter, w_exp_filter, std_size, param_mean, param_std + + +def reconstruct_paf_anchor(param, whitening=True): + if whitening: + param = param * param_std + param_mean + p, offset, alpha_shp, alpha_exp = _parse_param(param) + anchor = p @ (u_filter + w_filter @ alpha_shp + w_exp_filter @ alpha_exp).reshape(3, -1, order='F') + offset + anchor[1, :] = std_size + 1 - anchor[1, :] + return anchor[:2, :] + + +def gen_offsets(kernel_size): + offsets = np.zeros((2, kernel_size * kernel_size), dtype=np.int) + ind = 0 + delta = (kernel_size - 1) // 2 + for i in range(kernel_size): + y = i - delta + for j in range(kernel_size): + x = j - delta + offsets[0, ind] = x + offsets[1, ind] = y + ind += 1 + return offsets + + +def gen_img_paf(img_crop, param, kernel_size=3): + """Generate PAF image + img_crop: 120x120 + kernel_size: kernel_size for convolution, should be even number like 3 or 5 or ... + """ + anchor = reconstruct_paf_anchor(param) + anchor = np.round(anchor).astype(np.int) + delta = (kernel_size - 1) // 2 + anchor[anchor < delta] = delta + anchor[anchor >= std_size - delta - 1] = std_size - delta - 1 + + img_paf = np.zeros((64 * kernel_size, 64 * kernel_size, 3), dtype=np.uint8) + offsets = gen_offsets(kernel_size) + for i in range(kernel_size * kernel_size): + ox, oy = offsets[:, i] + index0 = anchor[0] + ox + index1 = anchor[1] + oy + p = img_crop[index1, index0].reshape(64, 64, 3).transpose(1, 0, 2) + + img_paf[oy + delta::kernel_size, ox + delta::kernel_size] = p + + return img_paf + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/params.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/params.py new file mode 100644 index 0000000000..e298bca1f7 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/params.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path as osp +import numpy as np +from .io import _load + + +def make_abs_path(d): + return osp.join(osp.dirname(osp.realpath(__file__)), d) + + +d = make_abs_path('../train.configs') +keypoints = _load(osp.join(d, 'keypoints_sim.npy')) +w_shp = _load(osp.join(d, 'w_shp_sim.npy')) +w_exp = _load(osp.join(d, 'w_exp_sim.npy')) # simplified version +meta = _load(osp.join(d, 'param_whitening.pkl')) +# param_mean and param_std are used for re-whitening +param_mean = meta.get('param_mean') +param_std = meta.get('param_std') +u_shp = _load(osp.join(d, 'u_shp.npy')) +u_exp = _load(osp.join(d, 'u_exp.npy')) +u = u_shp + u_exp +w = np.concatenate((w_shp, w_exp), axis=1) +w_base = w[keypoints] +w_norm = np.linalg.norm(w, axis=0) +w_base_norm = np.linalg.norm(w_base, axis=0) + +# for inference +dim = w_shp.shape[0] // 3 +u_base = u[keypoints].reshape(-1, 1) +w_shp_base = w_shp[keypoints] +w_exp_base = w_exp[keypoints] +std_size = 120 + +# for paf (pac) +paf = _load(osp.join(d, 'Model_PAF.pkl')) +u_filter = paf.get('mu_filter') +w_filter = paf.get('w_filter') +w_exp_filter = paf.get('w_exp_filter') + +# pncc code (mean shape) +pncc_code = _load(osp.join(d, 'pncc_code.npy')) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/path_helper.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/path_helper.py new file mode 100644 index 0000000000..e8a0da08df --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/path_helper.py @@ -0,0 +1,2 @@ +import sys +sys.path.append('../') diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/render.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/render.py new file mode 100644 index 0000000000..a849b9126a --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/utils/render.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +Modified from https://raw.githubusercontent.com/YadiraF/PRNet/master/utils/render.py +""" + +import numpy as np +import cython +from .cython import mesh_core_cython +from .params import pncc_code + +__author__ = 'cleardusk' +__all__ = ['cython'] + + +def is_point_in_tri(point, tri_points): + ''' Judge whether the point is in the triangle + Method: + http://blackpawn.com/texts/pointinpoly/ + Args: + point: [u, v] or [x, y] + tri_points: three vertices(2d points) of a triangle. 2 coords x 3 vertices + Returns: + bool: true for in triangle + ''' + tp = tri_points + + # vectors + v0 = tp[:, 2] - tp[:, 0] + v1 = tp[:, 1] - tp[:, 0] + v2 = point - tp[:, 0] + + # dot products + dot00 = np.dot(v0.T, v0) + dot01 = np.dot(v0.T, v1) + dot02 = np.dot(v0.T, v2) + dot11 = np.dot(v1.T, v1) + dot12 = np.dot(v1.T, v2) + + # barycentric coordinates + if dot00 * dot11 - dot01 * dot01 == 0: + inverDeno = 0 + else: + inverDeno = 1 / (dot00 * dot11 - dot01 * dot01) + + u = (dot11 * dot02 - dot01 * dot12) * inverDeno + v = (dot00 * dot12 - dot01 * dot02) * inverDeno + + # check if point in triangle + return (u >= 0) & (v >= 0) & (u + v < 1) + + +def render_colors(vertices, colors, tri, h, w, c=3): + """ render mesh by z buffer + Args: + vertices: 3 x nver + colors: 3 x nver + tri: 3 x ntri + h: height + w: width + """ + # initial + image = np.zeros((h, w, c)) + + depth_buffer = np.zeros([h, w]) - 999999. + # triangle depth: approximate the depth to the average value of z in each vertex(v0, v1, v2), since the vertices + # are closed to each other + tri_depth = (vertices[2, tri[0, :]] + vertices[2, tri[1, :]] + vertices[2, tri[2, :]]) / 3. + tri_tex = (colors[:, tri[0, :]] + colors[:, tri[1, :]] + colors[:, tri[2, :]]) / 3. + + for i in range(tri.shape[1]): + tri_idx = tri[:, i] # 3 vertex indices + + # the inner bounding box + umin = max(int(np.ceil(np.min(vertices[0, tri_idx]))), 0) + umax = min(int(np.floor(np.max(vertices[0, tri_idx]))), w - 1) + + vmin = max(int(np.ceil(np.min(vertices[1, tri_idx]))), 0) + vmax = min(int(np.floor(np.max(vertices[1, tri_idx]))), h - 1) + + if umax < umin or vmax < vmin: + continue + + for u in range(umin, umax + 1): + for v in range(vmin, vmax + 1): + if tri_depth[i] > depth_buffer[v, u] and is_point_in_tri([u, v], vertices[:2, tri_idx]): + depth_buffer[v, u] = tri_depth[i] + image[v, u, :] = tri_tex[:, i] + return image + + +def get_depths_image(img, vertices_lst, tri): + h, w = img.shape[:2] + c = 1 + + depths_img = np.zeros((h, w, c)) + for i in range(len(vertices_lst)): + vertices = vertices_lst[i] + + z = vertices[2, :] + z_min, z_max = min(z), max(z) + vertices[2, :] = (z - z_min) / (z_max - z_min) + + z = vertices[2:, :] + depth_img = render_colors(vertices.T, z.T, tri.T, h, w, 1) + depths_img[depth_img > 0] = depth_img[depth_img > 0] + + depths_img = depths_img.squeeze() * 255 + return depths_img + + +def crender_colors(vertices, triangles, colors, h, w, c=3, BG=None): + """ render mesh with colors + Args: + vertices: [nver, 3] + triangles: [ntri, 3] + colors: [nver, 3] + h: height + w: width + c: channel + BG: background image + Returns: + image: [h, w, c]. rendered image./rendering. + """ + + if BG is None: + image = np.zeros((h, w, c), dtype=np.float32) + else: + assert BG.shape[0] == h and BG.shape[1] == w and BG.shape[2] == c + image = BG.astype(np.float32).copy(order='C') + depth_buffer = np.zeros([h, w], dtype=np.float32, order='C') - 999999. + + # to C order + vertices = vertices.astype(np.float32).copy(order='C') + triangles = triangles.astype(np.int32).copy(order='C') + colors = colors.astype(np.float32).copy(order='C') + + mesh_core_cython.render_colors_core( + image, vertices, triangles, + colors, + depth_buffer, + vertices.shape[0], triangles.shape[0], + h, w, c + ) + return image + + +def cget_depths_image(img, vertices_lst, tri): + """cython version for depth image render""" + h, w = img.shape[:2] + c = 1 + + depths_img = np.zeros((h, w, c)) + for i in range(len(vertices_lst)): + vertices = vertices_lst[i] + + z = vertices[2, :] + z_min, z_max = min(z), max(z) + vertices[2, :] = (z - z_min) / (z_max - z_min) + z = vertices[2:, :] + + depth_img = crender_colors(vertices.T, tri.T, z.T, h, w, 1) + depths_img[depth_img > 0] = depth_img[depth_img > 0] + + depths_img = depths_img.squeeze() * 255 + return depths_img + + +def ncc(vertices): + # simple version + # ncc_vertices = np.zeros_like(vertices) + # x = vertices[0, :] + # y = vertices[1, :] + # z = vertices[2, :] + # + # ncc_vertices[0, :] = (x - min(x)) / (max(x) - min(x)) + # ncc_vertices[1, :] = (y - min(y)) / (max(y) - min(y)) + # ncc_vertices[2, :] = (z - min(z)) / (max(z) - min(z)) + + # matrix version + v_min = np.min(vertices, axis=1).reshape(-1, 1) + v_max = np.max(vertices, axis=1).reshape(-1, 1) + ncc_vertices = (vertices - v_min) / (v_max - v_min) + + return ncc_vertices + + +def cpncc(img, vertices_lst, tri): + """cython version for PNCC render: original paper""" + h, w = img.shape[:2] + c = 3 + + pnccs_img = np.zeros((h, w, c)) + for i in range(len(vertices_lst)): + vertices = vertices_lst[i] + pncc_img = crender_colors(vertices.T, tri.T, pncc_code.T, h, w, c) + pnccs_img[pncc_img > 0] = pncc_img[pncc_img > 0] + + pnccs_img = pnccs_img.squeeze() * 255 + return pnccs_img + + +def cpncc_v2(img, vertices_lst, tri): + """cython version for PNCC render""" + h, w = img.shape[:2] + c = 3 + + pnccs_img = np.zeros((h, w, c)) + for i in range(len(vertices_lst)): + vertices = vertices_lst[i] + ncc_vertices = ncc(vertices) + pncc_img = crender_colors(vertices.T, tri.T, ncc_vertices.T, h, w, c) + pnccs_img[pncc_img > 0] = pncc_img[pncc_img > 0] + + pnccs_img = pnccs_img.squeeze() * 255 + return pnccs_img + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/readme.md b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/readme.md new file mode 100644 index 0000000000..560c319af6 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/readme.md @@ -0,0 +1,3 @@ + `render_demo.m` is a simple matlab demo to render 3D face mesh. + +`tri.mat` provides the 3D mesh triangle indices. diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_demo.m b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_demo.m new file mode 100644 index 0000000000..25f8f0281f --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_demo.m @@ -0,0 +1,10 @@ +tri = load('tri.mat'); +vertex = load('image00427'); + +tri = tri.tri; +vertex = vertex.vertex; +render_face_mesh(vertex, tri); + +A = getframe(gcf); +mimg = A.cdata; +imwrite(mimg, 'demo.jpg', 'quality', 95); diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_face_mesh.m b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_face_mesh.m new file mode 100644 index 0000000000..2285ca2489 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/render_face_mesh.m @@ -0,0 +1,18 @@ +function render_face_mesh(vertex, tri) + trisurf(tri', vertex(1, :), vertex(2, :), vertex(3, :), ones(size(vertex, 2),1), 'edgecolor', 'none'); + + re=[1 1 1]; + colormap(re); + + light('Position', [0 0 1], 'Style', 'infinite'); + lighting gouraud + axis equal + view([0 90]); + + xlabel('x'); + ylabel('y'); + zlabel('z'); + + axis on; + grid on; +end diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/tri.mat b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/tri.mat new file mode 100644 index 0000000000..a09de19c98 Binary files /dev/null and b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/DDFA/visualize/tri.mat differ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/LICENSE b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/LICENSE new file mode 100644 index 0000000000..a6d7fd364b --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/LICENSE @@ -0,0 +1,384 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + +b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + +c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + +d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + +e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + +f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + +g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + +h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + +i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + +j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + +k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + +Section 2 -- Scope. + +a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + +a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + +b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + +a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + +b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + +c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + +Section 6 -- Term and Termination. + +a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + +Section 7 -- Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + +Section 8 -- Interpretation. + +a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + +c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + +d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the "Licensor." Except for the limited purpose of indicating +that material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/__init__.py new file mode 100644 index 0000000000..c5503ba361 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/__init__.py @@ -0,0 +1,150 @@ +import importlib +import torch.utils.data +from .base_dataset import BaseDataset +import math +from torch.utils.data.sampler import Sampler + + +class dataset_info(): + def __init__(self): + self.prefix = [ + './algorithm/DDFA/example/Images', + 'PREFIX-TO-YOUR-DATASET' + ] + self.file_list = [ + './algorithm/DDFA/example/file_list.txt', + 'YOUE-FILE-LIST.txt' + ] + + self.land_mark_list = [ + './algorithm/DDFA/example/realign_lmk', + 'LANDMARKS-OF-FACES-IN-YOUR-DATASET' + ] + + self.params_dir = [ + './algorithm/DDFA/results', + '3DFITTING-RESULTS-HOME-DIR' + ] + self.dataset_names = {'example': 0, 'YOUR-DATASET': 1} + self.folder_level = [1, 2] + + def get_dataset(self, opt): + dataset = opt.dataset.split(',') + dataset_list = [self.dataset_names[dataset[i].lower()] for i in range(len(dataset))] + + return dataset_list + + +def find_dataset_using_name(dataset_name): + # Given the option --dataset [datasetname], + # the file "datasets/datasetname_dataset.py" + # will be imported. + dataset_filename = "algorithm.Rotate_and_Render.data." + dataset_name + "_dataset" + datasetlib = importlib.import_module(dataset_filename) + + # In the file, the class called DatasetNameDataset() will + # be instantiated. It has to be a subclass of BaseDataset, + # and it is case-insensitive. + dataset = None + target_dataset_name = dataset_name.replace('_', '') + 'dataset' + for name, cls in datasetlib.__dict__.items(): + if name.lower() == target_dataset_name.lower() \ + and issubclass(cls, BaseDataset): + dataset = cls + + if dataset is None: + raise ValueError("In %s.py, there should be a subclass of BaseDataset " + "with class name that matches %s in lowercase." % + (dataset_filename, target_dataset_name)) + + return dataset + + +def get_option_setter(dataset_name): + dataset_class = find_dataset_using_name(dataset_name) + return dataset_class.modify_commandline_options + + +def create_dataloader(opt): + dataset = find_dataset_using_name(opt.dataset_mode) + instance = dataset() + instance.initialize(opt) + print("dataset [%s] of size %d was created" % + (type(instance).__name__, len(instance))) + dataloader = torch.utils.data.DataLoader( + instance, + batch_size=opt.batchSize, + shuffle=not opt.serial_batches, + num_workers=int(opt.nThreads), + drop_last=opt.isTrain + ) + return dataloader + + +class MySampler(Sampler): + + def __init__(self, opt, dataset, render_thread=None, rank=None, round_up=True): + self.dataset = dataset + self.opt = opt + self.render_thread = render_thread + self.rank = rank + self.round_up = round_up + self.epoch = 0 + + self.common_num = self.opt.batchSize * self.render_thread + if self.round_up: + self.total_size = int(math.ceil(len(self.dataset) * 1.0 / self.common_num)) * self.common_num + else: + self.total_size = len(self.dataset) + self.num_samples = int(math.ceil(self.total_size / self.render_thread)) + + def __iter__(self): + # deterministically shuffle based on epoch + g = torch.Generator() + g.manual_seed(self.epoch) + if self.opt.isTrain: + indices = list(torch.randperm(len(self.dataset), generator=g)) + else: + indices = list(torch.arange(len(self.dataset))) + + # add extra samples to make it evenly divisible + if self.round_up: + indices += indices[:(self.total_size - len(indices))] + assert len(indices) == self.total_size, 'indices {} != total_size {}'.format(len(indices), self.total_size) + + # subsample + # offset = self.num_samples * self.rank + # indices = indices[offset:offset + self.num_samples] + indices = indices[self.rank::self.render_thread] + if self.round_up or (not self.round_up and self.rank == 0): + assert len(indices) == self.num_samples + + return iter(indices) + + def __len__(self): + return self.num_samples + + def set_epoch(self, epoch): + self.epoch = epoch + + +def create_dataloader_test(opt): + dataset = find_dataset_using_name(opt.dataset_mode) + instance = dataset() + instance.initialize(opt) + print("dataset [%s] of size %d was created" % + (type(instance).__name__, len(instance))) + samplers = [MySampler(opt, instance, render_thread=opt.render_thread, rank=i, round_up=opt.isTrain) for i in + range(opt.render_thread)] + dataloaders = [ + torch.utils.data.DataLoader( + instance, + batch_size=opt.batchSize, + shuffle=False, + num_workers=int(opt.nThreads), + sampler=samplers[i], + drop_last=opt.isTrain, + ) + for i in range(opt.render_thread) + ] + return dataloaders diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/allface_dataset.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/allface_dataset.py new file mode 100644 index 0000000000..dfbbce280b --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/allface_dataset.py @@ -0,0 +1,165 @@ +import os +import math +import numpy as np +import skimage.transform as trans +import cv2 +import torch +from algorithm.Rotate_and_Render.data import dataset_info +from algorithm.Rotate_and_Render.data.base_dataset import BaseDataset + +dataset_info = dataset_info() + + +class AllFaceDataset(BaseDataset): + @staticmethod + def modify_commandline_options(parser, is_train): + parser.add_argument('--no_pairing_check', action='store_true', + help='If specified, skip sanity check of correct label-image file pairing') + return parser + + def cv2_loader(self, img_str): + img_array = np.frombuffer(img_str, dtype=np.uint8) + return cv2.imdecode(img_array, cv2.IMREAD_COLOR) + + def fill_list(self, tmp_list): + length = len(tmp_list) + if length % self.opt.batchSize != 0: + end = math.ceil(length / self.opt.batchSize) * self.opt.batchSize + tmp_list = tmp_list + tmp_list[-1 * (end - length):] + return tmp_list + + def initialize(self, opt): + self.opt = opt + dataset_num = dataset_info.get_dataset(opt) + self.prefix = [dataset_info.prefix[num] for num in dataset_num] + + file_list = [dataset_info.file_list[num] for num in dataset_num] + + land_mark_list = [dataset_info.land_mark_list[num] for num in dataset_num] + + self.params_dir = [dataset_info.params_dir[num] for num in dataset_num] + + self.folder_level = [dataset_info.folder_level[num] for num in dataset_num] + + self.num_datasets = len(file_list) + assert len(land_mark_list) == self.num_datasets, \ + 'num of landmk dir should be the num of datasets' + + assert len(self.params_dir) == self.num_datasets, \ + 'num of params_dir should be the num of datasets' + + self.dataset_lists = [] + self.landmark_paths = [] + self.sizes = [] + + for n in range(self.num_datasets): + with open(file_list[n]) as f: + img_lists = f.readlines() + img_lists = self.fill_list(img_lists) + self.sizes.append(len(img_lists)) + self.dataset_lists.append(sorted(img_lists)) + + with open(land_mark_list[n]) as f: + landmarks = f.readlines() + landmarks = self.fill_list(landmarks) + self.landmark_paths.append(sorted(landmarks)) + + self.dataset_size = min(self.sizes) + self.initialized = False + + def get_landmarks(self, landmark, img_list): + + landmark_split = landmark.strip().split(' ') + filename1_without_ext = os.path.basename(img_list.strip()) + filename2_without_ext = os.path.basename(landmark_split[0]) + assert (filename1_without_ext == filename2_without_ext), \ + "The image_path %s and params_path %s don't match." % \ + (img_list, landmark_split[0]) + + label = landmark_split[1] + landmarks = landmark_split[2:] + landmarks = list(map(float, landmarks)) + landmarks_array = np.array(landmarks).reshape(5, 2) + return landmarks_array, label + + def get_param_file(self, img_list, dataset_num): + img_name = os.path.splitext(img_list)[0] + name_split = img_name.split("/") + + folder_level = self.folder_level[dataset_num] + param_folder = os.path.join(self.params_dir[dataset_num], + "/".join([name_split[i] for i in + range(len(name_split) - folder_level, len(name_split))]) + ".txt") + # params = np.loadtxt(param_folder) + return param_folder + + def paths_match(self, path1, path2): + filename1_without_ext = os.path.splitext(os.path.basename(path1)[-10:])[0] + filename2_without_ext = os.path.splitext(os.path.basename(path2)[-10:])[0] + return filename1_without_ext == filename2_without_ext + + def affine_align(self, img, landmark=None, **kwargs): + M = None + h, w, c = img.shape + src = np.array([ + [38.2946, 51.6963], + [73.5318, 51.5014], + [56.0252, 71.7366], + [41.5493, 92.3655], + [70.7299, 92.2041]], dtype=np.float32) + src = src * 290 / 112 + src[:, 0] += 50 + src[:, 1] += 60 + src = src / 400 * self.opt.crop_size + dst = landmark + # dst = landmark.astype(np.float32) + tform = trans.SimilarityTransform() + tform.estimate(dst, src) + M = tform.params[0:2, :] + warped = cv2.warpAffine(img, M, (self.opt.crop_size, self.opt.crop_size), borderValue=0.0) + return warped, M + + def __getitem__(self, index): + # Label Image + + # randnum = np.random.randint(sum(self.sizes)) + dataset_num = np.random.randint(self.num_datasets) + + image_path = self.dataset_lists[dataset_num][index].strip() + image_path = os.path.join(self.prefix[dataset_num], image_path) + + img = cv2.imread(image_path) + if img is None: + raise Exception('None Image') + + param_path = self.get_param_file(image_path, dataset_num) + + # img = cv2.imread(image_path) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + M = None + landmark_path = self.landmark_paths[dataset_num][index].strip() + landmarks, label = self.get_landmarks(landmark_path, image_path) + wrapped_img, M = self.affine_align(img, landmarks) + M = torch.from_numpy(M).float() + + wrapped_img = wrapped_img.transpose(2, 0, 1) / 255.0 + + wrapped_img = torch.from_numpy(wrapped_img).float() + + input_dict = { + 'image': wrapped_img, + 'param_path': param_path, + 'M': M, + 'path': image_path + } + + # Give subclasses a chance to modify the final output + self.postprocess(input_dict) + + return input_dict + + def postprocess(self, input_dict): + return input_dict + + def __len__(self): + return self.dataset_size diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/base_dataset.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/base_dataset.py new file mode 100644 index 0000000000..b4bb726d96 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/base_dataset.py @@ -0,0 +1,123 @@ +import torch.utils.data as data +from PIL import Image +import torchvision.transforms as transforms +import numpy as np +import random + + +class BaseDataset(data.Dataset): + def __init__(self): + super(BaseDataset, self).__init__() + + @staticmethod + def modify_commandline_options(parser, is_train): + return parser + + def initialize(self, opt): + pass + + +def get_params(opt, size): + w, h = size + new_h = h + new_w = w + if opt.preprocess_mode == 'resize_and_crop': + new_h = new_w = opt.load_size + elif opt.preprocess_mode == 'scale_width_and_crop': + new_w = opt.load_size + new_h = opt.load_size * h // w + elif opt.preprocess_mode == 'scale_shortside_and_crop': + ss, ls = min(w, h), max(w, h) # shortside and longside + width_is_shorter = w == ss + ls = int(opt.load_size * ls / ss) + new_w, new_h = (ss, ls) if width_is_shorter else (ls, ss) + + x = random.randint(0, np.maximum(0, new_w - opt.crop_size)) + y = random.randint(0, np.maximum(0, new_h - opt.crop_size)) + + flip = random.random() > 0.5 + return {'crop_pos': (x, y), 'flip': flip} + + +def get_transform(opt, params, method=Image.BICUBIC, normalize=True, toTensor=True): + transform_list = [] + if 'resize' in opt.preprocess_mode: + osize = [opt.load_size, opt.load_size] + transform_list.append(transforms.Resize(osize, interpolation=method)) + elif 'scale_width' in opt.preprocess_mode: + transform_list.append(transforms.Lambda(lambda img: __scale_width(img, opt.load_size, method))) + elif 'scale_shortside' in opt.preprocess_mode: + transform_list.append(transforms.Lambda(lambda img: __scale_shortside(img, opt.load_size, method))) + + if 'crop' in opt.preprocess_mode: + transform_list.append(transforms.Lambda(lambda img: __crop(img, params['crop_pos'], opt.crop_size))) + + if opt.preprocess_mode == 'none': + base = 32 + transform_list.append(transforms.Lambda(lambda img: __make_power_2(img, base, method))) + + if opt.preprocess_mode == 'fixed': + w = opt.crop_size + h = round(opt.crop_size / opt.aspect_ratio) + transform_list.append(transforms.Lambda(lambda img: __resize(img, w, h, method))) + + if opt.isTrain and not opt.no_flip: + transform_list.append(transforms.Lambda(lambda img: __flip(img, params['flip']))) + + if toTensor: + transform_list += [transforms.ToTensor()] + + if normalize: + transform_list += [transforms.Normalize((0.5, 0.5, 0.5), + (0.5, 0.5, 0.5))] + return transforms.Compose(transform_list) + + +def normalize(): + return transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) + + +def __resize(img, w, h, method=Image.BICUBIC): + return img.resize((w, h), method) + + +def __make_power_2(img, base, method=Image.BICUBIC): + ow, oh = img.size + h = int(round(oh / base) * base) + w = int(round(ow / base) * base) + if (h == oh) and (w == ow): + return img + return img.resize((w, h), method) + + +def __scale_width(img, target_width, method=Image.BICUBIC): + ow, oh = img.size + if (ow == target_width): + return img + w = target_width + h = int(target_width * oh / ow) + return img.resize((w, h), method) + + +def __scale_shortside(img, target_width, method=Image.BICUBIC): + ow, oh = img.size + ss, ls = min(ow, oh), max(ow, oh) # shortside and longside + width_is_shorter = ow == ss + if (ss == target_width): + return img + ls = int(target_width * ls / ss) + nw, nh = (ss, ls) if width_is_shorter else (ls, ss) + return img.resize((nw, nh), method) + + +def __crop(img, pos, size): + ow, oh = img.size + x1, y1 = pos + tw = th = size + return img.crop((x1, y1, x1 + tw, y1 + th)) + + +def __flip(img, flip): + if flip: + return img.transpose(Image.FLIP_LEFT_RIGHT) + return img diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/curve.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/curve.py new file mode 100644 index 0000000000..a116ed426e --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/curve.py @@ -0,0 +1,250 @@ +import numpy as np +import cv2 +import math +from numpy import linalg as LA + + +def distance(p1, p2): + return math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])) + + +def curve_interp(src, samples, index): + assert (src.shape[0] > 2) + assert (samples >= 2) + + src_1 = src[0:src.shape[0] - 1, :] + src_2 = src[1:src.shape[0], :] + src_delta = src_1 - src_2 + length = np.sqrt(src_delta[:, 0] ** 2 + src_delta[:, 1] ** 2) + assert (length.shape[0] == src.shape[0] - 1) + + accu_length = np.zeros((src.shape[0])) + for i in range(1, accu_length.shape[0]): + accu_length[i] = accu_length[i - 1] + length[i - 1] + dst = np.zeros((samples, 2)) + pre_raw = 0 + + step_interp = accu_length[accu_length.shape[0] - 1] / float(samples - 1) + dst[0, :] = src[0, :] + dst[dst.shape[0] - 1, :] = src[src.shape[0] - 1, :] + for i in range(1, samples - 1): + covered_interp = step_interp * i + while (covered_interp > accu_length[pre_raw + 1]): + pre_raw += 1 + assert (pre_raw < accu_length.shape[0] - 1) + dx = (covered_interp - accu_length[pre_raw]) / length[pre_raw] + dst[i, :] = src[pre_raw, :] * (1.0 - dx) + src[pre_raw + 1, :] * dx + + return dst + + +def curve_fitting(points, samples, index): + num_points = points.shape[0] + assert (num_points > 1) + valid_points = [points[0]] + for i in range(1, num_points): + if (distance(points[i, :], points[i - 1, :]) > 0.001): + valid_points.append(points[i, :]) + assert (len(valid_points) > 1) + valid_points = np.asarray(valid_points) + functions = np.zeros((valid_points.shape[0] - 1, 9)) + + if valid_points.shape[0] == 2: + functions[0, 0] = LA.norm(valid_points[0, :] - valid_points[1, :]) + functions[0, 1] = valid_points[0, 0] + functions[0, 2] = (valid_points[1, 0] - valid_points[0, 0]) / functions[0, 0] + functions[0, 3] = 0 + functions[0, 4] = 0 + functions[0, 5] = valid_points[0, 1] + functions[0, 6] = (valid_points[1, 1] - valid_points[0, 1]) / functions[0, 0] + functions[0, 7] = 0 + functions[0, 8] = 0 + else: + Mx = np.zeros((valid_points.shape[0])) + My = np.zeros((valid_points.shape[0])) + A = np.zeros((valid_points.shape[0] - 2)) + B = np.zeros((valid_points.shape[0] - 2)) + C = np.zeros((valid_points.shape[0] - 2)) + Dx = np.zeros((valid_points.shape[0] - 2)) + Dy = np.zeros((valid_points.shape[0] - 2)) + for i in range(functions.shape[0]): + functions[i, 0] = LA.norm(valid_points[i, :] - valid_points[i + 1, :]) + for i in range(A.shape[0]): + A[i] = functions[i, 0] + B[i] = 2.0 * (functions[i, 0] + functions[i + 1, 0]) + C[i] = functions[i + 1, 0] + Dx[i] = 6.0 * ((valid_points[i + 2, 0] - valid_points[i + 1, 0]) / functions[i + 1, 0] - ( + valid_points[i + 1, 0] - valid_points[i, 0]) / functions[i, 0]) + Dy[i] = 6.0 * ((valid_points[i + 2, 1] - valid_points[i + 1, 1]) / functions[i + 1, 0] - ( + valid_points[i + 1, 1] - valid_points[i, 1]) / functions[i, 0]) + + C[0] = C[0] / B[0] + Dx[0] = Dx[0] / B[0] + Dy[0] = Dy[0] / B[0] + for i in range(1, A.shape[0]): + tmp = B[i] - A[i] * C[i - 1] + C[i] = C[i] / tmp + Dx[i] = (Dx[i] - A[i] * Dx[i - 1]) / tmp + Dy[i] = (Dy[i] - A[i] * Dy[i - 1]) / tmp + Mx[valid_points.shape[0] - 2] = Dx[valid_points.shape[0] - 3] + My[valid_points.shape[0] - 2] = Dy[valid_points.shape[0] - 3] + for i in range(valid_points.shape[0] - 4, -1, -1): + Mx[i + 1] = Dx[i] - C[i] * Mx[i + 2] + My[i + 1] = Dy[i] - C[i] * My[i + 2] + Mx[0] = 0 + Mx[valid_points.shape[0] - 1] = 0 + My[0] = 0 + My[valid_points.shape[0] - 1] = 0 + + for i in range(functions.shape[0]): + functions[i, 1] = valid_points[i, 0] + functions[i, 2] = (valid_points[i + 1, 0] - valid_points[i, 0]) / functions[i, 0] - ( + 2.0 * functions[i, 0] * Mx[i] + functions[i, 0] * Mx[i + 1]) / 6.0 + functions[i, 3] = Mx[i] / 2.0 + functions[i, 4] = (Mx[i + 1] - Mx[i]) / (6.0 * functions[i, 0]) + functions[i, 5] = valid_points[i, 1] + functions[i, 6] = (valid_points[i + 1, 1] - valid_points[i, 1]) / functions[i, 0] - ( + 2.0 * functions[i, 0] * My[i] + functions[i, 0] * My[i + 1]) / 6.0 + functions[i, 7] = My[i] / 2.0 + functions[i, 8] = (My[i + 1] - My[i]) / (6.0 * functions[i, 0]) + + samples_per_segment = samples * 1 / functions.shape[0] + 1 + samples_per_segment = int(samples_per_segment) + + rawcurve = np.zeros((functions.shape[0] * samples_per_segment, 2)) + for i in range(functions.shape[0]): + step = functions[i, 0] / samples_per_segment + for j in range(samples_per_segment): + t = step * j + rawcurve[i * samples_per_segment + j, :] = np.asarray( + [functions[i, 1] + functions[i, 2] * t + functions[i, 3] * t * t + functions[i, 4] * t * t * t, + functions[i, 5] + functions[i, 6] * t + functions[i, 7] * t * t + functions[i, 8] * t * t * t]) + + curve_tmp = curve_interp(rawcurve, samples, index) + + return curve_tmp + + +def points_to_heatmap_68points(points, heatmap_num, heatmap_size, sigma): + align_on_curve = [0] * heatmap_num + curves = [0] * heatmap_num + + align_on_curve[0] = np.zeros((3, 2)) # contour + align_on_curve[1] = np.zeros((5, 2)) # left eyebrow + align_on_curve[2] = np.zeros((5, 2)) # right eyebrow + align_on_curve[3] = np.zeros((4, 2)) # nose bridge + align_on_curve[4] = np.zeros((5, 2)) # nose tip + align_on_curve[5] = np.zeros((4, 2)) # left top eye + align_on_curve[6] = np.zeros((4, 2)) # left bottom eye + align_on_curve[7] = np.zeros((4, 2)) # right top eye + align_on_curve[8] = np.zeros((4, 2)) # right bottom eye + align_on_curve[9] = np.zeros((7, 2)) # up up lip + align_on_curve[10] = np.zeros((5, 2)) # up bottom lip + align_on_curve[11] = np.zeros((5, 2)) # bottom up lip + align_on_curve[12] = np.zeros((7, 2)) # bottom bottom lip + + for i in range(3): + align_on_curve[0][i] = points[7 + i] + + for i in range(5): + align_on_curve[1][i] = points[i + 17] + + for i in range(5): + align_on_curve[2][i] = points[i + 22] + + for i in range(4): + align_on_curve[3][i] = points[i + 27] + + for i in range(5): + align_on_curve[4][i] = points[i + 31] + + for i in range(4): + align_on_curve[5][i] = points[i + 36] + + align_on_curve[6][0] = points[36] + align_on_curve[6][1] = points[41] + align_on_curve[6][2] = points[40] + align_on_curve[6][3] = points[39] + + align_on_curve[7][0] = points[42] + align_on_curve[7][1] = points[43] + align_on_curve[7][2] = points[44] + align_on_curve[7][3] = points[45] + + align_on_curve[8][0] = points[42] + align_on_curve[8][1] = points[47] + align_on_curve[8][2] = points[46] + align_on_curve[8][3] = points[45] + + for i in range(7): + align_on_curve[9][i] = points[i + 48] + + for i in range(5): + align_on_curve[10][i] = points[i + 60] + + align_on_curve[11][0] = points[60] + align_on_curve[11][1] = points[67] + align_on_curve[11][2] = points[66] + align_on_curve[11][3] = points[65] + align_on_curve[11][4] = points[64] + + align_on_curve[12][0] = points[48] + align_on_curve[12][1] = points[59] + align_on_curve[12][2] = points[58] + align_on_curve[12][3] = points[57] + align_on_curve[12][4] = points[56] + align_on_curve[12][5] = points[55] + align_on_curve[12][6] = points[54] + + heatmap = np.zeros((heatmap_size, heatmap_size, heatmap_num)) + for i in range(heatmap_num): + curve_map = np.full((heatmap_size, heatmap_size), 255, dtype=np.uint8) + + valid_points = [align_on_curve[i][0, :]] + for j in range(1, align_on_curve[i].shape[0]): + if (distance(align_on_curve[i][j, :], align_on_curve[i][j - 1, :]) > 0.001): + valid_points.append(align_on_curve[i][j, :]) + + if len(valid_points) > 1: + curves[i] = curve_fitting(align_on_curve[i], align_on_curve[i].shape[0] * 10, i) + for j in range(curves[i].shape[0]): + if (int(curves[i][j, 0] + 0.5) >= 0 and int(curves[i][j, 0] + 0.5) < heatmap_size and + int(curves[i][j, 1] + 0.5) >= 0 and int(curves[i][j, 1] + 0.5) < heatmap_size): + curve_map[int(curves[i][j, 1] + 0.5), int(curves[i][j, 0] + 0.5)] = 0 + + # distance transform + image_dis = cv2.distanceTransform(curve_map, cv2.DIST_L2, cv2.DIST_MASK_PRECISE) + + # gaussian map generation + image_dis = image_dis.astype(np.float64) + image_gaussian = (1.0 / (2.0 * np.pi * (sigma ** 2))) * np.exp(-1.0 * image_dis ** 2 / (2.0 * sigma ** 2)) + image_gaussian = np.where(image_dis < (3.0 * sigma), image_gaussian, 0) + + # normalised to [0,1] + maxVal = image_gaussian.max() + minVal = image_gaussian.min() + + if maxVal == minVal: + image_gaussian = 0 + else: + image_gaussian = (image_gaussian - minVal) / (maxVal - minVal) + + heatmap[:, :, i] = image_gaussian + + return heatmap + + +def combine_map(heatmap, use_edge=True, no_guassian=False): + left_eye = (heatmap[:, :, 5] + heatmap[:, :, 6]).clip(0, 1) + right_eye = (heatmap[:, :, 7] + heatmap[:, :, 8]).clip(0, 1) + nose = (heatmap[:, :, 3] + heatmap[:, :, 4]).clip(0, 1) + mouth = (heatmap[:, :, 9] + heatmap[:, :, 10] + + heatmap[:, :, 11] + heatmap[:, :, 12]).clip(0, 1) + if use_edge: + edge = heatmap[:, :, 0] + else: + edge = np.zeros_like(heatmap[:, :, 0]) + label_map = np.stack([left_eye, right_eye, nose, mouth, edge], 0) + if no_guassian: + label_map = (label_map > 0).astype(float) + return label_map diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/data_utils.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/data_utils.py new file mode 100644 index 0000000000..cd0cb777ba --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/data/data_utils.py @@ -0,0 +1,183 @@ +import traceback +from torch.multiprocessing import Process +import numpy as np + +import os +import torch + + +def get_input(data, render): + real_image = data['image'] + input_semantics, rotated_mesh, orig_landmarks, rotate_landmarks, rendered_images_erode, original_angles, \ + Rd_a, rendered_images_rotate_artifacts = render.rotate_render(data['param_path'], real_image, data['M']) + output = {} + real_image = real_image * 2 - 1 + input_semantics = input_semantics * 2 - 1 + rotated_mesh = rotated_mesh * 2 - 1 + rendered_images_erode = rendered_images_erode * 2 - 1 + Rd_a = Rd_a * 2 - 1 + rendered_images_rotate_artifacts = rendered_images_rotate_artifacts * 2 - 1 + output['image'] = real_image.cpu() + output['rendered_images_erode'] = rendered_images_erode.cpu() + output['mesh'] = input_semantics.cpu() + output['rotated_mesh'] = rotated_mesh.cpu() + output['Rd_a'] = Rd_a.cpu() + output['orig_landmarks'] = orig_landmarks.cpu() + output['rotated_landmarks'] = rotate_landmarks.cpu() + output['original_angles'] = original_angles.cpu() + output['rendered_images_rotate_artifacts'] = rendered_images_rotate_artifacts.cpu() + output['path'] = data['path'] + return output + + +def get_test_input(data, render): + real_image = data['image'] + rotated_mesh, rotate_landmarks, original_angles \ + = render.rotate_render(data['param_path'], real_image, data['M']) + output = {} + real_image = real_image * 2 - 1 + rotated_mesh = rotated_mesh * 2 - 1 + output['image'] = real_image.cpu() + output['rotated_mesh'] = rotated_mesh.cpu() + output['rotated_landmarks'] = rotate_landmarks.cpu() + output['original_angles'] = original_angles.cpu() + output['path'] = data['path'] + return output + + +def get_multipose_test_input(data, render, yaw_poses, pitch_poses): + real_image = data['image'] + # num_poses = len(yaw_poses) + len(pitch_poses) + rotated_meshs = [] + rotated_landmarks_list = [] + original_angles_list = [] + rotated_landmarks_list_106 = [] + paths = [] + real_images = [] + pose_list = [] + for i in range(2): + prefix = 'yaw' if i == 0 else 'pitch' + poses = yaw_poses if i == 0 else pitch_poses + for pose in poses: + if i == 0: + rotated_mesh, rotate_landmarks, original_angles, rotate_landmarks_106 \ + = render.rotate_render(data['param_path'], real_image, data['M'], yaw_pose=pose) + else: + rotated_mesh, rotate_landmarks, original_angles, rotate_landmarks_106 \ + = render.rotate_render(data['param_path'], real_image, data['M'], pitch_pose=pose) + rotated_meshs.append(rotated_mesh) + rotated_landmarks_list.append(rotate_landmarks) + rotated_landmarks_list_106.append(rotate_landmarks_106) + original_angles_list.append(original_angles) + paths += data['path'] + pose_list += ['{}_{}'.format(prefix, pose) for i in range(len(data['path']))] + real_images.append(real_image) + rotated_meshs = torch.cat(rotated_meshs, 0) + rotated_landmarks_list = torch.cat(rotated_landmarks_list, 0) + rotated_landmarks_list_106 = torch.cat(rotated_landmarks_list_106, 0) + original_angles_list = torch.cat(original_angles_list, 0) + output = {} + real_image = real_image * 2 - 1 + rotated_meshs = rotated_meshs * 2 - 1 + output['image'] = real_image.cpu() + output['rotated_mesh'] = rotated_meshs.cpu() + output['rotated_landmarks'] = rotated_landmarks_list.cpu() + output['rotated_landmarks_106'] = rotated_landmarks_list_106.cpu() + output['original_angles'] = original_angles_list.cpu() + output['path'] = paths + output['pose_list'] = pose_list + return output + + +class data_prefetcher(): + def __init__(self, loader, opt, render_layer): + self.loader = iter(loader) + self.stream = torch.cuda.Stream() + self.opt = opt + self.render_layer = render_layer + self.preload() + + def preload(self): + try: + data = next(self.loader) + except StopIteration: + self.next_input = None + return + if self.opt.isTrain: + self.next_input = get_input(data, self.render_layer) + elif self.opt.yaw_poses is None and self.opt.pitch_poses is None: + self.next_input = get_test_input(data, self.render_layer) + else: + if self.opt.yaw_poses is not None: + if self.opt.posesrandom: + self.opt.yaw_poses = [round(np.random.uniform(-0.5, 0.5, 1)[0], 2) for k in + range(len(self.opt.yaw_poses))] + else: + self.opt.yaw_poses = [] + + if self.opt.pitch_poses is not None: + if self.opt.posesrandom: + self.opt.pitch_poses = [round(np.random.uniform(-0.5, 0.5, 1)[0], 2) for k in + range(len(self.opt.pitch_poses))] + else: + self.opt.pitch_poses = [] + + self.next_input = get_multipose_test_input(data, self.render_layer, self.opt.yaw_poses, + self.opt.pitch_poses) + with torch.cuda.stream(self.stream): + for k, v in self.next_input.items(): + if type(v) == torch.Tensor: + self.next_input[k] = v.cuda(non_blocking=True) + + def next(self): + torch.cuda.current_stream().wait_stream(self.stream) + input = self.next_input + + if input is not None: + for k in input.keys(): + if type(input[k]) == torch.Tensor: + input[k].record_stream(torch.cuda.current_stream()) + self.preload() + return input + + +def prefetch_data(queue, dataloader, iter_counter, opt, render_layer): + print("start prefetching data...") + np.random.seed(os.getpid()) + for epoch in iter_counter.training_epochs(): + prefetcher = data_prefetcher(dataloader, opt, render_layer) + input = prefetcher.next() + while input is not None: + try: + queue.put(input) + except Exception as e: + traceback.print_exc() + raise e + input = prefetcher.next() + + +def pin_memory(data_queue, pinned_data_queue, sema): + while True: + data = data_queue.get() + + for k, v in data.items(): + data[k] = v.pin_memory() + + pinned_data_queue.put(data) + + if sema.acquire(blocking=False): + return + + +def init_parallel_jobs(queue, dataloader, iter_counter, opt, render_layer): + if isinstance(dataloader, list): + tasks = [Process(target=prefetch_data, args=(queue, dataloader[i], iter_counter, opt, render_layer[i])) for i in + range(opt.render_thread)] + else: + tasks = [Process(target=prefetch_data, args=(queue, dataloader, iter_counter, opt, render_layer)) for i in + range(opt.render_thread)] + # task.daemon = True + for task in tasks: + task.start() + + return tasks diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/test.sh b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/test.sh new file mode 100644 index 0000000000..fccbb2d378 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/test.sh @@ -0,0 +1,24 @@ +python3 -u test_frontal.py \ + --names rs_ijba3 \ + --dataset megafaceprobe \ + --list_start 0 \ + --list_end 5000 \ + --dataset_mode single \ + --gpu_ids 0,1,2,3,4,5,6,7 \ + --netG rotatespade \ + --norm_G spectralsyncbatch \ + --batchSize 18 \ + --model rotatespade \ + --label_nc 5 \ + --nThreads 3 \ + --heatmap_size 2.5 \ + --chunk_size 40 40\ + --no_gaussian_landmark \ + --multi_gpu \ + --device_count 8\ + --render_thread 6 \ + --label_mask \ + --align \ + #--use_BG \ + #--chunk_size 2 4 4 4 4 4\ + diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/train.sh b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/train.sh new file mode 100644 index 0000000000..2c75e612d7 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/train.sh @@ -0,0 +1,32 @@ +python3 -u train.py \ + --name rotate \ + --dataset_mode allface \ + --load_size 400 \ + --crop_size 256 \ + --netG rotatespade \ + --trainer rotatespade \ + --norm_D spectralsyncbatch \ + --norm_G spectralsyncbatch \ + --model rotatespade \ + --dataset 'example' \ + --gpu_ids 0 \ + --lambda_D 0.75 \ + --lambda_rotate_D 0.001 \ + --D_input concat \ + --netD multiscale \ + --label_nc 5 \ + --nThreads 3 \ + --no_html \ + --display_freq 100 \ + --print_freq 100 \ + --load_separately \ + --heatmap_size 2.5 \ + --device_count 2 \ + --render_thread 1 \ + --chunk_size 1 \ + --no_gaussian_landmark \ + --landmark_align \ + --erode_kernel 19 \ + --pose_noise \ + # --G_pretrain_path ./checkpoints/rs_model/latest_net_G.pth \ + # --D_pretrain_path ./checkpoints/rs_model/latest_net_D.pth \ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/v100_test.sh b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/v100_test.sh new file mode 100644 index 0000000000..944871a061 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/experiments/v100_test.sh @@ -0,0 +1,24 @@ +python3 -u test_multipose.py \ + --names rs_model \ + --dataset example \ + --list_start 0 \ + --list_end 10 \ + --dataset_mode allface \ + --gpu_ids 0 \ + --netG rotatespade \ + --norm_G spectralsyncbatch \ + --model rotatespade \ + --label_nc 5 \ + --nThreads 8 \ + --heatmap_size 1\ + --chunk_size 1 \ + --no_gaussian_landmark \ + --multi_gpu \ + --device_count 2 \ + --render_thread 1 \ + --label_mask \ + --align \ + --erode_kernel 21 \ + --yaw_poses 0 5 10 15 20 25 30 35 40.5 45 50 55 60 \ + --pitch_poses 0 5 10 15 20 25 30 35 40.5 45 \ + diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/__init__.py new file mode 100644 index 0000000000..62c236c018 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/__init__.py @@ -0,0 +1,40 @@ +import importlib +import torch +__all__ = ['torch'] + + +def find_model_using_name(model_name): + # Given the option --model [modelname], + # the file "models/modelname_model.py" + # will be imported. + model_filename = "algorithm.Rotate_and_Render.models." + model_name + "_model" + modellib = importlib.import_module(model_filename) + + # In the file, the class called ModelNameModel() will + # be instantiated. It has to be a subclass of torch.nn.Module, + # and it is case-insensitive. + model = None + target_model_name = model_name.replace('_', '') + 'model' + for name, cls in modellib.__dict__.items(): + if name.lower() == target_model_name.lower(): + model = cls + + if model is None: + print("In %s.py, there should be a subclass of torch.nn.Module with \ + class name that matches %s in lowercase." % (model_filename, target_model_name)) + exit(0) + + return model + + +def get_option_setter(model_name): + model_class = find_model_using_name(model_name) + return model_class.modify_commandline_options + + +def create_model(opt): + model = find_model_using_name(opt.model) + instance = model(opt) + print("model [%s] was created" % (type(instance).__name__)) + + return instance diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/__init__.py new file mode 100644 index 0000000000..91e0febc81 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/__init__.py @@ -0,0 +1,60 @@ +import torch +from algorithm.Rotate_and_Render.models.networks.base_network import BaseNetwork +from algorithm.Rotate_and_Render.models.networks import loss +from algorithm.Rotate_and_Render.models.networks import discriminator +from algorithm.Rotate_and_Render.models.networks import generator +from algorithm.Rotate_and_Render.models.networks import encoder +from algorithm.Rotate_and_Render.models.networks.render import Render +import algorithm.Rotate_and_Render.util.util as util +__all__ = ['loss', 'discriminator', 'generator', 'encoder', 'Render'] + + +def find_network_using_name(target_network_name, filename): + target_class_name = target_network_name + filename + module_name = 'algorithm.Rotate_and_Render.models.networks.' + filename + network = util.find_class_in_module(target_class_name, module_name) + + assert issubclass(network, BaseNetwork), \ + "Class %s should be a subclass of BaseNetwork" % network + + return network + + +def modify_commandline_options(parser, is_train): + opt, _ = parser.parse_known_args() + + netG_cls = find_network_using_name(opt.netG, 'generator') + parser = netG_cls.modify_commandline_options(parser, is_train) + if is_train: + netD_cls = find_network_using_name(opt.netD, 'discriminator') + parser = netD_cls.modify_commandline_options(parser, is_train) + netE_cls = find_network_using_name('conv', 'encoder') + parser = netE_cls.modify_commandline_options(parser, is_train) + + return parser + + +def create_network(cls, opt): + net = cls(opt) + net.print_network() + if len(opt.gpu_ids) > 0: + assert(torch.cuda.is_available()) + net.cuda() + net.init_weights(opt.init_type, opt.init_variance) + return net + + +def define_G(opt): + netG_cls = find_network_using_name(opt.netG, 'generator') + return create_network(netG_cls, opt) + + +def define_D(opt): + netD_cls = find_network_using_name(opt.netD, 'discriminator') + return create_network(netD_cls, opt) + + +def define_E(opt): + # there exists only one encoder type + netE_cls = find_network_using_name('conv', 'encoder') + return create_network(netE_cls, opt) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/architecture.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/architecture.py new file mode 100644 index 0000000000..123004ef52 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/architecture.py @@ -0,0 +1,199 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision +import torch.nn.utils.spectral_norm as spectral_norm +from .normalization import SPADE +from ...util import util + + +# ResNet block that uses SPADE. +# It differs from the ResNet block of pix2pixHD in that +# it takes in the segmentation map as input, learns the skip connection if necessary, +# and applies normalization first and then convolution. +# This architecture seemed like a standard architecture for unconditional or +# class-conditional GAN architecture using residual block. +# The code was inspired from https://github.com/LMescheder/GAN_stability. +class SPADEResnetBlock(nn.Module): + def __init__(self, fin, fout, opt): + super().__init__() + # Attributes + self.learned_shortcut = (fin != fout) + fmiddle = min(fin, fout) + + # create conv layers + self.conv_0 = nn.Conv2d(fin, fmiddle, kernel_size=3, padding=1) + self.conv_1 = nn.Conv2d(fmiddle, fout, kernel_size=3, padding=1) + if self.learned_shortcut: + self.conv_s = nn.Conv2d(fin, fout, kernel_size=1, bias=False) + + # apply spectral norm if specified + if 'spectral' in opt.norm_G: + self.conv_0 = spectral_norm(self.conv_0) + self.conv_1 = spectral_norm(self.conv_1) + if self.learned_shortcut: + self.conv_s = spectral_norm(self.conv_s) + + # define normalization layers + spade_config_str = opt.norm_G.replace('spectral', '') + self.norm_0 = SPADE(spade_config_str, fmiddle, opt.semantic_nc) + self.norm_1 = SPADE(spade_config_str, fout, opt.semantic_nc) + if self.learned_shortcut: + self.norm_s = SPADE(spade_config_str, fout, opt.semantic_nc) + + # note the resnet block with SPADE also takes in |seg|, + # the semantic segmentation map as input + def _forward(self, x, seg): + x_s = self.shortcut(x, seg) + + dx = self.conv_0(self.actvn(self.norm_0(x, seg))) + dx = self.conv_1(self.actvn(self.norm_1(dx, seg))) + + out = x_s + dx + + return out + + def forward(self, x, seg): + if self.learned_shortcut: + x_s = self.norm_s(self.conv_s(x), seg) + else: + x_s = x + dx = self.actvn(self.norm_0(self.conv_0(x), seg)) + dx = self.actvn(self.norm_1(self.conv_1(dx), seg)) + + out = x_s + dx + return out + + def shortcut(self, x, seg): + if self.learned_shortcut: + x_s = self.conv_s(self.norm_s(x, seg)) + else: + x_s = x + return x_s + + def actvn(self, x): + return F.leaky_relu(x, 2e-1) + + +# try to put SPADE into pix2pixHD middle layers +class ResnetSPADEBlock(nn.Module): + def __init__(self, dim, semantic_nc, kernel_size=3): + super().__init__() + norm_G = 'spectralspadesyncbatch3x3' + pw = (kernel_size - 1) // 2 + self.conv_0 = nn.Conv2d(dim, dim, kernel_size=kernel_size) + self.conv_1 = nn.Conv2d(dim, dim, kernel_size=kernel_size) + self.padding = nn.ReflectionPad2d(pw) + if 'spectral' in norm_G: + self.add_module('conv_block1', spectral_norm(self.conv_0)) + self.add_module('conv_block4', spectral_norm(self.conv_1)) + + # define normalization layers + spade_config_str = norm_G.replace('spectral', '') + self.norm_0 = SPADE(spade_config_str, dim, semantic_nc) + self.norm_1 = SPADE(spade_config_str, dim, semantic_nc) + + def forward(self, x, seg): + dx = self.padding(x) + dx = self.activation(self.norm_0(self.conv_0(dx), seg)) + dx = self.padding(dx) + dx = self.activation(self.norm_1(self.conv_1(dx), seg)) + out = x + dx + + return out + + def activation(self, x): + return F.leaky_relu(x, 2e-1) + + +# ResNet block used in pix2pixHD +# We keep the same architecture as pix2pixHD. +class ResnetBlock(nn.Module): + def __init__(self, dim, norm_layer, activation=nn.ReLU(False), kernel_size=3): + super().__init__() + + pw = (kernel_size - 1) // 2 + self.conv_block = nn.Sequential( + nn.ReflectionPad2d(pw), + norm_layer(nn.Conv2d(dim, dim, kernel_size=kernel_size)), + activation, + nn.ReflectionPad2d(pw), + norm_layer(nn.Conv2d(dim, dim, kernel_size=kernel_size)), + # add an activation + activation, + ) + + def forward(self, x): + y = self.conv_block(x) + out = x + y + return out + + +# VGG architecter, used for the perceptual loss using a pretrained VGG network +class VGG19(torch.nn.Module): + def __init__(self, requires_grad=False): + super(VGG19, self).__init__() + vgg_pretrained_features = torchvision.models.vgg19(pretrained=True).features + self.slice1 = torch.nn.Sequential() + self.slice2 = torch.nn.Sequential() + self.slice3 = torch.nn.Sequential() + self.slice4 = torch.nn.Sequential() + self.slice5 = torch.nn.Sequential() + for x in range(2): + self.slice1.add_module(str(x), vgg_pretrained_features[x]) + for x in range(2, 7): + self.slice2.add_module(str(x), vgg_pretrained_features[x]) + for x in range(7, 12): + self.slice3.add_module(str(x), vgg_pretrained_features[x]) + for x in range(12, 21): + self.slice4.add_module(str(x), vgg_pretrained_features[x]) + for x in range(21, 30): + self.slice5.add_module(str(x), vgg_pretrained_features[x]) + if not requires_grad: + for param in self.parameters(): + param.requires_grad = False + + def forward(self, X): + h_relu1 = self.slice1(X) + h_relu2 = self.slice2(h_relu1) + h_relu3 = self.slice3(h_relu2) + h_relu4 = self.slice4(h_relu3) + h_relu5 = self.slice5(h_relu4) + out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5] + return out + + +class VGGFace19(torch.nn.Module): + def __init__(self, opt, requires_grad=False): + super(VGGFace19, self).__init__() + model = torchvision.models.vgg19_bn(pretrained=False) + ckpt = torch.load(opt.vggface_checkpoint)['state_dict'] + util.copy_state_dict(ckpt, model, 'module.base.') + vgg_pretrained_features = model.features + self.slice1 = torch.nn.Sequential() + self.slice2 = torch.nn.Sequential() + self.slice3 = torch.nn.Sequential() + self.slice4 = torch.nn.Sequential() + self.slice5 = torch.nn.Sequential() + for x in range(2): + self.slice1.add_module(str(x), vgg_pretrained_features[x]) + for x in range(2, 7): + self.slice2.add_module(str(x), vgg_pretrained_features[x]) + for x in range(7, 12): + self.slice3.add_module(str(x), vgg_pretrained_features[x]) + for x in range(12, 21): + self.slice4.add_module(str(x), vgg_pretrained_features[x]) + for x in range(21, 30): + self.slice5.add_module(str(x), vgg_pretrained_features[x]) + if not requires_grad: + for param in self.parameters(): + param.requires_grad = False + + def forward(self, X): + h_relu1 = self.slice1(X) + h_relu2 = self.slice2(h_relu1) + h_relu3 = self.slice3(h_relu2) + h_relu4 = self.slice4(h_relu3) + h_relu5 = self.slice5(h_relu4) + out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5] + return out diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/base_network.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/base_network.py new file mode 100644 index 0000000000..2eecf7d67c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/base_network.py @@ -0,0 +1,54 @@ +import torch.nn as nn +from torch.nn import init + + +class BaseNetwork(nn.Module): + def __init__(self): + super(BaseNetwork, self).__init__() + + @staticmethod + def modify_commandline_options(parser, is_train): + return parser + + def print_network(self): + if isinstance(self, list): + self = self[0] + num_params = 0 + for param in self.parameters(): + num_params += param.numel() + print('Network [%s] was created. Total number of parameters: %.1f million. ' + 'To see the architecture, do print(network).' + % (type(self).__name__, num_params / 1000000)) + + def init_weights(self, init_type='normal', gain=0.02): + def init_func(m): + classname = m.__class__.__name__ + if classname.find('BatchNorm2d') != -1: + if hasattr(m, 'weight') and m.weight is not None: + init.normal_(m.weight.data, 1.0, gain) + if hasattr(m, 'bias') and m.bias is not None: + init.constant_(m.bias.data, 0.0) + elif hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'xavier_uniform': + init.xavier_uniform_(m.weight.data, gain=1.0) + elif init_type == 'kaiming': + init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + init.orthogonal_(m.weight.data, gain=gain) + elif init_type == 'none': # uses pytorch's default init method + m.reset_parameters() + else: + raise NotImplementedError('initialization method [%s] is not implemented' % init_type) + if hasattr(m, 'bias') and m.bias is not None: + init.constant_(m.bias.data, 0.0) + + self.apply(init_func) + + # propagate to children + for m in self.children(): + if hasattr(m, 'init_weights'): + m.init_weights(init_type, gain) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/discriminator.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/discriminator.py new file mode 100644 index 0000000000..28dbb5baa7 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/discriminator.py @@ -0,0 +1,308 @@ +import torch.nn as nn +import numpy as np +import torch.nn.utils.spectral_norm as spectral_norm +import torch.nn.functional as F +from .base_network import BaseNetwork +from .sync_batchnorm import SynchronizedBatchNorm2d +from .normalization import get_nonspade_norm_layer +from ...util import util +import torch +from torch.utils.checkpoint import checkpoint + + +class MultiscaleDiscriminator(BaseNetwork): + @staticmethod + def modify_commandline_options(parser, is_train): + parser.add_argument('--netD_subarch', type=str, default='n_layer', + help='architecture of each discriminator') + parser.add_argument('--num_D', type=int, default=2, + help='number of discriminators to be used in multiscale') + opt, _ = parser.parse_known_args() + + # define properties of each discriminator of the multiscale discriminator + subnetD = util.find_class_in_module(opt.netD_subarch + 'discriminator', + 'models.networks.discriminator') + subnetD.modify_commandline_options(parser, is_train) + + return parser + + def __init__(self, opt): + super(MultiscaleDiscriminator, self).__init__() + self.opt = opt + + for i in range(opt.num_D): + subnetD = self.create_single_discriminator(opt) + self.add_module('discriminator_%d' % i, subnetD) + + def create_single_discriminator(self, opt): + subarch = opt.netD_subarch + if subarch == 'n_layer': + netD = NLayerDiscriminator(opt) + else: + raise ValueError('unrecognized discriminator subarchitecture %s' % subarch) + return netD + + def downsample(self, input): + return F.avg_pool2d(input, kernel_size=3, + stride=2, padding=[1, 1], + count_include_pad=False) + + # Returns list of lists of discriminator outputs. + # The final result is of size opt.num_D x opt.n_layers_D + def forward(self, input): + result = [] + get_intermediate_features = not self.opt.no_ganFeat_loss + for name, D in self.named_children(): + out = D(input) + if not get_intermediate_features: + out = [out] + result.append(out) + input = self.downsample(input) + + return result + + +# Defines the PatchGAN discriminator with the specified arguments. +class NLayerDiscriminator(BaseNetwork): + @staticmethod + def modify_commandline_options(parser, is_train): + parser.add_argument('--n_layers_D', type=int, default=4, + help='# layers in each discriminator') + return parser + + def __init__(self, opt): + + super(NLayerDiscriminator, self).__init__() + self.opt = opt + + kw = 4 + padw = int(np.ceil((kw - 1.0) / 2)) + nf = opt.ndf + input_nc = self.compute_D_input_nc(opt) + + norm_layer = get_nonspade_norm_layer(opt, opt.norm_D) + sequence = [[nn.Conv2d(input_nc, nf, kernel_size=kw, stride=2, padding=padw), + nn.LeakyReLU(0.2, False)]] + + for n in range(1, opt.n_layers_D): + nf_prev = nf + nf = min(nf * 2, 512) + stride = 1 if n == opt.n_layers_D - 1 else 2 + sequence += [[norm_layer(nn.Conv2d(nf_prev, nf, kernel_size=kw, + stride=stride, padding=padw)), + nn.LeakyReLU(0.2, False) + ]] + + sequence += [[nn.Conv2d(nf, 1, kernel_size=kw, stride=1, padding=padw)]] + + # We divide the layers into groups to extract intermediate layer outputs + for n in range(len(sequence)): + self.add_module('model' + str(n), nn.Sequential(*sequence[n])) + + def compute_D_input_nc(self, opt): + if opt.D_input == "concat": + input_nc = opt.label_nc + opt.output_nc + if opt.contain_dontcare_label: + input_nc += 1 + if not opt.no_instance: + input_nc += 1 + else: + input_nc = 3 + return input_nc + + def forward(self, input): + results = [input] + for submodel in self.children(): + + # intermediate_output = checkpoint(submodel, results[-1]) + intermediate_output = submodel(results[-1]) + results.append(intermediate_output) + + get_intermediate_features = not self.opt.no_ganFeat_loss + if get_intermediate_features: + return results[1:] + else: + return results[-1] + + +class ImageDiscriminator(BaseNetwork): + """Defines a PatchGAN discriminator""" + def modify_commandline_options(parser, is_train): + parser.add_argument('--n_layers_D', type=int, default=4, + help='# layers in each discriminator') + return parser + + def __init__(self, opt, n_layers=3, norm_layer=nn.BatchNorm2d): + """Construct a PatchGAN discriminator + Parameters: + input_nc (int) -- the number of channels in input images + ndf (int) -- the number of filters in the last conv layer + n_layers (int) -- the number of conv layers in the discriminator + norm_layer -- normalization layer + """ + super(ImageDiscriminator, self).__init__() + use_bias = norm_layer == nn.InstanceNorm2d + if opt.D_input == "concat": + input_nc = opt.label_nc + opt.output_nc + else: + input_nc = opt.label_nc + ndf = 64 + kw = 4 + padw = 1 + sequence = [nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True)] + nf_mult = 1 + nf_mult_prev = 1 + for n in range(1, n_layers): # gradually increase the number of filters + nf_mult_prev = nf_mult + nf_mult = min(2 ** n, 8) + sequence += [ + nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias), + norm_layer(ndf * nf_mult), + nn.LeakyReLU(0.2, True) + ] + + nf_mult_prev = nf_mult + nf_mult = min(2 ** n_layers, 8) + sequence += [ + nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias), + norm_layer(ndf * nf_mult), + nn.LeakyReLU(0.2, True) + ] + + sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)] # output 1 channel prediction map + self.model = nn.Sequential(*sequence) + + def forward(self, input): + """Standard forward.""" + return self.model(input) + + +class ProjectionDiscriminator(BaseNetwork): + @staticmethod + def modify_commandline_options(parser, is_train): + parser.add_argument('--n_layers_D', type=int, default=4, + help='# layers in each discriminator') + return parser + + def __init__(self, opt): + super().__init__() + self.opt = opt + nf = opt.ndf + input_nc = 3 + label_nc = opt.label_nc + (1 if opt.contain_dontcare_label else 0) + (0 if opt.no_instance else 1) + norm_layer = get_nonspade_norm_layer(opt, opt.norm_D) + + if opt.norm_D.startswith('spectral'): + use_spectral = True + else: + use_spectral = False + + self.enc1 = nn.Sequential(norm_layer(nn.Conv2d(input_nc, nf, kernel_size=3, stride=2, padding=1)), + nn.LeakyReLU(0.2, True)) + + self.relu = nn.LeakyReLU(0.2, True) + for i in range(2, 6): + nf_prev = nf + nf = min(nf * 2, opt.ndf * 8) + enconv = nn.Conv2d(nf_prev, nf, kernel_size=3, stride=2, padding=1) + latconv = nn.Conv2d(nf, opt.ndf * 4, kernel_size=3, stride=2, padding=1) + if use_spectral: + enconv = spectral_norm(enconv) + latconv = spectral_norm(latconv) + + self.add_module('enc' + str(i), enconv) + self.add_module('lat' + str(i), latconv) + self.add_module('norm_enc' + str(i), self.get_norm(enconv)) + self.add_module('norm_lat' + str(i), self.get_norm(latconv)) + + self.up = nn.Upsample(scale_factor=2, mode='bilinear') + + for i in range(2, 5): + finalconv = nn.Conv2d(opt.ndf * 4, opt.ndf, kernel_size=3, padding=1) + if use_spectral: + finalconv = spectral_norm(finalconv) + self.add_module('final' + str(i), finalconv) + self.add_module('norm_final' + str(i), self.get_norm(finalconv)) + + # shared True/False layer + self.tf = nn.Conv2d(opt.ndf, 1, kernel_size=1) + self.seg = nn.Conv2d(opt.ndf, opt.ndf, kernel_size=1) # do not need softmax + self.embedding = nn.Conv2d(label_nc, opt.ndf, kernel_size=1) + + def forward(self, input, segmap): + # feat11 = self.enc1(input) + feat11 = checkpoint(self.enc1, input) + feat12 = self.relu(self.norm_enc2(self.enc2(feat11))) + feat13 = self.relu(self.norm_enc3(self.enc3(feat12))) + feat14 = self.relu(self.norm_enc4(self.enc4(feat13))) + feat15 = self.relu(self.norm_enc5(self.enc5(feat14))) + feat25 = self.relu(self.norm_lat5(self.lat5(feat15))) + feat24 = self.up(feat25) + self.relu(self.norm_lat4(self.lat4(feat14))) + feat23 = self.up(feat24) + self.relu(self.norm_lat3(self.lat3(feat13))) + feat22 = self.up(feat23) + self.relu(self.norm_lat2(self.lat2(feat12))) + feat32 = self.norm_final2(self.final2(feat22)) + feat33 = self.norm_final3(self.final3(feat23)) + feat34 = self.norm_final4(self.final4(feat24)) + + pred2 = self.tf(feat32) + pred3 = self.tf(feat33) + pred4 = self.tf(feat34) + + seg2 = self.seg(feat32) + seg3 = self.seg(feat33) + seg4 = self.seg(feat34) + + if self.opt.gan_matching_feats == 'basic': + feats = [feat12, feat13, feat14, feat15] + elif self.opt.gan_matching_feats == 'more': + feats = [feat12, feat13, feat14, feat15, feat25, feat24, feat23, feat22] + elif self.opt.gan_matching_feats == 'chosen': + feats = [feat11, feat12, feat13, feat14, feat15] + else: + feats = [feat12, feat13, feat14, feat15, feat25, feat24, feat23, feat22, feat32, feat33, feat34] + + # calculate segmentation loss + # segmentation map embedding + segemb = self.embedding(segmap) + # downsample + segemb2 = F.adaptive_avg_pool2d(segemb, seg2.size(-1)) + segemb3 = F.adaptive_avg_pool2d(segemb, seg3.size(-1)) + segemb4 = F.adaptive_avg_pool2d(segemb, seg4.size(-1)) + + # product + pred2 += torch.mul(segemb2, seg2).sum(dim=1, keepdim=True) + pred3 += torch.mul(segemb3, seg3).sum(dim=1, keepdim=True) + pred4 += torch.mul(segemb4, seg4).sum(dim=1, keepdim=True) + + results = [pred2, pred3, pred4] + + return feats, results + + def get_out_channel(self, layer): + if hasattr(layer, 'out_channels'): + return getattr(layer, 'out_channels') + return layer.weight.size(0) + + # this function will be returned + def get_norm(self, layer): + norm_type = self.opt.norm_D + if norm_type.startswith('spectral'): + subnorm_type = norm_type[len('spectral'):] + else: + subnorm_type = norm_type + + # remove bias in the previous layer, which is meaningless + # since it has no effect after normalization + if getattr(layer, 'bias', None) is not None: + delattr(layer, 'bias') + layer.register_parameter('bias', None) + if subnorm_type == 'batch': + norm_layer = nn.BatchNorm2d(self.get_out_channel(layer), affine=True) + elif subnorm_type == 'syncbatch': + norm_layer = SynchronizedBatchNorm2d(self.get_out_channel(layer), affine=True) + elif subnorm_type == 'instance': + norm_layer = nn.InstanceNorm2d(self.get_out_channel(layer), affine=False) + else: + raise ValueError('normalization layer %s is not recognized' % subnorm_type) + + return norm_layer diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/encoder.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/encoder.py new file mode 100644 index 0000000000..a3e52242c8 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/encoder.py @@ -0,0 +1,50 @@ +import torch.nn as nn +import numpy as np +import torch.nn.functional as F +from .base_network import BaseNetwork +from .normalization import get_nonspade_norm_layer + + +class ConvEncoder(BaseNetwork): + """ Same architecture as the image discriminator """ + + def __init__(self, opt): + super().__init__() + + kw = 3 + pw = int(np.ceil((kw - 1.0) / 2)) + ndf = opt.ngf + norm_layer = get_nonspade_norm_layer(opt, opt.norm_E) + self.layer1 = norm_layer(nn.Conv2d(3, ndf, kw, stride=2, padding=pw)) + self.layer2 = norm_layer(nn.Conv2d(ndf * 1, ndf * 2, kw, stride=2, padding=pw)) + self.layer3 = norm_layer(nn.Conv2d(ndf * 2, ndf * 4, kw, stride=2, padding=pw)) + self.layer4 = norm_layer(nn.Conv2d(ndf * 4, ndf * 8, kw, stride=2, padding=pw)) + self.layer5 = norm_layer(nn.Conv2d(ndf * 8, ndf * 8, kw, stride=2, padding=pw)) + if opt.crop_size >= 256: + self.layer6 = norm_layer(nn.Conv2d(ndf * 8, ndf * 8, kw, stride=2, padding=pw)) + + self.so = s0 = 4 + self.fc_mu = nn.Linear(ndf * 8 * s0 * s0, 256) + self.fc_var = nn.Linear(ndf * 8 * s0 * s0, 256) + + self.actvn = nn.LeakyReLU(0.2, False) + self.opt = opt + + def forward(self, x): + if x.size(2) != 256 or x.size(3) != 256: + x = F.interpolate(x, size=(256, 256), mode='bilinear') + + x = self.layer1(x) + x = self.layer2(self.actvn(x)) + x = self.layer3(self.actvn(x)) + x = self.layer4(self.actvn(x)) + x = self.layer5(self.actvn(x)) + if self.opt.crop_size >= 256: + x = self.layer6(self.actvn(x)) + x = self.actvn(x) + + x = x.view(x.size(0), -1) + mu = self.fc_mu(x) + logvar = self.fc_var(x) + + return mu, logvar diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/generator.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/generator.py new file mode 100644 index 0000000000..ca3356c3b4 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/generator.py @@ -0,0 +1,126 @@ +import torch.nn as nn +from .base_network import BaseNetwork +from .normalization import get_nonspade_norm_layer +from .architecture import ResnetBlock as ResnetBlock +from .architecture import ResnetSPADEBlock +from torch.utils.checkpoint import checkpoint + + +class Interpolate(nn.Module): + def __init__(self, scale_factor=2, size=None, mode='bilinear'): + super(Interpolate, self).__init__() + self.interp = nn.functional.interpolate + self.size = size + self.scale_factor = scale_factor + self.mode = mode + + def forward(self, x): + if self.size is not None: + x = self.interp(x, size=self.size, mode=self.mode, align_corners=False) + else: + x = self.interp(x, scale_factor=self.scale_factor, mode=self.mode, align_corners=False) + return x + + +class RotateGenerator(BaseNetwork): + @staticmethod + def modify_commandline_options(parser, is_train): + parser.add_argument('--resnet_n_downsample', type=int, default=4, + help='number of downsampling layers in netG') + parser.add_argument('--resnet_n_blocks', type=int, default=9, + help='number of residual blocks in the global generator network') + parser.add_argument('--resnet_kernel_size', type=int, default=3, + help='kernel size of the resnet block') + parser.add_argument('--resnet_initial_kernel_size', type=int, default=7, + help='kernel size of the first convolution') + parser.set_defaults(norm_G='spectralsyncbatch') + return parser + + def __init__(self, opt): + super(RotateGenerator, self).__init__() + input_nc = 3 + + norm_layer = get_nonspade_norm_layer(opt, opt.norm_G) + activation = nn.ReLU(False) + # initial conv + self.first_layer = nn.Sequential(nn.ReflectionPad2d(opt.resnet_initial_kernel_size // 2), + norm_layer(nn.Conv2d(input_nc, opt.ngf, + kernel_size=opt.resnet_initial_kernel_size, + padding=0)), + activation) + # downsample + downsample_model = [] + + mult = 1 + for i in range(opt.resnet_n_downsample): + downsample_model += [norm_layer(nn.Conv2d(opt.ngf * mult, opt.ngf * mult * 2, + kernel_size=3, stride=2, padding=1)), + activation] + mult *= 2 + + self.downsample_layers = nn.Sequential(*downsample_model) + + # resnet blocks + resnet_model = [] + + for i in range(opt.resnet_n_blocks): + resnet_model += [ResnetBlock(opt.ngf * mult, + norm_layer=norm_layer, + activation=activation, + kernel_size=opt.resnet_kernel_size)] + + self.resnet_layers = nn.Sequential(*resnet_model) + + # upsample + + upsample_model = [] + + for i in range(opt.resnet_n_downsample): + nc_in = int(opt.ngf * mult) + nc_out = int((opt.ngf * mult) / 2) + upsample_model += [norm_layer(nn.ConvTranspose2d(nc_in, nc_out, + kernel_size=3, stride=2, + padding=1, output_padding=1)), + activation] + mult = mult // 2 + + self.upsample_layers = nn.Sequential(*upsample_model) + + # final output conv + self.final_layer = nn.Sequential(nn.ReflectionPad2d(3), + nn.Conv2d(nc_out, opt.output_nc, kernel_size=7, padding=0), + nn.Tanh()) + + def forward(self, input, z=None): + net = self.first_layer(input) + net = self.downsample_layers(net) + net = self.resnet_layers(net) + net = self.upsample_layers(net) + net = self.final_layer(net) + return net + + +class RotateSPADEGenerator(RotateGenerator): + def __init__(self, opt): + super(RotateSPADEGenerator, self).__init__(opt) + del self.resnet_layers + self.resnet_n_blocks = opt.resnet_n_blocks + mult = 1 + for i in range(opt.resnet_n_downsample): + mult *= 2 + for i in range(opt.resnet_n_blocks): + self.add_module('resnet_layers' + str(i), ResnetSPADEBlock(opt.ngf * mult, opt.semantic_nc)) + + def forward(self, input, seg=None): + # net = self.first_layer(input) + net = checkpoint(self.first_layer, input) + # net = self.downsample_layers(net) + net = checkpoint(self.downsample_layers, net) + for i in range(self.resnet_n_blocks): + # net = self._modules['resnet_layers' + str(i)](net, seg) + net = checkpoint(self._modules['resnet_layers' + str(i)], net, seg) + # net = self.upsample_layers(net) + net = checkpoint(self.upsample_layers, net) + # net = self.final_layer(net) + net = checkpoint(self.final_layer, net) + return net diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/loss.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/loss.py new file mode 100644 index 0000000000..17f0506e0c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/loss.py @@ -0,0 +1,188 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from .architecture import VGG19, VGGFace19 + + +# Defines the GAN loss which uses either LSGAN or the regular GAN. +# When LSGAN is used, it is basically same as MSELoss, +# but it abstracts away the need to create the target label tensor +# that has the same size as the input +class GANLoss(nn.Module): + def __init__(self, gan_mode, target_real_label=1.0, target_fake_label=0.0, + tensor=torch.FloatTensor, opt=None): + super(GANLoss, self).__init__() + self.real_label = target_real_label + self.fake_label = target_fake_label + self.real_label_tensor = None + self.fake_label_tensor = None + self.zero_tensor = None + self.Tensor = tensor + self.gan_mode = gan_mode + self.opt = opt + if gan_mode == 'ls': + pass + elif gan_mode == 'original': + pass + elif gan_mode == 'w': + pass + elif gan_mode == 'hinge': + pass + else: + raise ValueError('Unexpected gan_mode {}'.format(gan_mode)) + + def get_target_tensor(self, input, target_is_real): + if target_is_real: + if self.real_label_tensor is None: + self.real_label_tensor = self.Tensor(1).fill_(self.real_label) + self.real_label_tensor.requires_grad_(False) + return self.real_label_tensor.expand_as(input) + else: + if self.fake_label_tensor is None: + self.fake_label_tensor = self.Tensor(1).fill_(self.fake_label) + self.fake_label_tensor.requires_grad_(False) + return self.fake_label_tensor.expand_as(input) + + def get_zero_tensor(self, input): + if self.zero_tensor is None: + self.zero_tensor = self.Tensor(1).fill_(0) + self.zero_tensor.requires_grad_(False) + return self.zero_tensor.expand_as(input) + + def loss(self, input, target_is_real, for_discriminator=True): + if self.gan_mode == 'original': # cross entropy loss + target_tensor = self.get_target_tensor(input, target_is_real) + loss = F.binary_cross_entropy_with_logits(input, target_tensor) + return loss + elif self.gan_mode == 'ls': + target_tensor = self.get_target_tensor(input, target_is_real) + return F.mse_loss(input, target_tensor) + elif self.gan_mode == 'hinge': + if for_discriminator: + if target_is_real: + minval = torch.min(input - 1, self.get_zero_tensor(input)) + loss = -torch.mean(minval) + else: + minval = torch.min(-input - 1, self.get_zero_tensor(input)) + loss = -torch.mean(minval) + else: + assert target_is_real, "The generator's hinge loss must be aiming for real" + loss = -torch.mean(input) + return loss + else: + # wgan + if target_is_real: + return -input.mean() + else: + return input.mean() + + def __call__(self, input, target_is_real, for_discriminator=True): + # computing loss is a bit complicated because |input| may not be + # a tensor, but list of tensors in case of multiscale discriminator + if isinstance(input, list): + loss = 0 + for pred_i in input: + if isinstance(pred_i, list): + pred_i = pred_i[-1] + loss_tensor = self.loss(pred_i, target_is_real, for_discriminator) + bs = 1 if len(loss_tensor.size()) == 0 else loss_tensor.size(0) + new_loss = torch.mean(loss_tensor.view(bs, -1), dim=1) + loss += new_loss + return loss / len(input) + else: + return self.loss(input, target_is_real, for_discriminator) + + +# Perceptual loss that uses a pretrained VGG network +class VGGLoss(nn.Module): + def __init__(self, opt): + super(VGGLoss, self).__init__() + if opt.face_vgg: + self.vgg = VGGFace19(opt).cuda() + else: + self.vgg = VGG19().cuda() + self.criterion = nn.L1Loss() + self.weights = [1.0 / 32, 1.0 / 16, 1.0 / 8, 1.0 / 4, 1.0] + + def forward(self, x, y, layer=0): + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + loss = 0 + for i in range(len(x_vgg)): + if i >= layer: + loss += self.weights[i] * self.criterion(x_vgg[i], y_vgg[i].detach()) + return loss + + +class VGGwithContrastiveLoss(VGGLoss): + def __init__(self, opt): + super(VGGwithContrastiveLoss, self).__init__(opt) + self.closs = L2ContrastiveLoss(opt.l2_margin) + + def forward(self, x, y, layer=0): + x_vgg, y_vgg = self.vgg(x), self.vgg(y) + loss = 0 + for i in range(len(x_vgg)): + if i >= layer: + loss += self.weights[i] * self.criterion(x_vgg[i], y_vgg[i].detach()) + + if i == len(x_vgg) - 1: + x_feature = x_vgg[i].view(x_vgg[i].size(0), -1) + y_feature = y_vgg[i].view(y_vgg[i].size(0), -1) + loss + self.closs(x_feature, y_feature.detach()) + return loss + + +# KL Divergence loss used in VAE with an image encoder +class KLDLoss(nn.Module): + def forward(self, mu, logvar): + return -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp()) + + +class L2ContrastiveLoss(nn.Module): + """ + Compute L2 contrastive loss + """ + + def __init__(self, margin=1, max_violation=False): + super(L2ContrastiveLoss, self).__init__() + self.margin = margin + + self.sim = self.l2_sim + + self.max_violation = max_violation + + def forward(self, feature1, feature2): + # compute image-sentence score matrix + feature1 = self.l2_norm(feature1) + feature2 = self.l2_norm(feature2) + scores = self.sim(feature1, feature2) + # diagonal = scores.diag().view(feature1.size(0), 1) + diagonal_dist = scores.diag() + # d1 = diagonal.expand_as(scores) + + # compare every diagonal score to scores in its column + # caption retrieval + cost_s = (self.margin - scores).clamp(min=0) + + # clear diagonals + mask = torch.eye(scores.size(0)) > .5 + I = mask.clone() + if torch.cuda.is_available(): + I = I.cuda() + cost_s = cost_s.masked_fill_(I, 0) + + # keep the maximum violating negative for each query + if self.max_violation: + cost_s = cost_s.max(1)[0] + + loss = (torch.sum(cost_s ** 2) + torch.sum(diagonal_dist ** 2)) / (2 * feature1.size(0)) + + return loss + + def l2_norm(self, x): + x_norm = F.normalize(x, p=2, dim=1) + return x_norm + + def l2_sim(self, feature1, feature2): + Feature = feature1.expand(feature1.size(0), feature1.size(0), feature1.size(1)).transpose(0, 1) + return torch.norm(Feature - feature2, p=2, dim=2) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/normalization.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/normalization.py new file mode 100644 index 0000000000..cff06f4148 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/normalization.py @@ -0,0 +1,106 @@ +import re +import torch.nn as nn +import torch.nn.functional as F +from .sync_batchnorm import SynchronizedBatchNorm2d +import torch.nn.utils.spectral_norm as spectral_norm + + +# Returns a function that creates a normalization function +# that does not condition on semantic map +def get_nonspade_norm_layer(opt, norm_type='instance'): + # helper function to get # output channels of the previous layer + def get_out_channel(layer): + if hasattr(layer, 'out_channels'): + return getattr(layer, 'out_channels') + return layer.weight.size(0) + + # this function will be returned + def add_norm_layer(layer): + nonlocal norm_type + if norm_type.startswith('spectral'): + layer = spectral_norm(layer) + subnorm_type = norm_type[len('spectral'):] + else: + subnorm_type = norm_type + + if subnorm_type == 'none' or len(subnorm_type) == 0: + return layer + + # remove bias in the previous layer, which is meaningless + # since it has no effect after normalization + if getattr(layer, 'bias', None) is not None: + delattr(layer, 'bias') + layer.register_parameter('bias', None) + + if subnorm_type == 'batch': + norm_layer = nn.BatchNorm2d(get_out_channel(layer), affine=True) + elif subnorm_type == 'syncbatch': + norm_layer = SynchronizedBatchNorm2d(get_out_channel(layer), affine=True) + elif subnorm_type == 'instance': + norm_layer = nn.InstanceNorm2d(get_out_channel(layer), affine=False) + else: + raise ValueError('normalization layer %s is not recognized' % subnorm_type) + + return nn.Sequential(layer, norm_layer) + + return add_norm_layer + + +# Creates SPADE normalization layer based on the given configuration +# SPADE consists of two steps. First, it normalizes the activations using +# your favorite normalization method, such as Batch Norm or Instance Norm. +# Second, it applies scale and bias to the normalized output, conditioned on +# the segmentation map. +# The format of |config_text| is spade(norm)(ks), where +# (norm) specifies the type of parameter-free normalization. +# (e.g. syncbatch, batch, instance) +# (ks) specifies the size of kernel in the SPADE module (e.g. 3x3) +# Example |config_text| will be spadesyncbatch3x3, or spadeinstance5x5. +# Also, the other arguments are +# |norm_nc|: the #channels of the normalized activations, hence the output dim of SPADE +# |label_nc|: the #channels of the input semantic map, hence the input dim of SPADE +class SPADE(nn.Module): + def __init__(self, config_text, norm_nc, label_nc): + super().__init__() + + assert config_text.startswith('spade') + parsed = re.search('spade(\D+)(\d)x\d', config_text) + param_free_norm_type = str(parsed.group(1)) + ks = int(parsed.group(2)) + + if param_free_norm_type == 'instance': + self.param_free_norm = nn.InstanceNorm2d(norm_nc, affine=False) + elif param_free_norm_type == 'syncbatch': + self.param_free_norm = SynchronizedBatchNorm2d(norm_nc, affine=False) + elif param_free_norm_type == 'batch': + self.param_free_norm = nn.BatchNorm2d(norm_nc, affine=False) + else: + raise ValueError('%s is not a recognized param-free norm type in SPADE' + % param_free_norm_type) + + # The dimension of the intermediate embedding space. Yes, hardcoded. + nhidden = 128 + + pw = ks // 2 + self.mlp_shared = nn.Sequential( + nn.Conv2d(label_nc, nhidden, kernel_size=ks, padding=pw), + nn.ReLU() + ) + self.mlp_gamma = nn.Conv2d(nhidden, norm_nc, kernel_size=ks, padding=pw) + self.mlp_beta = nn.Conv2d(nhidden, norm_nc, kernel_size=ks, padding=pw) + + def forward(self, x, segmap): + + # Part 1. generate parameter-free normalized activations + normalized = self.param_free_norm(x) + + # Part 2. produce scaling and bias conditioned on semantic map + segmap = F.interpolate(segmap, size=x.size()[2:], mode='nearest') + actv = self.mlp_shared(segmap) + gamma = self.mlp_gamma(actv) + beta = self.mlp_beta(actv) + + # apply scale and bias + out = normalized * (1 + gamma) + beta + + return out diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/render.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/render.py new file mode 100644 index 0000000000..e57350490e --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/render.py @@ -0,0 +1,584 @@ +import os.path as osp +import numpy as np +import torch +import scipy.io as sio +import pickle +from ...data import curve +import skimage.transform as trans +from math import cos, sin, atan2, asin +import neural_renderer as nr + + +def _get_suffix(filename): + """a.jpg -> jpg""" + pos = filename.rfind('.') + if pos == -1: + return '' + return filename[pos + 1:] + + +def _load(fp): + suffix = _get_suffix(fp) + if suffix == 'npy': + return np.load(fp) + elif suffix == 'pkl': + return pickle.load(open(fp, 'rb')) + + +def P2sRt(P): + ''' decompositing camera matrix P. + Args: + P: (3, 4). Affine Camera Matrix. + Returns: + s: scale factor. + R: (3, 3). rotation matrix. + t2d: (2,). 2d translation. + ''' + t3d = P[:, 3] + R1 = P[0:1, :3] + R2 = P[1:2, :3] + s = (np.linalg.norm(R1) + np.linalg.norm(R2)) / 2.0 + r1 = R1 / np.linalg.norm(R1) + r2 = R2 / np.linalg.norm(R2) + r3 = np.cross(r1, r2) + + R = np.concatenate((r1, r2, r3), 0) + return s, R, t3d + + +def matrix2angle(R): + ''' compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf + Args: + R: (3,3). rotation matrix + Returns: + x: yaw + y: pitch + z: roll + ''' + # assert(isRotationMatrix(R)) + + if R[2, 0] != 1 and R[2, 0] != -1: + x = -asin(max(-1, min(R[2, 0], 1))) + y = atan2(R[2, 1] / cos(x), R[2, 2] / cos(x)) + z = atan2(R[1, 0] / cos(x), R[0, 0] / cos(x)) + + else: # Gimbal lock + z = 0 # can be anything + if R[2, 0] == -1: + x = np.pi / 2 + y = z + atan2(R[0, 1], R[0, 2]) + else: + x = -np.pi / 2 + y = -z + atan2(-R[0, 1], -R[0, 2]) + + return [x, y, z] + + +def angle2matrix(angles): + ''' get rotation matrix from three rotation angles(radian). The same as in 3DDFA. + Args: + angles: [3,]. x, y, z angles + x: yaw. + y: pitch. + z: roll. + Returns: + R: 3x3. rotation matrix. + ''' + # x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2]) + # x, y, z = angles[0], angles[1], angles[2] + y, x, z = angles[0], angles[1], angles[2] + + # x + Rx = np.array([[1, 0, 0], + [0, cos(x), -sin(x)], + [0, sin(x), cos(x)]]) + # y + Ry = np.array([[cos(y), 0, sin(y)], + [0, 1, 0], + [-sin(y), 0, cos(y)]]) + # z + Rz = np.array([[cos(z), -sin(z), 0], + [sin(z), cos(z), 0], + [0, 0, 1]]) + R = Rz.dot(Ry).dot(Rx) + return R.astype(np.float32) + + +class Render(object): + def __init__(self, opt): + self.opt = opt + self.render_size = opt.crop_size + print(self.render_size, opt.crop_size) + self.d = './algorithm/DDFA/train.configs' + w_shp = _load(osp.join(self.d, 'w_shp_sim.npy')) + w_exp = _load(osp.join(self.d, 'w_exp_sim.npy')) # simplified version + u_shp = _load(osp.join(self.d, 'u_shp.npy')) + u_exp = _load(osp.join(self.d, 'u_exp.npy')) + self.keypoints = _load(osp.join(self.d, 'keypoints_sim.npy')) + self.pose_noise = getattr(opt, 'pose_noise', False) + self.large_pose = getattr(opt, 'large_pose', False) + u = u_shp + u_exp + tri = sio.loadmat('./algorithm/DDFA/visualize/tri.mat')['tri'] # 3 * 53215 + faces_np = np.expand_dims(tri.T, axis=0).astype(np.int32) - 1 + + self.std_size = 120 + + opt.gpu_ids = 0 + + self.current_gpu = opt.gpu_ids + with torch.cuda.device(self.current_gpu): + self.faces = torch.from_numpy(faces_np).cuda() + self.renderer = nr.Renderer(camera_mode='look', image_size=self.render_size, perspective=False, + light_intensity_directional=0, light_intensity_ambient=1) + self.u_cuda = torch.from_numpy(u.astype(np.float32)).cuda() + self.w_shp_cuda = torch.from_numpy(w_shp.astype(np.float32)).cuda() + self.w_exp_cuda = torch.from_numpy(w_exp.astype(np.float32)).cuda() + + def random_p(self, s, angle): + + if np.random.randint(0, 2) == 0: + angle[0] += np.random.uniform(-0.965, -0.342, 1)[0] + # angle[1] += np.random.uniform(-0.1, 0.1, 1)[0] + else: + angle[0] += np.random.uniform(0.342, 0.965, 1)[0] + # angle[1] += np.random.uniform(-0.1, 0.1, 1)[0] + angle[0] = max(-1.2, min(angle[0], 1.2)) + random_2 = np.random.uniform(-0.5, 0.5, 1)[0] + angle[1] += random_2 + angle[1] = max(-1.0, min(angle[1], 1.0)) + p = angle2matrix(angle) * s + return p + + def assign_large(self, s, angle): + if np.random.randint(0, 2) == 0: + angle[0] = np.random.uniform(-1.05, -0.95, 1)[0] + # angle[1] += np.random.uniform(-0.1, 0.1, 1)[0] + else: + angle[0] = np.random.uniform(1.05, 0.95, 1)[0] + # angle[1] += np.random.uniform(-0.1, 0.1, 1)[0] + angle[0] = max(-1.2, min(angle[0], 1.2)) + random_2 = np.random.uniform(-0.5, 0.5, 1)[0] + angle[1] += random_2 + angle[1] = max(-1.0, min(angle[1], 1.0)) + p = angle2matrix(angle) * s + return p + + def _parse_param(self, param, pose_noise=False, frontal=True, + large_pose=False, yaw_pose=None, pitch_pose=None): + """Work for both numpy and tensor""" + p_ = param[:12].reshape(3, -1) + p = p_[:, :3] + s, R, t3d = P2sRt(p_) + angle = matrix2angle(R) + original_angle = angle[0] + if yaw_pose is not None or pitch_pose is not None: + # angle[0] = yaw_pose if yaw_pose is not None + if yaw_pose is not None: + angle[0] = yaw_pose + # flag = -1 if angle[0] < 0 else 1 + # angle[0] = flag * abs(yaw_pose) + if pitch_pose is not None: + angle[1] = pitch_pose + # flag = -1 if angle[1] < 0 else 1 + # angle[1] = flag * abs(pitch_pose) + # elif angle[1] < 0: + # angle[1] = 0 + p = angle2matrix(angle) * s + else: + if frontal: + angle[0] = 0 + if angle[1] < 0: + angle[1] = 0 + p = angle2matrix(angle) * s + if pose_noise: + if frontal: + if np.random.randint(0, 5): + p = self.random_p(s, angle) + else: + p = self.random_p(s, angle) + elif large_pose: + if frontal: + if np.random.randint(0, 5): + p = self.assign_large(s, angle) + else: + p = self.assign_large(s, angle) + + offset = p_[:, -1].reshape(3, 1) + alpha_shp = param[12:52].reshape(-1, 1) + alpha_exp = param[52:-4].reshape(-1, 1) + box = param[-4:] + return p, offset, alpha_shp, alpha_exp, box, original_angle + + def affine_align(self, landmark=None, **kwargs): + # M = None + src = np.array([ + [38.2946, 51.6963], + [73.5318, 51.5014], + [56.0252, 71.7366], + [41.5493, 92.3655], + [70.7299, 92.2041]], dtype=np.float32) + src = src * 290 / 112 + src[:, 0] += 50 + src[:, 1] += 60 + src = src / 400 * self.render_size + dst = landmark.astype(np.float32) + tform = trans.SimilarityTransform() + tform.estimate(dst, src) + M2 = tform.params[0:2, :] + with torch.cuda.device(self.current_gpu): + M2 = torch.from_numpy(M2).float().cuda() + return M2 + + def texture_vertices_to_faces(self, tex_input, faces): + # tex_input: (B, N, 2, 2, 2, C) + # faces: (faceN, 3) + faces = faces.long() + tex_out = tex_input[:, faces[0, :, 0], :] + tex_input[:, faces[0, :, 1], :] + tex_input[:, faces[0, :, 2], :] + return tex_out / 3.0 + + def compute_tri_normal(self, vertex, tri): + # Unit normals to the faces + # vertex : 3xvertex_num + # tri : 3xtri_num + + vt1_indices, vt2_indices, vt3_indices = torch.split(tri.t(), split_size_or_sections=1, dim=1) + + vt1 = vertex[vt1_indices[:, 0], :] + vt2 = vertex[vt2_indices[:, 0], :] + vt3 = vertex[vt3_indices[:, 0], :] + + normalf = (vt2 - vt1).cross(vt3 - vt1) + normalf = torch.nn.functional.normalize(normalf, dim=1, p=2) + + return normalf + + def vertices_rescale(self, v, roi_bbox): + vertices = v.clone() + sx, sy, ex, ey = roi_bbox + scale_x = (ex - sx) / 120 + scale_y = (ey - sy) / 120 + vertices[0, :] = vertices[0, :] * scale_x + sx + vertices[1, :] = vertices[1, :] * scale_y + sy + s = (scale_x + scale_y) / 2 + vertices[2, :] *= s + return vertices + + def get_five_points(self, vertices): + indexs = [4150, 11744, 8191, 5650, 10922] + five_points = np.zeros((5, 2)) + for i, idx in enumerate(indexs): + five_points[i, :] = vertices[0:2, idx] + return five_points + + def get_68_points(self, vertices): + vertixes = vertices.T.flatten() + vertice_68 = vertixes[self.keypoints].reshape(-1, 3) + vertice_68 = vertice_68.astype(np.int) + return vertice_68 + + def torch_get_68_points(self, vertices): + vertixes = vertices.transpose(1, 2).contiguous() + vertixes = vertixes.view(vertixes.size(0), -1) + vertice_68 = vertixes[:, self.keypoints].reshape(vertices.size(0), -1, 3) + return vertice_68 + + def transform_vertices(self, M, vertices): + # M = M.float() + v_size = vertices.size() + # M = torch.Tensor(M).cuda() + with torch.cuda.device(self.current_gpu): + M = M.float().cuda() + R = M[:, :2] + t = M[:, 2] + vertices2 = vertices.clone() + vertices2 = vertices2.float() + vertices2[:2, :] = R.mm(vertices2[:2, :]) + t.repeat(v_size[1], 1).t() + return vertices2 + + def generate_vertices_and_rescale_to_img(self, param, pose_noise=False, + mean_shp=False, mean_exp=False, frontal=True, large_pose=False, + yaw_pose=None, pitch_pose=None): + p, offset, alpha_shp, alpha_exp, roi_bbox, original_angle = self._parse_param(param, pose_noise=pose_noise, + frontal=frontal, + large_pose=large_pose, + yaw_pose=yaw_pose, + pitch_pose=pitch_pose) + if mean_shp: + alpha_shp.fill(0.0) + if mean_exp: + alpha_exp.fill(0.0) + with torch.cuda.device(self.current_gpu): + p = torch.from_numpy(p.astype(np.float32)).cuda() + alpha_shp = torch.from_numpy(alpha_shp.astype(np.float32)).cuda() + alpha_exp = torch.from_numpy(alpha_exp.astype(np.float32)).cuda() + offset = torch.from_numpy(offset.astype(np.float32)).cuda() + + vertices = p.matmul( + (self.u_cuda + self.w_shp_cuda.matmul(alpha_shp) + self.w_exp_cuda.matmul(alpha_exp)).view(-1, + 3).t()) + offset + + vertices[1, :] = self.std_size + 1 - vertices[1, :] + vertices = self.vertices_rescale(vertices, roi_bbox) + + return vertices, original_angle + + def flip_normalize_vertices(self, vertices): + # flip and normalize vertices + vertices[1, :] = self.render_size - vertices[1, :] - 1 + vertices[:2, :] = vertices[:2, :] / (self.render_size / 2.0) - 1.0 + vertices[2, :] = (vertices[2, :] - vertices[2, :].min()) / (vertices[2, :].max() - vertices[2, :].min()) * 2 - 1 + vertices[2, :] = -1.0 * vertices[2, :] + vertices = vertices.t().unsqueeze(0) + return vertices + + def get_render_from_vertices(self, img_ori, vertices_in_ori_img): + c, h, w = img_ori.size() + img_ori = img_ori.clone().permute(1, 2, 0) + # random_num = np.random.randint(30000, 50000) + # vertices_in_ori_img[:,30000:50000] = vertices_in_ori_img[:,30000:50000] * 1.02 - 3 + # vertices_in_ori_img[:, 20000:random_num] = vertices_in_ori_img[:, 20000:random_num] * np.random.uniform(1.01, + # 1.02) - np.random.uniform(0.5, 1.5) + + textures = img_ori[vertices_in_ori_img[1, :].round().clamp(0, h - 1).long(), vertices_in_ori_img[0, :].round().clamp( + 0, w - 1).long(), :] + + N = textures.shape[0] + with torch.cuda.device(self.current_gpu): + textures = textures.cuda().view(1, N, 1, 1, 1, 3) + textures = textures.expand(1, N, 2, 2, 2, 3) + textures = textures.float() + tex_a = self.texture_vertices_to_faces(textures, self.faces) + + return tex_a + + def _forward(self, param_file, img_ori, M=None, + pose_noise=True, mean_exp=False, mean_shp=False, align=True, frontal=True, + large_pose=False, yaw_pose=None, pitch_pose=None): + ''' + img_ori: rgb image, normalized within 0-1, h * w * 3 + return: render image, bgr + ''' + param = np.fromfile(param_file, sep=' ') + + vertices, original_angle = self.generate_vertices_and_rescale_to_img(param, pose_noise=pose_noise, + mean_shp=mean_shp, mean_exp=mean_exp, + frontal=frontal, + large_pose=large_pose, yaw_pose=yaw_pose, + pitch_pose=pitch_pose) + + if not (pose_noise or mean_exp or mean_exp or frontal): + print('pose_noise') + print(not pose_noise or mean_exp or mean_exp or frontal) + if M is not None: + vertices = self.transform_vertices(M, vertices) + else: + five_points = self.get_five_points(vertices.cpu().numpy()) + M = self.affine_align(five_points) + vertices = self.transform_vertices(M, vertices) + vertices_in_ori_img = vertices.clone() + align_vertices = vertices.clone() + else: + vertices_in_ori_img, _ = self.generate_vertices_and_rescale_to_img(param, pose_noise=False, + mean_shp=False, mean_exp=False, + frontal=False, large_pose=False) + if M is not None: + vertices_in_ori_img = self.transform_vertices(M, vertices_in_ori_img) + else: + five_points = self.get_five_points(vertices_in_ori_img.cpu().numpy()) + M = self.affine_align(five_points) + vertices_in_ori_img = self.transform_vertices(M, vertices_in_ori_img) + + five_points = self.get_five_points(vertices.cpu().numpy()) + M_0 = self.affine_align(five_points) + + # if np.random.randint(0, 4) < 1: + if align: + vertices = self.transform_vertices(M_0, vertices) + align_vertices = vertices.clone() + else: + align_vertices = vertices.clone() + align_vertices = self.transform_vertices(M_0, align_vertices) + vertices = self.transform_vertices(M, vertices) + + with torch.cuda.device(self.current_gpu): + img_ori = img_ori.cuda() + c, h, w = img_ori.size() + assert h == w + + vertices_in_ori_img[:2, :] = vertices_in_ori_img[:2, :] / self.render_size * h + # original image size is 400 * 400 * 3 + + # original image size is 400 * 400 * 3 + vertices_out = vertices.clone() + tex_a = self.get_render_from_vertices(img_ori, vertices_in_ori_img) + vertices = self.flip_normalize_vertices(vertices) + vertices_in_ori_img[:2, :] = vertices_in_ori_img[:2, :] / h * self.render_size + return tex_a, vertices, vertices_out, vertices_in_ori_img, align_vertices, original_angle + + def rotate_render(self, params, images, M=None, with_BG=False, pose_noise=False, large_pose=False, + align=True, frontal=True, erode=True, grey_background=False, avg_BG=True, + yaw_pose=None, pitch_pose=None): + + bz, c, w, h = images.size() + pose_noise = self.pose_noise + large_pose = self.large_pose + face_size = self.faces.size() + self.faces_use = self.faces.expand(bz, face_size[1], face_size[2]) + + # get render color vertices and normal vertices information, get original texs + vertices = [] + vertices_out = [] + vertices_in_ori_img = [] + vertices_aligned_normal = [] + vertices_aligned_out = [] + vertices_ori_normal = [] + texs = [] + original_angles = torch.zeros(bz) + with torch.no_grad(): + for n in range(bz): + tex_a, vertice, vertice_out, vertice_in_ori_img, align_vertice, original_angle \ + = self._forward(params[n], images[n], M[n], + pose_noise=pose_noise, align=align, frontal=frontal, + large_pose=large_pose, yaw_pose=yaw_pose, pitch_pose=pitch_pose) + vertices.append(vertice) + vertices_out.append(vertice_out) + vertices_in_ori_img.append(vertice_in_ori_img.clone()) + vertice2 = self.flip_normalize_vertices(vertice_in_ori_img.clone()) + vertices_ori_normal.append(vertice2) + vertices_aligned_out.append(align_vertice) + align_vertice_normal = self.flip_normalize_vertices(align_vertice.clone()) + vertices_aligned_normal.append(align_vertice_normal.clone()) + texs.append(tex_a) + original_angles[n] = original_angle + + vertices = torch.cat(vertices, 0) + vertices_aligned_normal = torch.cat(vertices_aligned_normal, 0) + vertices_ori_normal = torch.cat(vertices_ori_normal, 0) + + vertices_in_ori_img = torch.stack(vertices_in_ori_img, 0) + vertices_aligned_out = torch.stack(vertices_aligned_out, 0) + + texs = torch.cat(texs, 0) + texs_old = texs.clone() + + # erode the original mask and render again + rendered_images_erode = None + if erode: + + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices_ori_normal, self.faces_use, texs) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + masks_erode = self.generate_erode_mask(masks, kernal_size=self.opt.erode_kernel) + rendered_images = rendered_images.cpu() + Rd_a = rendered_images.clone() + if grey_background: + rendered_images_erode = masks_erode * rendered_images + else: + + inv_masks_erode = (torch.ones_like(masks_erode) - (masks_erode)).float() + if avg_BG: + contentsum = torch.sum(torch.sum(masks_erode * rendered_images, 3), 2) + sumsum = torch.sum(torch.sum(masks_erode, 3), 2) + contentsum[contentsum == 0] = 0.5 + sumsum[sumsum == 0] = 1 + masked_sum = contentsum / sumsum + masked_BG = masked_sum.unsqueeze(2).unsqueeze(3).expand(rendered_images.size()) + else: + masked_BG = 0.5 + rendered_images_erode = masks_erode * rendered_images + inv_masks_erode * masked_BG + + texs_a_crop = [] + for n in range(bz): + tex_a_crop = self.get_render_from_vertices(rendered_images_erode[n], vertices_in_ori_img[n]) + texs_a_crop.append(tex_a_crop) + texs = torch.cat(texs_a_crop, 0) + + # render face to rotated pose + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices, self.faces_use, texs) + + # add mask to rotated + masks_erode = self.generate_erode_mask(masks, kernal_size=5) + inv_masks_erode = (torch.ones_like(masks_erode) - masks_erode).float() + rendered_images = rendered_images.cpu() + if with_BG: + images = torch.nn.functional.interpolate(images, size=(self.render_size)) + rendered_images = masks_erode * rendered_images + inv_masks_erode * images # 3 * h * w + else: + if grey_background: + if np.random.randint(0, 4): + rendered_images = masks_erode * rendered_images + else: + if avg_BG: + contentsum = torch.sum(torch.sum(masks_erode * rendered_images, 3), 2) + sumsum = torch.sum(torch.sum(masks_erode, 3), 2) + contentsum[contentsum == 0] = 0.5 + sumsum[sumsum == 0] = 1 + masked_sum = contentsum / sumsum + masked_BG = masked_sum.unsqueeze(2).unsqueeze(3).expand(rendered_images.size()) + else: + masked_BG = 0.5 + rendered_images = masks_erode * rendered_images + inv_masks_erode * masked_BG + + # get rendered face vertices + texs_b = [] + for n in range(bz): + tex_b = self.get_render_from_vertices(rendered_images[n], vertices_out[n]) + texs_b.append(tex_b) + texs_b = torch.cat(texs_b, 0) + + # render back + with torch.cuda.device(self.current_gpu): + rendered_images_rotate, depths1, masks1, = self.renderer(vertices_ori_normal, self.faces_use, texs_b) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + rendered_images_rotate_artifacts, depths1, masks1, = self.renderer(vertices_aligned_normal, self.faces_use, + texs_old) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + rendered_images_double, depths2, masks2, = self.renderer(vertices_aligned_normal, self.faces_use, texs_b) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + + masks2 = masks2.unsqueeze(1) + inv_masks2 = (torch.ones_like(masks2) - masks2).float().cpu() + # BG = inv_masks2 * images + if grey_background: + masks1 = masks1.unsqueeze(1) + + inv_masks1 = (torch.ones_like(masks1) - masks1).float() + + rendered_images_rotate = (inv_masks1 * 0.5 + rendered_images_rotate).clamp(0, 1) + rendered_images_double = (inv_masks2 * 0.5 + rendered_images_double).clamp(0, 1) + + artifacts = rendered_images_rotate_artifacts + return rendered_images_rotate, rendered_images_double, self.torch_get_68_points( + vertices_in_ori_img), self.torch_get_68_points( + vertices_aligned_out), rendered_images_erode, original_angles, Rd_a, artifacts + + def generate_erode_mask(self, masks, kernal_size=5): + masks = masks.unsqueeze(1) + masks = masks.cpu() + with torch.no_grad(): + Conv = torch.nn.Conv2d(1, 1, kernal_size, padding=(kernal_size // 2), bias=False) + Conv.weight.fill_(1 / (kernal_size * kernal_size)) + masks2 = Conv(masks) + random_start1 = np.random.randint(50, 100) + masks[:, :, random_start1:self.render_size - 10, :] = masks2[:, :, random_start1:self.render_size - 10, :] + masks = (masks > np.random.uniform(0.8, 0.99)).float() + return masks + + def get_seg_map(self, vertices, no_guassian=False, size=256): + landmarks = self.torch_get_68_points(vertices) + landmarks = landmarks[:, :, :2].cpu().numpy().astype(np.float) + all_heatmap = [] + all_orig_heatmap = [] + for i in range(landmarks.shape[0]): + heatmap = curve.points_to_heatmap_68points(landmarks[i], 13, size, self.opt.heatmap_size) + heatmap2 = curve.combine_map(heatmap, no_guassian=no_guassian) + all_heatmap.append(heatmap2) + all_orig_heatmap.append(heatmap) + all_heatmap = np.stack(all_heatmap, axis=0) + all_orig_heatmap = np.stack(all_orig_heatmap, axis=0) + all_heatmap = torch.from_numpy(all_heatmap.astype(np.float32)).cuda() + all_orig_heatmap = torch.from_numpy(all_orig_heatmap.astype(np.float32)).cuda() + all_orig_heatmap = all_orig_heatmap.permute(0, 3, 1, 2) + all_orig_heatmap[all_orig_heatmap > 0] = 1.0 + return all_heatmap, all_orig_heatmap diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/rotate_render.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/rotate_render.py new file mode 100644 index 0000000000..c32239200d --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/rotate_render.py @@ -0,0 +1,115 @@ +import torch +import pickle +import numpy as np +from .render import osp, Render + + +def _get_suffix(filename): + """a.jpg -> jpg""" + pos = filename.rfind('.') + if pos == -1: + return '' + return filename[pos + 1:] + + +def _load(fp): + suffix = _get_suffix(fp) + if suffix == 'npy': + return np.load(fp) + elif suffix == 'pkl': + return pickle.load(open(fp, 'rb')) + + +class TestRender(Render): + + def __init__(self, opt): + super(TestRender, self).__init__(opt) + self.keypoints_106 = _load(osp.join(self.d, '106_index.npy')) + + def torch_get_106_points(self, vertices): + vertixes = vertices.transpose(1, 2).contiguous() + vertixes = vertixes.view(vertixes.size(0), -1) + vertice_106 = vertixes[:, self.keypoints_106].reshape(vertices.size(0), -1, 3) + return vertice_106 + + def rotate_render(self, params, images, M=None, with_BG=False, pose_noise=False, large_pose=False, + align=True, frontal=True, erode=True, grey_background=False, avg_BG=True, + yaw_pose=None, pitch_pose=None): + + bz, c, w, h = images.size() + + face_size = self.faces.size() + self.faces_use = self.faces.expand(bz, face_size[1], face_size[2]) + + # get render color vertices and normal vertices information, get original texs + vertices = [] + vertices_out = [] + vertices_in_ori_img = [] + vertices_aligned_normal = [] + vertices_aligned_out = [] + vertices_ori_normal = [] + texs = [] + original_angles = torch.zeros(bz) + with torch.no_grad(): + for n in range(bz): + tex_a, vertice, vertice_out, vertice_in_ori_img, align_vertice, original_angle \ + = self._forward(params[n], images[n], M[n], + pose_noise=pose_noise, align=align, frontal=frontal, + yaw_pose=yaw_pose, pitch_pose=pitch_pose) + vertices.append(vertice) + vertices_out.append(vertice_out) + vertices_in_ori_img.append(vertice_in_ori_img.clone()) + vertice2 = self.flip_normalize_vertices(vertice_in_ori_img.clone()) + vertices_ori_normal.append(vertice2) + vertices_aligned_out.append(align_vertice) + align_vertice_normal = self.flip_normalize_vertices(align_vertice.clone()) + vertices_aligned_normal.append(align_vertice_normal.clone()) + texs.append(tex_a) + original_angles[n] = original_angle + + vertices = torch.cat(vertices, 0) + vertices_aligned_normal = torch.cat(vertices_aligned_normal, 0) + vertices_ori_normal = torch.cat(vertices_ori_normal, 0) + + vertices_in_ori_img = torch.stack(vertices_in_ori_img, 0) + vertices_aligned_out = torch.stack(vertices_aligned_out, 0) + + texs = torch.cat(texs, 0) + + # erode the original mask and render again + rendered_images_erode = None + if erode: + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices_ori_normal, self.faces_use, + texs) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + masks_erode = self.generate_erode_mask(masks, kernal_size=15) + rendered_images = rendered_images.cpu() + if grey_background: + rendered_images_erode = masks_erode * rendered_images + else: + inv_masks_erode = (torch.ones_like(masks_erode) - (masks_erode)).float() + if avg_BG: + contentsum = torch.sum(torch.sum(masks_erode * rendered_images, 3), 2) + sumsum = torch.sum(torch.sum(masks_erode, 3), 2) + contentsum[contentsum == 0] = 0.5 + sumsum[sumsum == 0] = 1 + masked_sum = contentsum / sumsum + masked_BG = masked_sum.unsqueeze(2).unsqueeze(3).expand(rendered_images.size()) + else: + masked_BG = 0.5 + rendered_images_erode = masks_erode * rendered_images + inv_masks_erode * masked_BG + + texs_a_crop = [] + for n in range(bz): + tex_a_crop = self.get_render_from_vertices(rendered_images_erode[n], vertices_in_ori_img[n]) + texs_a_crop.append(tex_a_crop) + texs = torch.cat(texs_a_crop, 0) + + # render face to rotated pose + with torch.no_grad(): + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices, self.faces_use, texs) + + return rendered_images, self.torch_get_68_points( + vertices_aligned_out), original_angles, self.torch_get_106_points(vertices_aligned_out) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/__init__.py new file mode 100644 index 0000000000..0c6b2d893b --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/__init__.py @@ -0,0 +1,6 @@ +from .batchnorm import SynchronizedBatchNorm1d, SynchronizedBatchNorm2d, SynchronizedBatchNorm3d +from .batchnorm import patch_sync_batchnorm, convert_model +from .replicate import DataParallelWithCallback, patch_replication_callback + +__all__ = ['SynchronizedBatchNorm1d', 'SynchronizedBatchNorm2d', 'SynchronizedBatchNorm3d', 'patch_sync_batchnorm', + 'convert_model', 'DataParallelWithCallback', 'patch_replication_callback'] diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm.py new file mode 100644 index 0000000000..be9ef149c5 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm.py @@ -0,0 +1,384 @@ +import collections +import contextlib + +import torch +import torch.nn.functional as F + +from torch.nn.modules.batchnorm import _BatchNorm + +try: + from torch.nn.parallel._functions import ReduceAddCoalesced, Broadcast +except ImportError: + ReduceAddCoalesced = Broadcast = None + +try: + from jactorch.parallel.comm import SyncMaster + from jactorch.parallel.data_parallel import JacDataParallel as DataParallelWithCallback +except ImportError: + from .comm import SyncMaster + from .replicate import DataParallelWithCallback + +__all__ = [ + 'SynchronizedBatchNorm1d', 'SynchronizedBatchNorm2d', 'SynchronizedBatchNorm3d', + 'patch_sync_batchnorm', 'convert_model' +] + + +def _sum_ft(tensor): + """sum over the first and last dimention""" + return tensor.sum(dim=0).sum(dim=-1) + + +def _unsqueeze_ft(tensor): + """add new dimensions at the front and the tail""" + return tensor.unsqueeze(0).unsqueeze(-1) + + +_ChildMessage = collections.namedtuple('_ChildMessage', ['sum', 'ssum', 'sum_size']) +_MasterMessage = collections.namedtuple('_MasterMessage', ['sum', 'inv_std']) + + +class _SynchronizedBatchNorm(_BatchNorm): + def __init__(self, num_features, eps=1e-5, momentum=0.1, affine=True): + assert ReduceAddCoalesced is not None, 'Can not use Synchronized Batch Normalization without CUDA support.' + + super(_SynchronizedBatchNorm, self).__init__(num_features, eps=eps, momentum=momentum, affine=affine) + + self._sync_master = SyncMaster(self._data_parallel_master) + + self._is_parallel = False + self._parallel_id = None + self._slave_pipe = None + + def forward(self, input): + # If it is not parallel computation or is in evaluation mode, use PyTorch's implementation. + if not (self._is_parallel and self.training): + return F.batch_norm( + input, self.running_mean, self.running_var, self.weight, self.bias, + self.training, self.momentum, self.eps) + + # Resize the input to (B, C, -1). + input_shape = input.size() + input = input.view(input.size(0), self.num_features, -1) + + # Compute the sum and square-sum. + sum_size = input.size(0) * input.size(2) + input_sum = _sum_ft(input) + input_ssum = _sum_ft(input ** 2) + + # Reduce-and-broadcast the statistics. + if self._parallel_id == 0: + mean, inv_std = self._sync_master.run_master(_ChildMessage(input_sum, input_ssum, sum_size)) + else: + mean, inv_std = self._slave_pipe.run_slave(_ChildMessage(input_sum, input_ssum, sum_size)) + + # Compute the output. + if self.affine: + # MJY:: Fuse the multiplication for speed. + output = (input - _unsqueeze_ft(mean)) * _unsqueeze_ft(inv_std * self.weight) + _unsqueeze_ft(self.bias) + else: + output = (input - _unsqueeze_ft(mean)) * _unsqueeze_ft(inv_std) + + # Reshape it. + return output.view(input_shape) + + def __data_parallel_replicate__(self, ctx, copy_id): + self._is_parallel = True + self._parallel_id = copy_id + + # parallel_id == 0 means master device. + if self._parallel_id == 0: + ctx.sync_master = self._sync_master + else: + self._slave_pipe = ctx.sync_master.register_slave(copy_id) + + def _data_parallel_master(self, intermediates): + """Reduce the sum and square-sum, compute the statistics, and broadcast it.""" + + # Always using same "device order" makes the ReduceAdd operation faster. + # Thanks to:: Tete Xiao (http://tetexiao.com/) + intermediates = sorted(intermediates, key=lambda i: i[1].sum.get_device()) + + to_reduce = [i[1][:2] for i in intermediates] + to_reduce = [j for i in to_reduce for j in i] # flatten + target_gpus = [i[1].sum.get_device() for i in intermediates] + + sum_size = sum([i[1].sum_size for i in intermediates]) + sum_, ssum = ReduceAddCoalesced.apply(target_gpus[0], 2, *to_reduce) + mean, inv_std = self._compute_mean_std(sum_, ssum, sum_size) + + broadcasted = Broadcast.apply(target_gpus, mean, inv_std) + + outputs = [] + for i, rec in enumerate(intermediates): + outputs.append((rec[0], _MasterMessage(*broadcasted[i*2:i*2+2]))) + + return outputs + + def _compute_mean_std(self, sum_, ssum, size): + """Compute the mean and standard-deviation with sum and square-sum. This method + also maintains the moving average on the master device.""" + assert size > 1, 'BatchNorm computes unbiased standard-deviation, which requires size > 1.' + mean = sum_ / size + sumvar = ssum - sum_ * mean + unbias_var = sumvar / (size - 1) + bias_var = sumvar / size + + if hasattr(torch, 'no_grad'): + with torch.no_grad(): + self.running_mean = (1 - self.momentum) * self.running_mean + self.momentum * mean.data + self.running_var = (1 - self.momentum) * self.running_var + self.momentum * unbias_var.data + else: + self.running_mean = (1 - self.momentum) * self.running_mean + self.momentum * mean.data + self.running_var = (1 - self.momentum) * self.running_var + self.momentum * unbias_var.data + + return mean, bias_var.clamp(self.eps) ** -0.5 + + +class SynchronizedBatchNorm1d(_SynchronizedBatchNorm): + r"""Applies Synchronized Batch Normalization over a 2d or 3d input that is seen as a + mini-batch. + + .. math:: + + y = \frac{x - mean[x]}{ \sqrt{Var[x] + \epsilon}} * gamma + beta + + This module differs from the built-in PyTorch BatchNorm1d as the mean and + standard-deviation are reduced across all devices during training. + + For example, when one uses `nn.DataParallel` to wrap the network during + training, PyTorch's implementation normalize the tensor on each device using + the statistics only on that device, which accelerated the computation and + is also easy to implement, but the statistics might be inaccurate. + Instead, in this synchronized version, the statistics will be computed + over all training samples distributed on multiple devices. + + Note that, for one-GPU or CPU-only case, this module behaves exactly same + as the built-in PyTorch implementation. + + The mean and standard-deviation are calculated per-dimension over + the mini-batches and gamma and beta are learnable parameter vectors + of size C (where C is the input size). + + During training, this layer keeps a running estimate of its computed mean + and variance. The running sum is kept with a default momentum of 0.1. + + During evaluation, this running mean/variance is used for normalization. + + Because the BatchNorm is done over the `C` dimension, computing statistics + on `(N, L)` slices, it's common terminology to call this Temporal BatchNorm + + Args: + num_features: num_features from an expected input of size + `batch_size x num_features [x width]` + eps: a value added to the denominator for numerical stability. + Default: 1e-5 + momentum: the value used for the running_mean and running_var + computation. Default: 0.1 + affine: a boolean value that when set to ``True``, gives the layer learnable + affine parameters. Default: ``True`` + + Shape:: + - Input: :math:`(N, C)` or :math:`(N, C, L)` + - Output: :math:`(N, C)` or :math:`(N, C, L)` (same shape as input) + + Examples: + >>> # With Learnable Parameters + >>> m = SynchronizedBatchNorm1d(100) + >>> # Without Learnable Parameters + >>> m = SynchronizedBatchNorm1d(100, affine=False) + >>> input = torch.autograd.Variable(torch.randn(20, 100)) + >>> output = m(input) + """ + + def _check_input_dim(self, input): + if input.dim() != 2 and input.dim() != 3: + raise ValueError('expected 2D or 3D input (got {}D input)' + .format(input.dim())) + super(SynchronizedBatchNorm1d, self)._check_input_dim(input) + + +class SynchronizedBatchNorm2d(_SynchronizedBatchNorm): + r"""Applies Batch Normalization over a 4d input that is seen as a mini-batch + of 3d inputs + + .. math:: + + y = \frac{x - mean[x]}{ \sqrt{Var[x] + \epsilon}} * gamma + beta + + This module differs from the built-in PyTorch BatchNorm2d as the mean and + standard-deviation are reduced across all devices during training. + + For example, when one uses `nn.DataParallel` to wrap the network during + training, PyTorch's implementation normalize the tensor on each device using + the statistics only on that device, which accelerated the computation and + is also easy to implement, but the statistics might be inaccurate. + Instead, in this synchronized version, the statistics will be computed + over all training samples distributed on multiple devices. + + Note that, for one-GPU or CPU-only case, this module behaves exactly same + as the built-in PyTorch implementation. + + The mean and standard-deviation are calculated per-dimension over + the mini-batches and gamma and beta are learnable parameter vectors + of size C (where C is the input size). + + During training, this layer keeps a running estimate of its computed mean + and variance. The running sum is kept with a default momentum of 0.1. + + During evaluation, this running mean/variance is used for normalization. + + Because the BatchNorm is done over the `C` dimension, computing statistics + on `(N, H, W)` slices, it's common terminology to call this Spatial BatchNorm + + Args: + num_features: num_features from an expected input of + size batch_size x num_features x height x width + eps: a value added to the denominator for numerical stability. + Default: 1e-5 + momentum: the value used for the running_mean and running_var + computation. Default: 0.1 + affine: a boolean value that when set to ``True``, gives the layer learnable + affine parameters. Default: ``True`` + + Shape:: + - Input: :math:`(N, C, H, W)` + - Output: :math:`(N, C, H, W)` (same shape as input) + + Examples: + >>> # With Learnable Parameters + >>> m = SynchronizedBatchNorm2d(100) + >>> # Without Learnable Parameters + >>> m = SynchronizedBatchNorm2d(100, affine=False) + >>> input = torch.autograd.Variable(torch.randn(20, 100, 35, 45)) + >>> output = m(input) + """ + + def _check_input_dim(self, input): + if input.dim() != 4: + raise ValueError('expected 4D input (got {}D input)' + .format(input.dim())) + super(SynchronizedBatchNorm2d, self)._check_input_dim(input) + + +class SynchronizedBatchNorm3d(_SynchronizedBatchNorm): + r"""Applies Batch Normalization over a 5d input that is seen as a mini-batch + of 4d inputs + + .. math:: + + y = \frac{x - mean[x]}{ \sqrt{Var[x] + \epsilon}} * gamma + beta + + This module differs from the built-in PyTorch BatchNorm3d as the mean and + standard-deviation are reduced across all devices during training. + + For example, when one uses `nn.DataParallel` to wrap the network during + training, PyTorch's implementation normalize the tensor on each device using + the statistics only on that device, which accelerated the computation and + is also easy to implement, but the statistics might be inaccurate. + Instead, in this synchronized version, the statistics will be computed + over all training samples distributed on multiple devices. + + Note that, for one-GPU or CPU-only case, this module behaves exactly same + as the built-in PyTorch implementation. + + The mean and standard-deviation are calculated per-dimension over + the mini-batches and gamma and beta are learnable parameter vectors + of size C (where C is the input size). + + During training, this layer keeps a running estimate of its computed mean + and variance. The running sum is kept with a default momentum of 0.1. + + During evaluation, this running mean/variance is used for normalization. + + Because the BatchNorm is done over the `C` dimension, computing statistics + on `(N, D, H, W)` slices, it's common terminology to call this Volumetric BatchNorm + or Spatio-temporal BatchNorm + + Args: + num_features: num_features from an expected input of + size batch_size x num_features x depth x height x width + eps: a value added to the denominator for numerical stability. + Default: 1e-5 + momentum: the value used for the running_mean and running_var + computation. Default: 0.1 + affine: a boolean value that when set to ``True``, gives the layer learnable + affine parameters. Default: ``True`` + + Shape:: + - Input: :math:`(N, C, D, H, W)` + - Output: :math:`(N, C, D, H, W)` (same shape as input) + + Examples: + >>> # With Learnable Parameters + >>> m = SynchronizedBatchNorm3d(100) + >>> # Without Learnable Parameters + >>> m = SynchronizedBatchNorm3d(100, affine=False) + >>> input = torch.autograd.Variable(torch.randn(20, 100, 35, 45, 10)) + >>> output = m(input) + """ + + def _check_input_dim(self, input): + if input.dim() != 5: + raise ValueError('expected 5D input (got {}D input)' + .format(input.dim())) + super(SynchronizedBatchNorm3d, self)._check_input_dim(input) + + +@contextlib.contextmanager +def patch_sync_batchnorm(): + import torch.nn as nn + + backup = nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d + + nn.BatchNorm1d = SynchronizedBatchNorm1d + nn.BatchNorm2d = SynchronizedBatchNorm2d + nn.BatchNorm3d = SynchronizedBatchNorm3d + + yield + + nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d = backup + + +def convert_model(module): + """Traverse the input module and its child recursively + and replace all instance of torch.nn.modules.batchnorm.BatchNorm*N*d + to SynchronizedBatchNorm*N*d + + Args: + module: the input module needs to be convert to SyncBN model + + Examples: + >>> import torch.nn as nn + >>> import torchvision + >>> # m is a standard pytorch model + >>> m = torchvision.models.resnet18(True) + >>> m = nn.DataParallel(m) + >>> # after convert, m is using SyncBN + >>> m = convert_model(m) + """ + if isinstance(module, torch.nn.DataParallel): + mod = module.module + mod = convert_model(mod) + mod = DataParallelWithCallback(mod) + return mod + + mod = module + for pth_module, sync_module in zip([torch.nn.modules.batchnorm.BatchNorm1d, + torch.nn.modules.batchnorm.BatchNorm2d, + torch.nn.modules.batchnorm.BatchNorm3d], + [SynchronizedBatchNorm1d, + SynchronizedBatchNorm2d, + SynchronizedBatchNorm3d]): + if isinstance(module, pth_module): + mod = sync_module(module.num_features, module.eps, module.momentum, module.affine) + mod.running_mean = module.running_mean + mod.running_var = module.running_var + if module.affine: + mod.weight.data = module.weight.data.clone().detach() + mod.bias.data = module.bias.data.clone().detach() + + for name, child in module.named_children(): + mod.add_module(name, convert_model(child)) + + return mod diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm_reimpl.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm_reimpl.py new file mode 100644 index 0000000000..6f9a5565a6 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/batchnorm_reimpl.py @@ -0,0 +1,57 @@ +import torch +import torch.nn as nn +import torch.nn.init as init + +__all__ = ['BatchNorm2dReimpl'] + + +class BatchNorm2dReimpl(nn.Module): + """ + A re-implementation of batch normalization, used for testing the numerical + stability. + + Author: acgtyrant + See also: + https://github.com/vacancy/Synchronized-BatchNorm-PyTorch/issues/14 + """ + + def __init__(self, num_features, eps=1e-5, momentum=0.1): + super().__init__() + + self.num_features = num_features + self.eps = eps + self.momentum = momentum + self.weight = nn.Parameter(torch.empty(num_features)) + self.bias = nn.Parameter(torch.empty(num_features)) + self.register_buffer('running_mean', torch.zeros(num_features)) + self.register_buffer('running_var', torch.ones(num_features)) + self.reset_parameters() + + def reset_running_stats(self): + self.running_mean.zero_() + self.running_var.fill_(1) + + def reset_parameters(self): + self.reset_running_stats() + init.uniform_(self.weight) + init.zeros_(self.bias) + + def forward(self, input_): + batchsize, channels, height, width = input_.size() + numel = batchsize * height * width + input_ = input_.permute(1, 0, 2, 3).contiguous().view(channels, numel) + sum_ = input_.sum(1) + sum_of_square = input_.pow(2).sum(1) + mean = sum_ / numel + sumvar = sum_of_square - sum_ * mean + + self.running_mean = ((1 - self.momentum) * self.running_mean + self.momentum * mean.detach()) + unbias_var = sumvar / (numel - 1) + self.running_var = ((1 - self.momentum) * self.running_var + self.momentum * unbias_var.detach()) + + bias_var = sumvar / numel + inv_std = 1 / (bias_var + self.eps).pow(0.5) + output = ((input_ - mean.unsqueeze(1)) * inv_std.unsqueeze(1) * self.weight.unsqueeze(1) + self.bias.unsqueeze( + 1)) + + return output.view(channels, batchsize, height, width).permute(1, 0, 2, 3).contiguous() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/comm.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/comm.py new file mode 100644 index 0000000000..0e159b3f53 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/comm.py @@ -0,0 +1,127 @@ +import queue +import collections +import threading + +__all__ = ['FutureResult', 'SlavePipe', 'SyncMaster'] + + +class FutureResult(object): + """A thread-safe future implementation. Used only as one-to-one pipe.""" + + def __init__(self): + self._result = None + self._lock = threading.Lock() + self._cond = threading.Condition(self._lock) + + def put(self, result): + with self._lock: + assert self._result is None, 'Previous result has\'t been fetched.' + self._result = result + self._cond.notify() + + def get(self): + with self._lock: + if self._result is None: + self._cond.wait() + + res = self._result + self._result = None + return res + + +_MasterRegistry = collections.namedtuple('MasterRegistry', ['result']) +_SlavePipeBase = collections.namedtuple('_SlavePipeBase', ['identifier', 'queue', 'result']) + + +class SlavePipe(_SlavePipeBase): + """Pipe for master-slave communication.""" + + def run_slave(self, msg): + self.queue.put((self.identifier, msg)) + ret = self.result.get() + self.queue.put(True) + return ret + + +class SyncMaster(object): + """An abstract `SyncMaster` object. + + - During the replication, as the data parallel will trigger an callback of each module, all slave devices should + call `register(id)` and obtain an `SlavePipe` to communicate with the master. + - During the forward pass, master device invokes `run_master`, all messages from slave devices will be collected, + and passed to a registered callback. + - After receiving the messages, the master device should gather the information and determine to message passed + back to each slave devices. + """ + + def __init__(self, master_callback): + """ + + Args: + master_callback: a callback to be invoked after having collected messages from slave devices. + """ + self._master_callback = master_callback + self._queue = queue.Queue() + self._registry = collections.OrderedDict() + self._activated = False + + def __getstate__(self): + return {'master_callback': self._master_callback} + + def __setstate__(self, state): + self.__init__(state['master_callback']) + + def register_slave(self, identifier): + """ + Register an slave device. + + Args: + identifier: an identifier, usually is the device id. + + Returns: a `SlavePipe` object which can be used to communicate with the master device. + + """ + if self._activated: + assert self._queue.empty(), 'Queue is not clean before next initialization.' + self._activated = False + self._registry.clear() + future = FutureResult() + self._registry[identifier] = _MasterRegistry(future) + return SlavePipe(identifier, self._queue, future) + + def run_master(self, master_msg): + """ + Main entry for the master device in each forward pass. + The messages were first collected from each devices (including the master device), and then + an callback will be invoked to compute the message to be sent back to each devices + (including the master device). + + Args: + master_msg: the message that the master want to send to itself. This will be placed as the first + message when calling `master_callback`. For detailed usage, see `_SynchronizedBatchNorm` for an example. + + Returns: the message to be sent back to the master device. + + """ + self._activated = True + + intermediates = [(0, master_msg)] + for i in range(self.nr_slaves): + intermediates.append(self._queue.get()) + + results = self._master_callback(intermediates) + assert results[0][0] == 0, 'The first result should belongs to the master.' + + for i, res in results: + if i == 0: + continue + self._registry[i].result.put(res) + + for i in range(self.nr_slaves): + assert self._queue.get() is True + + return results[0][1] + + @property + def nr_slaves(self): + return len(self._registry) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/replicate.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/replicate.py new file mode 100644 index 0000000000..63feed8971 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/replicate.py @@ -0,0 +1,119 @@ +import torch.multiprocessing as multiprocessing +import functools +import torch +from torch.nn.parallel.data_parallel import DataParallel +from .scatter_gather import scatter_kwargs +multiprocessing.set_start_method('spawn', force=True) +__all__ = [ + 'CallbackContext', + 'execute_replication_callbacks', + 'DataParallelWithCallback', + 'patch_replication_callback' +] + + +class CallbackContext(object): + pass + + +def execute_replication_callbacks(modules): + """ + Execute an replication callback `__data_parallel_replicate__` on each module created by original replication. + + The callback will be invoked with arguments `__data_parallel_replicate__(ctx, copy_id)` + + Note that, as all modules are isomorphism, we assign each sub-module with a context + (shared among multiple copies of this module on different devices). + Through this context, different copies can share some information. + + We guarantee that the callback on the master copy (the first copy) will be called ahead of calling the callback + of any slave copies. + """ + master_copy = modules[0] + nr_modules = len(list(master_copy.modules())) + ctxs = [CallbackContext() for _ in range(nr_modules)] + + for i, module in enumerate(modules): + for j, m in enumerate(module.modules()): + if hasattr(m, '__data_parallel_replicate__'): + m.__data_parallel_replicate__(ctxs[j], i) + + +class DataParallelWithCallback(DataParallel): + """ + Data Parallel with a replication callback. + + An replication callback `__data_parallel_replicate__` of each module will be invoked after being created by + original `replicate` function. + The callback will be invoked with arguments `__data_parallel_replicate__(ctx, copy_id)` + + Examples: + > sync_bn = SynchronizedBatchNorm1d(10, eps=1e-5, affine=False) + > sync_bn = DataParallelWithCallback(sync_bn, device_ids=[0, 1]) + # sync_bn.__data_parallel_replicate__ will be invoked. + """ + def __init__(self, module, device_ids=None, output_device=None, dim=0, chunk_size=None): + super(DataParallelWithCallback, self).__init__(module) + + if not torch.cuda.is_available(): + self.module = module + self.device_ids = [] + return + + if device_ids is None: + device_ids = list(range(torch.cuda.device_count())) + if output_device is None: + output_device = device_ids[0] + self.dim = dim + self.module = module + self.device_ids = device_ids + self.output_device = output_device + self.chunk_size = chunk_size + + if len(self.device_ids) == 1: + self.module.cuda(device_ids[0]) + + def forward(self, *inputs, **kwargs): + if not self.device_ids: + return self.module(*inputs, **kwargs) + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids, self.chunk_size) + if len(self.device_ids) == 1: + return self.module(*inputs[0], **kwargs[0]) + replicas = self.replicate(self.module, self.device_ids[:len(inputs)]) + outputs = self.parallel_apply(replicas, inputs, kwargs) + return self.gather(outputs, self.output_device) + + def scatter(self, inputs, kwargs, device_ids, chunk_size): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim, chunk_size=self.chunk_size) + + def replicate(self, module, device_ids): + modules = super(DataParallelWithCallback, self).replicate(module, device_ids) + execute_replication_callbacks(modules) + return modules + + +def patch_replication_callback(data_parallel): + """ + Monkey-patch an existing `DataParallel` object. Add the replication callback. + Useful when you have customized `DataParallel` implementation. + + Examples: + > sync_bn = SynchronizedBatchNorm1d(10, eps=1e-5, affine=False) + > sync_bn = DataParallel(sync_bn, device_ids=[0, 1]) + > patch_replication_callback(sync_bn) + # this is equivalent to + > sync_bn = SynchronizedBatchNorm1d(10, eps=1e-5, affine=False) + > sync_bn = DataParallelWithCallback(sync_bn, device_ids=[0, 1]) + """ + + assert isinstance(data_parallel, DataParallel) + + old_replicate = data_parallel.replicate + + @functools.wraps(old_replicate) + def new_replicate(module, device_ids): + modules = old_replicate(module, device_ids) + execute_replication_callbacks(modules) + return modules + + data_parallel.replicate = new_replicate diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/scatter_gather.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/scatter_gather.py new file mode 100644 index 0000000000..ad6fff3a54 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/scatter_gather.py @@ -0,0 +1,44 @@ +import torch +from torch.nn.parallel._functions import Scatter + + +def scatter(inputs, target_gpus, dim=0, chunk_size=None): + r""" + Slices tensors into approximately equal chunks and + distributes them across given GPUs. Duplicates + references to objects that are not tensors. + """ + def scatter_map(obj): + if isinstance(obj, torch.Tensor): + return Scatter.apply(target_gpus, chunk_size, dim, obj) + if isinstance(obj, tuple) and len(obj) > 0: + return list(zip(*map(scatter_map, obj))) + if isinstance(obj, list) and len(obj) > 0: + return list(map(list, zip(*map(scatter_map, obj)))) + if isinstance(obj, dict) and len(obj) > 0: + return list(map(type(obj), zip(*map(scatter_map, obj.items())))) + return [obj for targets in target_gpus] + + # After scatter_map is called, a scatter_map cell will exist. This cell + # has a reference to the actual function scatter_map, which has references + # to a closure that has a reference to the scatter_map cell (because the + # fn is recursive). To avoid this reference cycle, we set the function to + # None, clearing the cell + try: + res = scatter_map(inputs) + finally: + scatter_map = None + return res + + +def scatter_kwargs(inputs, kwargs, target_gpus, dim=0, chunk_size=None): + r"""Scatter with support for kwargs dictionary""" + inputs = scatter(inputs, target_gpus, dim, chunk_size) if inputs else [] + kwargs = scatter(kwargs, target_gpus, dim, chunk_size) if kwargs else [] + if len(inputs) < len(kwargs): + inputs.extend([() for _ in range(len(kwargs) - len(inputs))]) + elif len(kwargs) < len(inputs): + kwargs.extend([{} for _ in range(len(inputs) - len(kwargs))]) + inputs = tuple(inputs) + kwargs = tuple(kwargs) + return inputs, kwargs diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/unittest.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/unittest.py new file mode 100644 index 0000000000..dde4f6e12c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/sync_batchnorm/unittest.py @@ -0,0 +1,18 @@ +import unittest +import torch + + +class TorchTestCase(unittest.TestCase): + def assertTensorClose(self, x, y): + adiff = float((x - y).abs().max()) + if (y == 0).all(): + rdiff = 'NaN' + else: + rdiff = float((adiff / y).abs().max()) + + message = ( + 'Tensor close check failed\n' + 'adiff={}\n' + 'rdiff={}\n' + ).format(adiff, rdiff) + self.assertTrue(torch.allclose(x, y), message) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/test_render.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/test_render.py new file mode 100644 index 0000000000..a0f64f32ca --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/test_render.py @@ -0,0 +1,152 @@ +import torch +import pickle +import numpy as np +from models.networks.render import Render, angle2matrix, matrix2angle, P2sRt + + +def _get_suffix(filename): + """a.jpg -> jpg""" + pos = filename.rfind('.') + if pos == -1: + return '' + return filename[pos + 1:] + + +def _load(fp): + suffix = _get_suffix(fp) + if suffix == 'npy': + return np.load(fp) + elif suffix == 'pkl': + return pickle.load(open(fp, 'rb')) + + +class TestRender(Render): + + def __init__(self, opt): + super(TestRender, self).__init__(opt) + + def _parse_param(self, param, pose_noise=False, frontal=True, large_pose=False, pose=None): + """Work for both numpy and tensor""" + p_ = param[:12].reshape(3, -1) + p = p_[:, :3] + s, R, t3d = P2sRt(p_) + angle = matrix2angle(R) + original_angle = angle[0] + if frontal: + angle[0] = 0 + if angle[1] < 0: + angle[1] = 0 + p = angle2matrix(angle) * s + if pose_noise: + angle[0] = np.random.uniform(-0.258, 0.258, 1)[0] + p = angle2matrix(angle) * s + + if large_pose: + if original_angle < 0: + angle[0] = np.random.uniform(-1, -0.955, 1)[0] + else: + angle[0] = np.random.uniform(0.955, 1, 1)[0] + if angle[1] < 0: + angle[1] = 0 + p = angle2matrix(angle) * s + + offset = p_[:, -1].reshape(3, 1) + alpha_shp = param[12:52].reshape(-1, 1) + alpha_exp = param[52:-4].reshape(-1, 1) + box = param[-4:] + return p, offset, alpha_shp, alpha_exp, box, original_angle + + def rotate_render(self, params, images, M=None, with_BG=False, + pose_noise=False, large_pose=False, align=True, frontal=True, erode=True, grey_background=False, + avg_BG=True, pose=None): + + bz, c, w, h = images.size() + + face_size = self.faces.size() + self.faces_use = self.faces.expand(bz, face_size[1], face_size[2]) + + # get render color vertices and normal vertices information, get original texs + vertices = [] + vertices_out = [] + vertices_in_ori_img = [] + vertices_aligned_normal = [] + vertices_aligned_out = [] + vertices_ori_normal = [] + texs = [] + original_angles = torch.zeros(bz) + with torch.no_grad(): + for n in range(bz): + tex_a, vertice, vertice_out, vertice_in_ori_img, align_vertice, original_angle \ + = self._forward(params[n], images[n], M[n], + pose_noise=pose_noise, align=align, frontal=frontal) + vertices.append(vertice) + vertices_out.append(vertice_out) + vertices_in_ori_img.append(vertice_in_ori_img.clone()) + vertice2 = self.flip_normalize_vertices(vertice_in_ori_img.clone()) + vertices_ori_normal.append(vertice2) + vertices_aligned_out.append(align_vertice) + align_vertice_normal = self.flip_normalize_vertices(align_vertice.clone()) + vertices_aligned_normal.append(align_vertice_normal.clone()) + texs.append(tex_a) + original_angles[n] = original_angle + + vertices = torch.cat(vertices, 0) + vertices_aligned_normal = torch.cat(vertices_aligned_normal, 0) + vertices_ori_normal = torch.cat(vertices_ori_normal, 0) + + vertices_in_ori_img = torch.stack(vertices_in_ori_img, 0) + vertices_aligned_out = torch.stack(vertices_aligned_out, 0) + + texs = torch.cat(texs, 0) + + # erode the original mask and render again + rendered_images_erode = None + if erode: + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices_ori_normal, self.faces_use, + texs) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + masks_erode = self.generate_erode_mask(masks, kernal_size=15) + rendered_images = rendered_images.cpu() + if grey_background: + rendered_images_erode = masks_erode * rendered_images + else: + inv_masks_erode = (torch.ones_like(masks_erode) - (masks_erode)).float() + if avg_BG: + contentsum = torch.sum(torch.sum(masks_erode * rendered_images, 3), 2) + sumsum = torch.sum(torch.sum(masks_erode, 3), 2) + contentsum[contentsum == 0] = 0.5 + sumsum[sumsum == 0] = 1 + masked_sum = contentsum / sumsum + masked_BG = masked_sum.unsqueeze(2).unsqueeze(3).expand(rendered_images.size()) + else: + masked_BG = 0.5 + rendered_images_erode = masks_erode * rendered_images + inv_masks_erode * masked_BG + + texs_a_crop = [] + for n in range(bz): + tex_a_crop = self.get_render_from_vertices(rendered_images_erode[n], vertices_in_ori_img[n]) + texs_a_crop.append(tex_a_crop) + texs = torch.cat(texs_a_crop, 0) + + # render face to rotated pose + with torch.no_grad(): + with torch.cuda.device(self.current_gpu): + rendered_images, depths, masks, = self.renderer(vertices, self.faces_use, texs) + + rendered_images = rendered_images.cpu() + + # get rendered face vertices + texs_b = [] + for n in range(bz): + tex_b = self.get_render_from_vertices(rendered_images[n], vertices_out[n]) + texs_b.append(tex_b) + texs_b = torch.cat(texs_b, 0) + + with torch.cuda.device(self.current_gpu): + + rendered_images_double, depths2, masks2, = self.renderer(vertices_aligned_normal, self.faces_use, + texs_b) + # rendered_images: batch * 3 * h * w, masks: batch * h * w + + return rendered_images_double, self.torch_get_68_points(vertices_aligned_out), original_angles diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/util.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/util.py new file mode 100644 index 0000000000..2411fa9ba3 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/networks/util.py @@ -0,0 +1,176 @@ +"""This module contains simple helper functions """ +from __future__ import print_function +import torch +import numpy as np +from PIL import Image +import os +from math import sin, cos, atan2, asin + + +def P2sRt(P): + ''' decompositing camera matrix P. + Args: + P: (3, 4). Affine Camera Matrix. + Returns: + s: scale factor. + R: (3, 3). rotation matrix. + t2d: (2,). 2d translation. + ''' + t3d = P[:, 3] + R1 = P[0:1, :3] + R2 = P[1:2, :3] + s = (np.linalg.norm(R1) + np.linalg.norm(R2)) / 2.0 + r1 = R1 / np.linalg.norm(R1) + r2 = R2 / np.linalg.norm(R2) + r3 = np.cross(r1, r2) + + R = np.concatenate((r1, r2, r3), 0) + return s, R, t3d + + +def matrix2angle(R): + ''' compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf + Args: + R: (3,3). rotation matrix + Returns: + x: yaw + y: pitch + z: roll + ''' + # assert(isRotationMatrix(R)) + + if R[2, 0] != 1 and R[2, 0] != -1: + x = -asin(max(-1, min(R[2, 0], 1))) + y = atan2(R[2, 1] / cos(x), R[2, 2] / cos(x)) + z = atan2(R[1, 0] / cos(x), R[0, 0] / cos(x)) + + else: # Gimbal lock + z = 0 # can be anything + if R[2, 0] == -1: + x = np.pi / 2 + y = z + atan2(R[0, 1], R[0, 2]) + else: + x = -np.pi / 2 + y = -z + atan2(-R[0, 1], -R[0, 2]) + + return [x, y, z] + + +def angle2matrix(angles): + ''' get rotation matrix from three rotation angles(radian). The same as in 3DDFA. + Args: + angles: [3,]. x, y, z angles + x: yaw. + y: pitch. + z: roll. + Returns: + R: 3x3. rotation matrix. + ''' + # x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2]) + # x, y, z = angles[0], angles[1], angles[2] + y, x, z = angles[0], angles[1], angles[2] + + # x + Rx = np.array([[1, 0, 0], + [0, cos(x), -sin(x)], + [0, sin(x), cos(x)]]) + # y + Ry = np.array([[cos(y), 0, sin(y)], + [0, 1, 0], + [-sin(y), 0, cos(y)]]) + # z + Rz = np.array([[cos(z), -sin(z), 0], + [sin(z), cos(z), 0], + [0, 0, 1]]) + R = Rz.dot(Ry).dot(Rx) + return R.astype(np.float32) + + +def tensor2im(input_image, imtype=np.uint8): + """"Converts a Tensor array into a numpy image array. + + Parameters: + input_image (tensor) -- the input image tensor array + imtype (type) -- the desired type of the converted numpy array + """ + if not isinstance(input_image, np.ndarray): + if isinstance(input_image, torch.Tensor): # get the data from a variable + image_tensor = input_image.data + else: + return input_image + image_numpy = image_tensor[0].cpu().float().numpy() # convert it into a numpy array + if image_numpy.shape[0] == 1: # grayscale to RGB + image_numpy = np.tile(image_numpy, (3, 1, 1)) + image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + 1) / 2.0 * 255.0 # post-processing: tranpose and scaling + else: # if it is a numpy array, do nothing + image_numpy = input_image + return image_numpy.astype(imtype) + + +def diagnose_network(net, name='network'): + """Calculate and print the mean of average absolute(gradients) + + Parameters: + net (torch network) -- Torch network + name (str) -- the name of the network + """ + mean = 0.0 + count = 0 + for param in net.parameters(): + if param.grad is not None: + mean += torch.mean(torch.abs(param.grad.data)) + count += 1 + if count > 0: + mean = mean / count + print(name) + print(mean) + + +def save_image(image_numpy, image_path): + """Save a numpy image to the disk + + Parameters: + image_numpy (numpy array) -- input numpy array + image_path (str) -- the path of the image + """ + image_pil = Image.fromarray(image_numpy) + image_pil.save(image_path) + + +def print_numpy(x, val=True, shp=False): + """Print the mean, min, max, median, std, and size of a numpy array + + Parameters: + val (bool) -- if print the values of the numpy array + shp (bool) -- if print the shape of the numpy array + """ + x = x.astype(np.float64) + if shp: + print('shape,', x.shape) + if val: + x = x.flatten() + print('mean = %3.3f, min = %3.3f, max = %3.3f, median = %3.3f, std=%3.3f' % ( + np.mean(x), np.min(x), np.max(x), np.median(x), np.std(x))) + + +def mkdirs(paths): + """create empty directories if they don't exist + + Parameters: + paths (str list) -- a list of directory paths + """ + if isinstance(paths, list) and not isinstance(paths, str): + for path in paths: + mkdir(path) + else: + mkdir(paths) + + +def mkdir(path): + """create a single empty directory if it didn't exist + + Parameters: + path (str) -- a single directory path + """ + if not os.path.exists(path): + os.makedirs(path) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotate_model.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotate_model.py new file mode 100644 index 0000000000..6b32f129a6 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotate_model.py @@ -0,0 +1,330 @@ +import torch +import algorithm.Rotate_and_Render.models.networks as networks +import algorithm.Rotate_and_Render.util.util as util +import os + + +class RotateModel(torch.nn.Module): + @staticmethod + def modify_commandline_options(parser, is_train): + networks.modify_commandline_options(parser, is_train) + return parser + + def __init__(self, opt): + super(RotateModel, self).__init__() + self.opt = opt + self.save_dir = os.path.join(opt.checkpoints_dir, opt.name) + self.FloatTensor = torch.cuda.FloatTensor if self.use_gpu() \ + else torch.FloatTensor + self.ByteTensor = torch.cuda.ByteTensor if self.use_gpu() \ + else torch.ByteTensor + self.real_image = torch.zeros(opt.batchSize, 3, opt.crop_size, opt.crop_size) + self.input_semantics = torch.zeros(opt.batchSize, 3, opt.crop_size, opt.crop_size) + + self.netG, self.netD, self.netE, self.netD_rotate = self.initialize_networks(opt) + + # set loss functions + if opt.isTrain: + self.criterionGAN = networks.GANLoss( + opt.gan_mode, tensor=self.FloatTensor, opt=self.opt) + self.criterionFeat = torch.nn.L1Loss() + if not opt.no_vgg_loss: + self.criterionVGG = networks.VGGLoss(self.opt) + if opt.use_vae: + self.KLDLoss = networks.KLDLoss() + + # Entry point for all calls involving forward pass + # of deep networks. We used this approach since DataParallel module + # can't parallelize custom functions, we branch to different + # routines based on |mode|. + # |data|: dictionary of the input data + + def forward(self, data, mode): + real_image = data['image'] + input_semantics = data['mesh'] + if self.opt.use_rotated_mesh: + rotated_mesh = data['rotated_mesh'] + else: + rotated_mesh = None + if mode == 'generator': + g_loss, generated = self.compute_generator_loss( + input_semantics, real_image, netD=self.netD, mode=mode, no_ganFeat_loss=self.opt.no_ganFeat_loss, + no_vgg_loss=self.opt.no_vgg_loss, lambda_D=self.opt.lambda_D) + return g_loss, generated + if mode == 'generator_rotated': + g_loss, generated = self.compute_generator_loss( + rotated_mesh, real_image, netD=self.netD_rotate, mode=mode, no_ganFeat_loss=True, + no_vgg_loss=self.opt.no_vgg_loss, lambda_D=self.opt.lambda_rotate_D) + return g_loss, generated + elif mode == 'discriminator': + d_loss = self.compute_discriminator_loss( + input_semantics, real_image, netD=self.netD, lambda_D=self.opt.lambda_D) + return d_loss + elif mode == 'discriminator_rotated': + d_loss = self.compute_discriminator_loss( + rotated_mesh, real_image, self.netD_rotate, lambda_D=self.opt.lambda_rotate_D) + return d_loss + elif mode == 'encode_only': + z, mu, logvar = self.encode_z(real_image) + return mu, logvar + elif mode == 'inference': + with torch.no_grad(): + fake_image, _ = self.generate_fake(input_semantics, real_image) + fake_rotate, _ = self.generate_fake(rotated_mesh, real_image) + return fake_image, fake_rotate + else: + raise ValueError("|mode| is invalid") + + def create_optimizers(self, opt): + G_params = list(self.netG.parameters()) + if opt.use_vae: + G_params += list(self.netE.parameters()) + if opt.isTrain: + if opt.train_rotate: + D_params = list(self.netD.parameters()) + list(self.netD_rotate.parameters()) + else: + D_params = self.netD.parameters() + + if opt.no_TTUR: + beta1, beta2 = opt.beta1, opt.beta2 + G_lr, D_lr = opt.lr, opt.lr + else: + beta1, beta2 = 0, 0.9 + G_lr, D_lr = opt.lr / 2, opt.lr * 2 + + optimizer_G = torch.optim.Adam(G_params, lr=G_lr, betas=(beta1, beta2)) + optimizer_D = torch.optim.Adam(D_params, lr=D_lr, betas=(beta1, beta2)) + + return optimizer_G, optimizer_D + + def save(self, epoch): + util.save_network(self.netG, 'G', epoch, self.opt) + util.save_network(self.netD, 'D', epoch, self.opt) + if self.opt.train_rotate: + util.save_network(self.netD_rotate, 'D_rotate', epoch, self.opt) + if self.opt.use_vae: + util.save_network(self.netE, 'E', epoch, self.opt) + + ############################################################################ + # Private helper methods + ############################################################################ + + def initialize_networks(self, opt): + + netG = networks.define_G(opt) + netD = networks.define_D(opt) if opt.isTrain else None + netD_rotate = networks.define_D(opt) if opt.isTrain else None + netE = networks.define_E(opt) if opt.use_vae else None + pretrained_path = '' + if not opt.isTrain or opt.continue_train: + self.load_network(netG, 'G', opt.which_epoch, pretrained_path) + if opt.isTrain and not opt.noload_D: + self.load_network(netD, 'D', opt.which_epoch, pretrained_path) + self.load_network(netD_rotate, 'D_rotate', opt.which_epoch, pretrained_path) + if opt.use_vae: + self.load_network(netE, 'E', opt.which_epoch, pretrained_path) + else: + + if opt.load_separately: + netG = self.load_separately(netG, 'G', opt) + if not opt.noload_D: + netD = self.load_separately(netD, 'D', opt) + netD_rotate = self.load_separately(netD_rotate, 'D_rotate', opt) + if opt.use_vae: + netE = self.load_separately(netE, 'E', opt) + + return netG, netD, netE, netD_rotate + + # preprocess the input, such as moving the tensors to GPUs and + # transforming the label map to one-hot encoding + + def compute_generator_loss(self, input_semantics, real_image, netD, mode, no_ganFeat_loss=False, no_vgg_loss=False, + lambda_D=1): + G_losses = {} + + fake_image, KLD_loss = self.generate_fake( + input_semantics, real_image, compute_kld_loss=self.opt.use_vae) + + if self.opt.use_vae: + G_losses['KLD'] = KLD_loss + + pred_fake, pred_real = self.discriminate( + input_semantics, fake_image, real_image, netD) + + G_losses['GAN'] = self.criterionGAN(pred_fake, True, + for_discriminator=False) * lambda_D + + if not no_ganFeat_loss: + num_D = len(pred_fake) + GAN_Feat_loss = self.FloatTensor(1).fill_(0) + for i in range(num_D): # for each discriminator + # last output is the final prediction, so we exclude it + num_intermediate_outputs = len(pred_fake[i]) - 1 + for j in range(num_intermediate_outputs): # for each layer output + unweighted_loss = self.criterionFeat( + pred_fake[i][j], pred_real[i][j].detach()) + if j == 0: + unweighted_loss *= self.opt.lambda_image + GAN_Feat_loss += unweighted_loss * self.opt.lambda_feat / num_D + G_losses['GAN_Feat'] = GAN_Feat_loss + + if not no_vgg_loss: + if mode == 'generator_rotated': + num = 2 + else: + num = 0 + G_losses['VGG'] = self.criterionVGG(fake_image, real_image, num) * self.opt.lambda_vgg + + return G_losses, fake_image + + def compute_discriminator_loss(self, input_semantics, real_image, netD, lambda_D=1): + D_losses = {} + with torch.no_grad(): + fake_image, _ = self.generate_fake(input_semantics, real_image) + fake_image = fake_image.detach() + fake_image.requires_grad_() + + pred_fake, pred_real = self.discriminate( + input_semantics, fake_image, real_image, netD) + + D_losses['D_Fake'] = self.criterionGAN(pred_fake, False, + for_discriminator=True) * lambda_D + + D_losses['D_real'] = self.criterionGAN(pred_real, True, + for_discriminator=True) * lambda_D + + return D_losses + + def encode_z(self, real_image): + mu, logvar = self.netE(real_image) + z = self.reparameterize(mu, logvar) + return z, mu, logvar + + def generate_fake(self, input_semantics, real_image, compute_kld_loss=False): + z = None + KLD_loss = None + if self.opt.use_vae: + z, mu, logvar = self.encode_z(real_image) + if compute_kld_loss: + KLD_loss = self.KLDLoss(mu, logvar) * self.opt.lambda_kld + + fake_image = self.netG(input_semantics, z=z) + + assert (not compute_kld_loss) or self.opt.use_vae, \ + "You cannot compute KLD loss if opt.use_vae == False" + + return fake_image, KLD_loss + + # Given fake and real image, return the prediction of discriminator + # for each fake and real image. + + def discriminate(self, input_semantics, fake_image, real_image, netD): + if self.opt.D_input == "concat": + fake_concat = torch.cat([input_semantics, fake_image], dim=1) + real_concat = torch.cat([input_semantics, real_image], dim=1) + else: + fake_concat = fake_image + real_concat = real_image + + # In Batch Normalization, the fake and real images are + # recommended to be in the same batch to avoid disparate + # statistics in fake and real images. + # So both fake and real images are fed to D all at once. + fake_and_real = torch.cat([fake_concat, real_concat], dim=0) + + discriminator_out = netD(fake_and_real) + + pred_fake, pred_real = self.divide_pred(discriminator_out) + + return pred_fake, pred_real + + # Take the prediction of fake and real images from the combined batch + def divide_pred(self, pred): + # the prediction contains the intermediate outputs of multiscale GAN, + # so it's usually a list + if type(pred) == list: + fake = [] + real = [] + for p in pred: + fake.append([tensor[:tensor.size(0) // 2] for tensor in p]) + real.append([tensor[tensor.size(0) // 2:] for tensor in p]) + else: + fake = pred[:pred.size(0) // 2] + # rotate_fake = pred[pred.size(0) // 3: pred.size(0) * 2 // 3] + real = pred[pred.size(0) // 2:] + + return fake, real + + def get_edges(self, t): + edge = self.ByteTensor(t.size()).zero_() + edge[:, :, :, 1:] = edge[:, :, :, 1:] | (t[:, :, :, 1:] != t[:, :, :, :-1]) + edge[:, :, :, :-1] = edge[:, :, :, :-1] | (t[:, :, :, 1:] != t[:, :, :, :-1]) + edge[:, :, 1:, :] = edge[:, :, 1:, :] | (t[:, :, 1:, :] != t[:, :, :-1, :]) + edge[:, :, :-1, :] = edge[:, :, :-1, :] | (t[:, :, 1:, :] != t[:, :, :-1, :]) + return edge.float() + + def load_separately(self, network, network_label, opt): + load_path = None + if network_label == 'G': + load_path = opt.G_pretrain_path + elif network_label == 'D': + + load_path = opt.D_pretrain_path + elif network_label == 'D_rotate': + load_path = opt.D_rotate_pretrain_path + elif network_label == 'E': + load_path = opt.E_pretrain_path + + if load_path is not None: + if os.path.isfile(load_path): + print("=> loading checkpoint '{}'".format(load_path)) + checkpoint = torch.load(load_path) + util.copy_state_dict(checkpoint, network) + else: + print("no load_path") + return network + + def load_network(self, network, network_label, epoch_label, save_dir=''): + save_filename = '%s_net_%s.pth' % (epoch_label, network_label) + if not save_dir: + save_dir = self.save_dir + save_path = os.path.join(save_dir, save_filename) + if not os.path.isfile(save_path): + print('%s not exists yet!' % save_path) + if network_label == 'G': + raise ('Generator must exist!') + else: + # network.load_state_dict(torch.load(save_path)) + try: + network.load_state_dict(torch.load(save_path)) + except: + pretrained_dict = torch.load(save_path) + model_dict = network.state_dict() + try: + pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict} + network.load_state_dict(pretrained_dict) + if self.opt.verbose: + print( + 'Pretrained network %s has excessive layers; Only loading layers that are used' % network_label) + except: + print('Pretrained network %s has fewer layers; The following are not initialized:' % network_label) + for k, v in pretrained_dict.items(): + if v.size() == model_dict[k].size(): + model_dict[k] = v + + not_initialized = set() + + for k, v in model_dict.items(): + if k not in pretrained_dict or v.size() != pretrained_dict[k].size(): + not_initialized.add(k.split('.')[0]) + + print(sorted(not_initialized)) + network.load_state_dict(model_dict) + + def reparameterize(self, mu, logvar): + std = torch.exp(0.5 * logvar) + eps = torch.randn_like(std) + return eps.mul(std) + mu + + def use_gpu(self): + return len(self.opt.gpu_ids) > 0 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotatespade_model.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotatespade_model.py new file mode 100644 index 0000000000..826ae6a46d --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/rotatespade_model.py @@ -0,0 +1,391 @@ +import torch +from . import networks +from ..util import util +from ..data import curve +import numpy as np +import os + + +class RotateSPADEModel(torch.nn.Module): + @staticmethod + def modify_commandline_options(parser, is_train): + networks.modify_commandline_options(parser, is_train) + return parser + + def __init__(self, opt): + super(RotateSPADEModel, self).__init__() + self.opt = opt + self.save_dir = os.path.join(opt.checkpoints_dir, opt.name) + self.FloatTensor = torch.cuda.FloatTensor if self.use_gpu() \ + else torch.FloatTensor + self.ByteTensor = torch.cuda.ByteTensor if self.use_gpu() \ + else torch.ByteTensor + self.real_image = torch.zeros(opt.batchSize, 3, opt.crop_size, opt.crop_size) + self.input_semantics = torch.zeros(opt.batchSize, 3, opt.crop_size, opt.crop_size) + + self.netG, self.netD, self.netE, self.netD_rotate = self.initialize_networks(opt) + + # set loss functions + if opt.isTrain: + self.criterionGAN = networks.GANLoss( + opt.gan_mode, tensor=self.FloatTensor, opt=self.opt) + self.criterionFeat = torch.nn.L1Loss() + if not opt.no_vgg_loss: + self.criterionVGG = networks.VGGLoss(self.opt) + if opt.use_vae: + self.KLDLoss = networks.KLDLoss() + + def landmark_68_to_5(self, t68): + le = t68[36:42, :].mean(axis=0, keepdims=True) + re = t68[42:48, :].mean(axis=0, keepdims=True) + no = t68[31:32, :] + lm = t68[48:49, :] + rm = t68[54:55, :] + t5 = np.concatenate([le, re, no, lm, rm], axis=0) + t5 = t5.reshape(10) + t5 = torch.from_numpy(t5).unsqueeze(0).cuda() + return t5 + + def get_seg_map(self, landmarks, no_guassian=False, size=256, original_angles=None): + landmarks = landmarks[:, :, :2].cpu().numpy().astype(np.float) + all_heatmap = [] + all_orig_heatmap = [] + if original_angles is None: + original_angles = torch.zeros(landmarks.shape[0]) + # key_points = [] + for i in range(landmarks.shape[0]): + heatmap = curve.points_to_heatmap_68points(landmarks[i], 13, size, self.opt.heatmap_size) + + heatmap2 = curve.combine_map(heatmap, no_guassian=no_guassian) + if self.opt.isTrain: + if np.random.randint(2): + heatmap = np.zeros_like(heatmap) + else: + if torch.abs(original_angles[i]) < 0.255: + heatmap = np.zeros_like(heatmap) + + all_heatmap.append(heatmap2) + all_orig_heatmap.append(heatmap) + # key_points.append(self.landmark_68_to_5(landmarks[i])) + all_heatmap = np.stack(all_heatmap, axis=0) + all_orig_heatmap = np.stack(all_orig_heatmap, axis=0) + all_heatmap = torch.from_numpy(all_heatmap.astype(np.float32)).cuda() + all_orig_heatmap = torch.from_numpy(all_orig_heatmap.astype(np.float32)).cuda() + all_orig_heatmap = all_orig_heatmap.permute(0, 3, 1, 2) + all_orig_heatmap[all_orig_heatmap > 0] = 2.0 + return all_heatmap, all_orig_heatmap + + # Entry point for all calls involving forward pass + # of deep networks. We used this approach since DataParallel module + # can't parallelize custom functions, we branch to different + # routines based on |mode|. + # |data|: dictionary of the input data + + def forward(self, data, mode): + real_image = data['image'] + + orig_landmarks = data['orig_landmarks'] + rotated_landmarks = data['rotated_landmarks'] + original_angles = data['original_angles'] + self.orig_seg, orig_seg_all = \ + self.get_seg_map(orig_landmarks, self.opt.no_gaussian_landmark, self.opt.crop_size, original_angles) + self.rotated_seg, rotated_seg_all = \ + self.get_seg_map(rotated_landmarks, self.opt.no_gaussian_landmark, self.opt.crop_size, original_angles) + + input_semantics = data['mesh'] + rotated_mesh = data['rotated_mesh'] + if self.opt.label_mask: + input_semantics = (input_semantics + orig_seg_all[:, 4].unsqueeze(1) + orig_seg_all[:, 0].unsqueeze(1)) + rotated_mesh = (rotated_mesh + rotated_seg_all[:, 4].unsqueeze(1) + rotated_seg_all[:, 0].unsqueeze(1)) + input_semantics[input_semantics >= 1] = 0 + rotated_mesh[rotated_mesh >= 1] = 0 + + if mode == 'generator': + g_loss, generated = self.compute_generator_loss( + input_semantics, real_image, self.orig_seg, netD=self.netD, mode=mode, + no_ganFeat_loss=self.opt.no_ganFeat_loss, + no_vgg_loss=self.opt.no_vgg_loss, lambda_D=self.opt.lambda_D) + return g_loss, generated, input_semantics + if mode == 'generator_rotated': + g_loss, generated = self.compute_generator_loss( + rotated_mesh, real_image, self.rotated_seg, netD=self.netD_rotate, mode=mode, no_ganFeat_loss=True, + no_vgg_loss=self.opt.no_vgg_loss, lambda_D=self.opt.lambda_rotate_D) + return g_loss, generated, rotated_mesh + elif mode == 'discriminator': + d_loss = self.compute_discriminator_loss( + input_semantics, real_image, self.orig_seg, netD=self.netD, lambda_D=self.opt.lambda_D) + return d_loss + elif mode == 'discriminator_rotated': + d_loss = self.compute_discriminator_loss( + rotated_mesh, real_image, self.rotated_seg, self.netD_rotate, lambda_D=self.opt.lambda_rotate_D) + return d_loss + elif mode == 'encode_only': + z, mu, logvar = self.encode_z(real_image) + return mu, logvar + elif mode == 'inference': + with torch.no_grad(): + if self.opt.label_mask: + rotated_mesh = ( + rotated_mesh + rotated_seg_all[:, 4].unsqueeze(1) + rotated_seg_all[:, 0].unsqueeze(1)) + rotated_mesh[rotated_mesh >= 1] = 0 + fake_image, _ = self.generate_fake(input_semantics, real_image, self.orig_seg) + fake_rotate, _ = self.generate_fake(rotated_mesh, real_image, self.rotated_seg) + + return fake_image, fake_rotate + else: + raise ValueError("|mode| is invalid") + + def create_optimizers(self, opt): + G_params = list(self.netG.parameters()) + if opt.use_vae: + G_params += list(self.netE.parameters()) + if opt.isTrain: + if opt.train_rotate: + D_params = list(self.netD.parameters()) + list(self.netD_rotate.parameters()) + else: + D_params = self.netD.parameters() + + if opt.no_TTUR: + beta1, beta2 = opt.beta1, opt.beta2 + G_lr, D_lr = opt.lr, opt.lr + else: + beta1, beta2 = 0, 0.9 + G_lr, D_lr = opt.lr / 2, opt.lr * 2 + + optimizer_G = torch.optim.Adam(G_params, lr=G_lr, betas=(beta1, beta2)) + optimizer_D = torch.optim.Adam(D_params, lr=D_lr, betas=(beta1, beta2)) + + return optimizer_G, optimizer_D + + def save(self, epoch): + util.save_network(self.netG, 'G', epoch, self.opt) + util.save_network(self.netD, 'D', epoch, self.opt) + if self.opt.train_rotate: + util.save_network(self.netD_rotate, 'D_rotate', epoch, self.opt) + if self.opt.use_vae: + util.save_network(self.netE, 'E', epoch, self.opt) + + ############################################################################ + # Private helper methods + ############################################################################ + + def initialize_networks(self, opt): + + netG = networks.define_G(opt) + netD = networks.define_D(opt) if opt.isTrain else None + netD_rotate = networks.define_D(opt) if opt.isTrain else None + netE = networks.define_E(opt) if opt.use_vae else None + pretrained_path = '' + if not opt.isTrain or opt.continue_train: + self.load_network(netG, 'G', opt.which_epoch, pretrained_path) + if opt.isTrain and not opt.noload_D: + self.load_network(netD, 'D', opt.which_epoch, pretrained_path) + self.load_network(netD_rotate, 'D_rotate', opt.which_epoch, pretrained_path) + if opt.use_vae: + self.load_network(netE, 'E', opt.which_epoch, pretrained_path) + else: + + if opt.load_separately: + netG = self.load_separately(netG, 'G', opt) + if not opt.noload_D: + netD = self.load_separately(netD, 'D', opt) + netD_rotate = self.load_separately(netD_rotate, 'D_rotate', opt) + if opt.use_vae: + netE = self.load_separately(netE, 'E', opt) + + return netG, netD, netE, netD_rotate + + # preprocess the input, such as moving the tensors to GPUs and + # transforming the label map to one-hot encoding + + def compute_generator_loss(self, input_semantics, real_image, seg, netD, mode, no_ganFeat_loss=False, + no_vgg_loss=False, lambda_D=1): + G_losses = {} + + fake_image, KLD_loss = self.generate_fake( + input_semantics, real_image, seg, compute_kld_loss=self.opt.use_vae) + + if self.opt.use_vae: + G_losses['KLD'] = KLD_loss + + pred_fake, pred_real = self.discriminate( + input_semantics, fake_image, real_image, seg, netD) + + G_losses['GAN'] = self.criterionGAN(pred_fake, True, + for_discriminator=False) * lambda_D + + if not no_ganFeat_loss: + num_D = len(pred_fake) + GAN_Feat_loss = self.FloatTensor(1).fill_(0) + for i in range(num_D): # for each discriminator + # last output is the final prediction, so we exclude it + num_intermediate_outputs = len(pred_fake[i]) - 1 + for j in range(num_intermediate_outputs): # for each layer output + unweighted_loss = self.criterionFeat( + pred_fake[i][j], pred_real[i][j].detach()) + if j == 0: + unweighted_loss *= self.opt.lambda_image + GAN_Feat_loss += unweighted_loss * self.opt.lambda_feat / num_D + G_losses['GAN_Feat'] = GAN_Feat_loss + + if not no_vgg_loss: + if mode == 'generator_rotated': + num = 2 + else: + num = 0 + G_losses['VGG'] = self.criterionVGG(fake_image, real_image, num) * self.opt.lambda_vgg + + return G_losses, fake_image + + def compute_discriminator_loss(self, input_semantics, real_image, seg, netD, lambda_D=1): + D_losses = {} + with torch.no_grad(): + fake_image, _ = self.generate_fake(input_semantics, real_image, seg) + fake_image = fake_image.detach() + fake_image.requires_grad_() + + pred_fake, pred_real = self.discriminate( + input_semantics, fake_image, real_image, seg, netD) + + D_losses['D_Fake'] = self.criterionGAN(pred_fake, False, + for_discriminator=True) * lambda_D + + D_losses['D_real'] = self.criterionGAN(pred_real, True, + for_discriminator=True) * lambda_D + + return D_losses + + def encode_z(self, real_image): + mu, logvar = self.netE(real_image) + z = self.reparameterize(mu, logvar) + return z, mu, logvar + + def generate_fake(self, input_semantics, real_image, seg, compute_kld_loss=False): + z = None + KLD_loss = None + if self.opt.use_vae: + z, mu, logvar = self.encode_z(real_image) + if compute_kld_loss: + KLD_loss = self.KLDLoss(mu, logvar) * self.opt.lambda_kld + + fake_image = self.netG(input_semantics, seg) + + assert (not compute_kld_loss) or self.opt.use_vae, \ + "You cannot compute KLD loss if opt.use_vae == False" + + return fake_image, KLD_loss + + # Given fake and real image, return the prediction of discriminator + # for each fake and real image. + + def discriminate(self, input_semantics, fake_image, real_image, seg, netD): + if self.opt.D_input == "concat": + fake_concat = torch.cat([seg, fake_image], dim=1) + real_concat = torch.cat([self.orig_seg, real_image], dim=1) + else: + fake_concat = fake_image + real_concat = real_image + + # In Batch Normalization, the fake and real images are + # recommended to be in the same batch to avoid disparate + # statistics in fake and real images. + # So both fake and real images are fed to D all at once. + fake_and_real = torch.cat([fake_concat, real_concat], dim=0) + + discriminator_out = netD(fake_and_real) + + pred_fake, pred_real = self.divide_pred(discriminator_out) + + return pred_fake, pred_real + + # Take the prediction of fake and real images from the combined batch + def divide_pred(self, pred): + # the prediction contains the intermediate outputs of multiscale GAN, + # so it's usually a list + if type(pred) == list: + fake = [] + real = [] + for p in pred: + fake.append([tensor[:tensor.size(0) // 2] for tensor in p]) + real.append([tensor[tensor.size(0) // 2:] for tensor in p]) + else: + fake = pred[:pred.size(0) // 2] + # rotate_fake = pred[pred.size(0) // 3: pred.size(0) * 2 // 3] + real = pred[pred.size(0) // 2:] + + return fake, real + + def get_edges(self, t): + edge = self.ByteTensor(t.size()).zero_() + edge[:, :, :, 1:] = edge[:, :, :, 1:] | (t[:, :, :, 1:] != t[:, :, :, :-1]) + edge[:, :, :, :-1] = edge[:, :, :, :-1] | (t[:, :, :, 1:] != t[:, :, :, :-1]) + edge[:, :, 1:, :] = edge[:, :, 1:, :] | (t[:, :, 1:, :] != t[:, :, :-1, :]) + edge[:, :, :-1, :] = edge[:, :, :-1, :] | (t[:, :, 1:, :] != t[:, :, :-1, :]) + return edge.float() + + def load_separately(self, network, network_label, opt): + load_path = None + if network_label == 'G': + load_path = opt.G_pretrain_path + elif network_label == 'D': + + load_path = opt.D_pretrain_path + elif network_label == 'D_rotate': + load_path = opt.D_rotate_pretrain_path + elif network_label == 'E': + load_path = opt.E_pretrain_path + + if load_path is not None: + if os.path.isfile(load_path): + print("=> loading checkpoint '{}'".format(load_path)) + checkpoint = torch.load(load_path) + util.copy_state_dict(checkpoint, network) + else: + print("no load_path") + return network + + def load_network(self, network, network_label, epoch_label, save_dir=''): + save_filename = '%s_net_%s.pth' % (epoch_label, network_label) + if not save_dir: + save_dir = self.save_dir + save_path = os.path.join(save_dir, save_filename) + if not os.path.isfile(save_path): + print('%s not exists yet!' % save_path) + if network_label == 'G': + raise ('Generator must exist!') + else: + # network.load_state_dict(torch.load(save_path)) + try: + network.load_state_dict(torch.load(save_path)) + except: + pretrained_dict = torch.load(save_path) + model_dict = network.state_dict() + try: + pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict} + network.load_state_dict(pretrained_dict) + if self.opt.verbose: + print( + 'Pretrained network %s has excessive layers; Only loading layers that are used' % network_label) + except: + print('Pretrained network %s has fewer layers; The following are not initialized:' % network_label) + + for k, v in pretrained_dict.items(): + if v.size() == model_dict[k].size(): + model_dict[k] = v + + not_initialized = set() + + for k, v in model_dict.items(): + if k not in pretrained_dict or v.size() != pretrained_dict[k].size(): + not_initialized.add(k.split('.')[0]) + + print(sorted(not_initialized)) + network.load_state_dict(model_dict) + + def reparameterize(self, mu, logvar): + std = torch.exp(0.5 * logvar) + eps = torch.randn_like(std) + return eps.mul(std) + mu + + def use_gpu(self): + return len(self.opt.gpu_ids) > 0 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/test_model.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/test_model.py new file mode 100644 index 0000000000..c9e9a17605 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/models/test_model.py @@ -0,0 +1,58 @@ +import torch +from . import networks +from .rotatespade_model import RotateSPADEModel + + +class TestModel(RotateSPADEModel): + @staticmethod + def modify_commandline_options(parser, is_train): + networks.modify_commandline_options(parser, is_train) + return parser + + def __init__(self, opt): + super(TestModel, self).__init__(opt) + + def forward(self, data, mode): + if mode == 'single': + real_image = data['image'] + rotated_landmarks = data['rotated_landmarks'] + original_angles = data['original_angles'] + self.rotated_seg, rotated_seg_all = \ + self.get_seg_map(rotated_landmarks, self.opt.no_gaussian_landmark, self.opt.crop_size, original_angles) + rotated_mesh = data['rotated_mesh'] + if self.opt.label_mask: + rotated_mesh = (rotated_mesh + rotated_seg_all[:, 4].unsqueeze(1) + rotated_seg_all[:, 0].unsqueeze(1)) + rotated_mesh[rotated_mesh >= 1] = 0 + with torch.no_grad(): + fake_rotate, _ = self.generate_fake(rotated_mesh, real_image, self.rotated_seg) + + return fake_rotate + + else: + real_image = data['image'] + + orig_landmarks = data['orig_landmarks'] + rotated_landmarks = data['rotated_landmarks'] + orig_seg, orig_seg_all = self.get_seg_map(orig_landmarks, self.opt.no_gaussian_landmark, self.opt.crop_size) + rotated_seg, rotated_seg_all = self.get_seg_map(rotated_landmarks, self.opt.no_gaussian_landmark, + self.opt.crop_size) + + input_semantics = data['mesh'] + rotated_mesh = data['rotated_mesh'] + # BG = data['BG'] + + if self.opt.label_mask: + input_semantics = (input_semantics + orig_seg_all[:, 4].unsqueeze(1) + orig_seg_all[:, 0].unsqueeze(1)) + rotated_mesh = (rotated_mesh + rotated_seg_all[:, 4].unsqueeze(1) + rotated_seg_all[:, 0].unsqueeze(1)) + input_semantics[input_semantics >= 1] = 0 + rotated_mesh[rotated_mesh >= 1] = 0 + + with torch.no_grad(): + if self.opt.label_mask: + rotated_mesh = ( + rotated_mesh + rotated_seg_all[:, 4].unsqueeze(1) + rotated_seg_all[:, 0].unsqueeze(1)) + rotated_mesh[rotated_mesh >= 1] = 0 + fake_image, _ = self.generate_fake(input_semantics, real_image, self.orig_seg) + fake_rotate, _ = self.generate_fake(rotated_mesh, real_image, self.rotated_seg) + + return fake_image, fake_rotate diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/base_options.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/base_options.py new file mode 100644 index 0000000000..8528a58620 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/base_options.py @@ -0,0 +1,243 @@ +import sys +import argparse +import math +import os +from ..util import util +import torch +from algorithm.Rotate_and_Render import models +from algorithm.Rotate_and_Render import data +import pickle +__all__ = ['math'] + + +class BaseOptions(): + def __init__(self): + self.initialized = False + # self.isTrain=False + + def initialize(self, parser): + # experiment specifics + parser.add_argument('--name', type=str, default='mesh2face', + help='name of the experiment. It decides where to store samples and models') + + parser.add_argument('--gpu_ids', type=str, default='0', nargs='+', help='useless') + parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here') + parser.add_argument('--model', type=str, default='rotate', help='which model to use, rotate|rotatespade') + parser.add_argument('--trainer', type=str, default='rotate', help='which trainer to use, rotate|rotatespade') + parser.add_argument('--norm_G', type=str, default='spectralsyncbatch', + help='instance normalization or batch normalization') + parser.add_argument('--norm_D', type=str, default='spectralinstance', + help='instance normalization or batch normalization') + parser.add_argument('--norm_E', type=str, default='spectralinstance', + help='instance normalization or batch normalization') + parser.add_argument('--phase', type=str, default='test', help='train, val, test, etc') + parser.add_argument('--device_count', type=int, default=1, help='the total number of gpus to use') # 2 + parser.add_argument('--render_thread', type=int, default=1, help='number of gpus used for rendering') # 1 + parser.add_argument('--chunk_size', default=1, type=int, nargs='+', + help='specify the batch size on each training gpu. Training gpu # = device_count - render_thread') + # input/output sizes + parser.add_argument('--batchSize', type=int, default=4, help='input batch size') + parser.add_argument('--preprocess_mode', type=str, default='resize_and_crop', + help='scaling and cropping of images at load time.', choices=("resize_and_crop", "crop", + "scale_width", + "scale_width_and_crop", + "scale_shortside", + "scale_shortside_and_crop", + "fixed", + "none")) + parser.add_argument('--load_size', type=int, default=400, + help='Scale images to this size. The final image will be cropped to --crop_size.') + parser.add_argument('--crop_size', type=int, default=256, + help='Crop to the width of crop_size (after initially scaling the images to load_size.)') + parser.add_argument('--aspect_ratio', type=float, default=1.0, + help='The ratio width/height. The final height of the load image will be crop_size/aspect_ratio') + parser.add_argument('--label_nc', type=int, default=5, + help='# of input label classes without unknown class. If you have unknown class as class label, ' + 'specify --contain_dopntcare_label.') + parser.add_argument('--contain_dontcare_label', action='store_true', + help='if the label map contains dontcare label (dontcare=255)') + parser.add_argument('--output_nc', type=int, default=3, help='# of output image channels') + parser.add_argument('--use_BG', action='store_true', help='') + parser.add_argument('--use_vae', action='store_true', help='') + # for setting inputs + parser.add_argument('--dataset', type=str, default='example', help='dataset') + parser.add_argument('--dataset_mode', type=str, default='allface') + parser.add_argument('--landmark_align', action='store_true', help='wether there is landmark_align') + parser.add_argument('--serial_batches', action='store_true', + help='if true, takes images in order to make batches, otherwise takes them randomly') + parser.add_argument('--no_flip', action='store_true', + help='if specified, do not flip the images for data argumentation') + parser.add_argument('--nThreads', default=8, type=int, help='# threads for loading data') + parser.add_argument('--max_dataset_size', type=int, default=sys.maxsize, + help='Maximum number of samples allowed per dataset. If the dataset directory contains more ' + 'than max_dataset_size, only a subset is loaded.') + parser.add_argument('--load_from_opt_file', action='store_true', + help='load the options from checkpoints and use that as default') + parser.add_argument('--cache_filelist_write', action='store_true', + help='saves the current filelist into a text file, so that it loads faster') + parser.add_argument('--cache_filelist_read', action='store_true', help='reads from the file list cache') + + # for displays + parser.add_argument('--display_winsize', type=int, default=400, help='display window size') + + # for generator + parser.add_argument('--netG', type=str, default='rotatespade', + help='selects model to use for netG (pix2pixhd | spade)') + parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in first conv layer') + parser.add_argument('--init_type', type=str, default='xavier', + help='network initialization [normal|xavier|kaiming|orthogonal]') + parser.add_argument('--init_variance', type=float, default=0.02, + help='variance of the initialization distribution') + # parser.add_argument('--z_dim', type=int, default=256, help='dimension of the latent z vector') + + # for instance-wise features + parser.add_argument('--no_instance', action='store_true', default='True', + help='if specified, do *not* add instance map as input') + parser.add_argument('--nef', type=int, default=16, help='# of encoder filters in the first conv layer') + + parser.add_argument('--no_gaussian_landmark', action='store_false', + help='whether to use no_gaussian_landmark (1.0 landmark) for rotatespade model') + parser.add_argument('--label_mask', action='store_false', help='whether to use face mask') + parser.add_argument('--heatmap_size', type=float, default=1, + help='the size of the heatmap, used in rotatespade model') + parser.add_argument('--erode_kernel', type=int, default=21, help='erode kernel size, used in renderer') + parser.add_argument("-device", default="cuda", type=str, help="choose between cuda or cpu ") + parser.add_argument("-path_in", default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "demos", "imgs_input"), + type=str, help='Give the path of image folder') + parser.add_argument('-path_3ddfa', default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "algorithm", "DDFA"), + type=str, help='Give the path of DDFA folder') + parser.add_argument('-save_path', default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "results"), + type=str, help='Give the path of results folder') + parser.add_argument('-val_yaw', default="10 20", nargs='+', type=float, help='yaw poses list between [-90,90] ') + parser.add_argument('-val_pitch', default="30 40", nargs='+', type=float, + help='pitch poses list between [-90,90] ') + + self.initialized = True + return parser + + def gather_options(self): + # initialize parser with basic options + if not self.initialized: + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser = self.initialize(parser) + + # get the basic options + opt, unknown = parser.parse_known_args() + + # modify model-related parser options + model_name = opt.model + model_option_setter = models.get_option_setter(model_name) + parser = model_option_setter(parser, self.isTrain) + + # modify dataset-related parser options + dataset_mode = opt.dataset_mode + dataset_option_setter = data.get_option_setter(dataset_mode) + parser = dataset_option_setter(parser, self.isTrain) + + opt, unknown = parser.parse_known_args() + + # if there is opt_file, load it. + # The previous default options will be overwritten + if opt.load_from_opt_file: + parser = self.update_options_from_file(parser, opt) + + opt = parser.parse_args() + self.parser = parser + return opt + + def print_options(self, opt): + message = '' + message += '----------------- Options ---------------\n' + for k, v in sorted(vars(opt).items()): + comment = '' + default = self.parser.get_default(k) + if v != default: + comment = '\t[default: %s]' % str(default) + message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment) + message += '----------------- End -------------------' + print(message) + + def option_file_path(self, opt, makedir=False): + expr_dir = os.path.join(opt.checkpoints_dir, opt.name) + if makedir: + util.mkdirs(expr_dir) + file_name = os.path.join(expr_dir, 'opt') + return file_name + + def save_options(self, opt): + file_name = self.option_file_path(opt, makedir=True) + with open(file_name + '.txt', 'wt') as opt_file: + for k, v in sorted(vars(opt).items()): + comment = '' + default = self.parser.get_default(k) + if v != default: + comment = '\t[default: %s]' % str(default) + opt_file.write('{:>25}: {:<30}{}\n'.format(str(k), str(v), comment)) + + with open(file_name + '.pkl', 'wb') as opt_file: + pickle.dump(opt, opt_file) + + def update_options_from_file(self, parser, opt): + new_opt = self.load_options(opt) + for k, v in sorted(vars(opt).items()): + if hasattr(new_opt, k) and v != getattr(new_opt, k): + new_val = getattr(new_opt, k) + parser.set_defaults(**{k: new_val}) + return parser + + def load_options(self, opt): + file_name = self.option_file_path(opt, makedir=False) + new_opt = pickle.load(open(file_name + '.pkl', 'rb')) + return new_opt + + def parse(self, save=False): + + opt = self.gather_options() + opt.isTrain = self.isTrain # train or test + + self.print_options(opt) + if opt.isTrain: + self.save_options(opt) + ''' + if not opt.isTrain: + # change radian to angle + if opt.yaw_poses is not None: + for pose in opt.yaw_poses: + assert abs(pose) <= 90, "yaw pose must be between [-90, 90]" + opt.yaw_poses = [round(x / 180.0 * math.pi, 2) for x in opt.yaw_poses] + if opt.pitch_poses is not None: + for pose in opt.pitch_poses: + assert abs(pose) <= 90, "pitch pose must be between [-90, 90]" + opt.pitch_poses = [round(x / 180.0 * math.pi, 2) for x in opt.pitch_poses] + ''' + # Set semantic_nc based on the option. + # This will be convenient in many places + opt.semantic_nc = opt.label_nc + (3 if opt.use_BG else 0) + + # set gpu ids + str_ids = opt.gpu_ids.split(',') + opt.gpu_ids = [] + for str_id in str_ids: + id = int(str_id) + if id >= 0: + opt.gpu_ids.append(id) + if len(opt.gpu_ids) > 0: + torch.cuda.set_device(opt.gpu_ids[0]) + + assert len(opt.gpu_ids) == 0 or opt.batchSize % len(opt.gpu_ids) == 0, \ + "Batch size %d is wrong. It must be a multiple of # GPUs %d." \ + % (opt.batchSize, len(opt.gpu_ids)) + # opt.batchSize = sum(opt.chunk_size) + + self.opt = opt + return self.opt diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/test_options.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/test_options.py new file mode 100644 index 0000000000..6f860bc59d --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/test_options.py @@ -0,0 +1,29 @@ +from .base_options import BaseOptions + + +class TestOptions(BaseOptions): + def initialize(self, parser): + BaseOptions.initialize(self, parser) + parser.add_argument('--results_dir', type=str, default='./results/', help='saves results here.') + parser.add_argument('--list_num', type=int, default=0, help='list num') + parser.add_argument('--which_epoch', type=str, default='latest', + help='which epoch to load? set to latest to use latest cached model') + parser.add_argument('--how_many', type=int, default=float("inf"), help='how many test images to run') + parser.add_argument('--list_start', type=int, default=0, help='which num in the list to start') + parser.add_argument('--list_end', type=int, default=10, help='how many test images to run') + # parser.add_argument('--save_path', type=str, default='./results/', help='where to save data') + parser.add_argument('--names', type=str, default='rs_model', help='dataset') + parser.add_argument('--multi_gpu', action='store_false', help='whether to use multi gpus') + parser.add_argument('--align', action='store_false', help='whether to save align') + # parser.add_argument('--yaw_poses', type=str, default='30,40', nargs='+', + # help='yaw poses list during testing') + # parser.add_argument('--pitch_poses', type=str, default='10,20', nargs='+', + # help='pitch poses list during testing') + parser.add_argument('--posesrandom', action='store_true', help='whether to random the poses') + + parser.set_defaults(preprocess_mode='scale_width_and_crop', crop_size=256, load_size=256, display_winsize=256) + parser.set_defaults(serial_batches=True) + parser.set_defaults(no_flip=True) + parser.set_defaults(phase='test') + self.isTrain = False + return parser diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/train_options.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/train_options.py new file mode 100644 index 0000000000..a845eea1fe --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/options/train_options.py @@ -0,0 +1,73 @@ +from .base_options import BaseOptions + + +class TrainOptions(BaseOptions): + def initialize(self, parser): + BaseOptions.initialize(self, parser) + # for displays + parser.add_argument('--display_freq', type=int, default=100, + help='frequency of showing training results on screen') + parser.add_argument('--print_freq', type=int, default=100, + help='frequency of showing training results on console') + parser.add_argument('--save_latest_freq', type=int, default=5000, help='frequency of saving the latest results') + parser.add_argument('--save_epoch_freq', type=int, default=5, + help='frequency of saving checkpoints at the end of epochs') + parser.add_argument('--no_html', action='store_true', + help='do not save intermediate training results to [opt.checkpoints_dir]/[opt.name]/web/') + parser.add_argument('--debug', action='store_true', help='only do one epoch and displays at each iteration') + parser.add_argument('--tf_log', action='store_true', + help='if specified, use tensorboard logging. Requires tensorflow installed') + parser.add_argument('--tensorboard', default=True, + help='if specified, use tensorboard logging. Requires tensorflow installed') + parser.add_argument('--load_pretrain', type=str, default='', + help='load the pretrained model from the specified location') + parser.add_argument('--train_rotate', action='store_true', + help='whether train rotated mesh') + parser.add_argument('--lambda_rotate_D', type=float, default='0.1', + help='rotated D loss weight') + parser.add_argument('--lambda_D', type=float, default='1', + help='D loss weight') + # for training + parser.add_argument('--continue_train', action='store_true', help='continue training: load the latest model') + parser.add_argument('--which_epoch', type=str, default='latest', + help='which epoch to load? set to latest to use latest cached model') + parser.add_argument('--noload_D', action='store_true', help='whether to load D when continue training') + parser.add_argument('--large_pose', action='store_true', help='whether to use large pose training') + parser.add_argument('--pose_noise', action='store_true', help='whether to use pose noise training') + parser.add_argument('--load_separately', action='store_true', + help='whether to continue train by loading separate models') + parser.add_argument('--niter', type=int, default=50, + help='# of iter at starting learning rate. This is NOT the total #epochs. Totla #epochs is ' + 'niter + niter_decay') + parser.add_argument('--niter_decay', type=int, default=1000, + help='# of iter to linearly decay learning rate to zero') + parser.add_argument('--optimizer', type=str, default='adam') + parser.add_argument('--beta1', type=float, default=0.5, help='momentum term of adam') + parser.add_argument('--beta2', type=float, default=0.999, help='momentum term of adam') + parser.add_argument('--lr', type=float, default=0.0002, help='initial learning rate for adam') + parser.add_argument('--D_steps_per_G', type=int, default=1, + help='number of discriminator iterations per generator iterations.') + parser.add_argument('--D_input', type=str, default='single', help='(concat|single|hinge)') + parser.add_argument('--gan_matching_feats', type=str, default='more', help='(concat|single|hinge)') + parser.add_argument('--G_pretrain_path', type=str, default='./checkpoints/100_net_G.pth', + help='G pretrain path') + parser.add_argument('--D_pretrain_path', type=str, default='', help='D pretrain path') + parser.add_argument('--E_pretrain_path', type=str, default='', help='E pretrain path') + parser.add_argument('--D_rotate_pretrain_path', type=str, default='', help='D_rotate pretrain path') + + # for discriminators + parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in first conv layer') + parser.add_argument('--lambda_feat', type=float, default=10.0, help='weight for feature matching loss') + parser.add_argument('--lambda_image', type=float, default=1.0, help='weight for image reconstruction') + parser.add_argument('--lambda_vgg', type=float, default=10.0, help='weight for vgg loss') + parser.add_argument('--no_ganFeat_loss', action='store_true', + help='if specified, do *not* use discriminator feature matching loss') + parser.add_argument('--no_vgg_loss', action='store_true', + help='if specified, do *not* use VGG feature matching loss') + parser.add_argument('--face_vgg', action='store_true', help='if specified, use VGG feature matching loss') + parser.add_argument('--vggface_checkpoint', type=str, default='', help='pth to vggface ckpt') + parser.add_argument('--gan_mode', type=str, default='hinge', help='(ls|original|hinge)') + parser.add_argument('--netD', type=str, default='multiscale', help='(n_layers|multiscale|image|projection)') + parser.add_argument('--no_TTUR', action='store_true', help='Use TTUR training scheme') + self.isTrain = True + return parser diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_frontal.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_frontal.py new file mode 100644 index 0000000000..f35985c1d8 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_frontal.py @@ -0,0 +1,205 @@ +from models.test_model import TestModel +from options.test_options import TestOptions +from util.iter_counter import IterationCounter +from util.visualizer import Visualizer +from util import util +from data.data_utils import init_parallel_jobs +from models.networks.test_render import TestRender +import torch.multiprocessing as multiprocessing +import numpy as np +import os +import data +from torch.multiprocessing import Queue +from skimage import transform as trans +import cv2 +import time +import torch + +multiprocessing.set_start_method('spawn', force=True) + + +def create_path(a_path, b_path): + name_id_path = os.path.join(a_path, b_path) + if not os.path.exists(name_id_path): + os.makedirs(name_id_path) + return name_id_path + + +def create_paths(save_path, img_path, foldername='orig', folderlevel=2): + save_rotated_path_name = create_path(save_path, foldername) + + path_split = img_path.split('/') + rotated_file_savepath = save_rotated_path_name + for level in range(len(path_split) - folderlevel, len(path_split)): + file_name = path_split[level] + rotated_file_savepath = os.path.join(rotated_file_savepath, file_name) + return rotated_file_savepath + + +def affine_align(img, landmark=None, **kwargs): + M = None + src = np.array([ + [38.2946, 51.6963], + [73.5318, 51.5014], + [56.0252, 71.7366], + [41.5493, 92.3655], + [70.7299, 92.2041]], dtype=np.float32) + src = src * 224 / 112 + + dst = landmark.astype(np.float32) + tform = trans.SimilarityTransform() + tform.estimate(dst, src) + M = tform.params[0:2, :] + warped = cv2.warpAffine(img, M, (224, 224), borderValue=0.0) + return warped + + +def landmark_68_to_5(t68): + le = t68[36:42, :].mean(axis=0, keepdims=True) + re = t68[42:48, :].mean(axis=0, keepdims=True) + no = t68[31:32, :] + lm = t68[48:49, :] + rm = t68[54:55, :] + t5 = np.concatenate([le, re, no, lm, rm], axis=0) + t5 = t5.reshape(10) + return t5 + + +def save_img(img, save_path): + image_numpy = util.tensor2im(img) + util.save_image(image_numpy, save_path, create_dir=True) + return image_numpy + + +if __name__ == '__main__': + + opt = TestOptions().parse() + + data_info = data.dataset_info() + datanum = data_info.get_dataset(opt) + folderlevel = data_info.folder_level[datanum] + + dataloaders = data.create_dataloader_test(opt) + + visualizer = Visualizer(opt) + iter_counter = IterationCounter(opt, len(dataloaders[0]) * opt.render_thread) + # create a webpage that summarizes the all results + + testing_queue = Queue(10) + + ngpus = opt.device_count + + render_gpu_ids = list(range(ngpus - opt.render_thread, ngpus)) + render_layer_list = [] + for gpu in render_gpu_ids: + opt.gpu_ids = gpu + render_layer = TestRender(opt) + render_layer_list.append(render_layer) + + opt.gpu_ids = list(range(0, ngpus - opt.render_thread)) + print('Testing gpu ', opt.gpu_ids) + if opt.names is None: + model = TestModel(opt) + model.eval() + model = torch.nn.DataParallel(model.cuda(), + device_ids=opt.gpu_ids, + output_device=opt.gpu_ids[-1], + ) + models = [model] + names = [opt.name] + save_path = create_path(create_path(opt.save_path, opt.name), opt.dataset) + save_paths = [save_path] + f = [open( + os.path.join(save_path, opt.dataset + str(opt.list_start) + str(opt.list_end) + '_rotate_lmk.txt'), 'w')] + else: + models = [] + names = [] + save_paths = [] + f = [] + for name in opt.names.split(','): + opt.name = name + model = TestModel(opt) + model.eval() + model = torch.nn.DataParallel(model.cuda(), + device_ids=opt.gpu_ids, + output_device=opt.gpu_ids[-1], + ) + models.append(model) + names.append(name) + save_path = create_path(create_path(opt.save_path, opt.name), opt.dataset) + save_paths.append(save_path) + f_rotated = open( + os.path.join(save_path, opt.dataset + str(opt.list_start) + str(opt.list_end) + '_rotate_lmk.txt'), 'w') + f.append(f_rotated) + + test_tasks = init_parallel_jobs(testing_queue, dataloaders, iter_counter, opt, render_layer_list) + # test + landmarks = [] + + process_num = opt.list_start + first_time = time.time() + try: + for i, data_i in enumerate(range(len(dataloaders[0]) * opt.render_thread)): + # if i * opt.batchSize >= opt.how_many: + # break + # data = trainer.get_input(data_i) + start_time = time.time() + data = testing_queue.get(block=True) + + current_time = time.time() + time_per_iter = (current_time - start_time) / opt.batchSize + message = '(************* each image render time: %.3f *****************) ' % (time_per_iter) + print(message) + + img_path = data['path'] + rotated_landmarks = data['rotated_landmarks'][:, :, :2].cpu().numpy().astype(np.float) + + generate_rotateds = [] + for model in models: + generate_rotated = model.forward(data, mode='single') + generate_rotateds.append(generate_rotated) + + for n, name in enumerate(names): + opt.name = name + for b in range(generate_rotateds[n].shape[0]): + # get 5 key points + rotated_keypoints = landmark_68_to_5(rotated_landmarks[b]) + # get savepaths + rotated_file_savepath = create_paths(save_paths[n], img_path[b], folderlevel=folderlevel) + + image_numpy = save_img(generate_rotateds[n][b], rotated_file_savepath) + rotated_keypoints_str = rotated_file_savepath + ' 1 ' + ' '.join( + [str(int(n)) for n in rotated_keypoints]) + '\n' + print('process image...' + rotated_file_savepath) + f[n].write(rotated_keypoints_str) + + current_time = time.time() + if n == 0: + process_num += 1 + print('processed num ' + str(process_num)) + if opt.align: + aligned_file_savepath = create_paths(save_paths[n], img_path[b], 'aligned', + folderlevel=folderlevel) + warped = affine_align(image_numpy, rotated_keypoints.reshape(5, 2)) + util.save_image(warped, aligned_file_savepath, create_dir=True) + + current_time = time.time() + time_per_iter = (current_time - start_time) / opt.batchSize + message = '(************* each image time total: %.3f *****************) ' % (time_per_iter) + print(message) + + except KeyboardInterrupt: + print("Interrupted!") + for fs in f: + fs.close() + pass + + except Exception as e: + print(e) + for fs in f: + fs.close() + + else: + print('finished') + for fs in f: + fs.close() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_multipose.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_multipose.py new file mode 100644 index 0000000000..8e8bf09b58 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/test_multipose.py @@ -0,0 +1,241 @@ +import torch.multiprocessing as multiprocessing +import numpy as np +import os +from .util.iter_counter import IterationCounter +from .options.test_options import TestOptions +from .models.test_model import TestModel +from .util.visualizer import Visualizer +from .util import util +from torch.multiprocessing import Queue +from .data.data_utils import init_parallel_jobs +from skimage import transform as trans +import cv2 +import time +import torch +import math +from .models.networks.rotate_render import TestRender +from algorithm.Rotate_and_Render.data import dataset_info +multiprocessing.set_start_method('spawn', force=True) +__all__ = ['dataset_info'] + + +def create_path(a_path, b_path): + name_id_path = os.path.join(a_path, b_path) + if not os.path.exists(name_id_path): + os.makedirs(name_id_path) + return name_id_path + + +def create_paths(save_path, img_path, foldername='orig', folderlevel=2, pose='0'): + save_rotated_path_name = create_path(save_path, foldername) + + path_split = img_path.split('/') + rotated_file_savepath = save_rotated_path_name + for level in range(len(path_split) - folderlevel, len(path_split)): + file_name = path_split[level] + if level == len(path_split) - 1: + fname, ext = os.path.splitext(file_name) + if ext == ".jpg": + file_name = fname + '_' + str(pose) + '.jpg' + # elif ext == ".png": + # file_name = filename + '_' + str(pose) + '.png' + rotated_file_savepath = os.path.join(rotated_file_savepath, file_name) + return rotated_file_savepath + + +def affine_align(img, landmark=None, **kwargs): + M = None + src = np.array([ + [38.2946, 51.6963], + [73.5318, 51.5014], + [56.0252, 71.7366], + [41.5493, 92.3655], + [70.7299, 92.2041]], dtype=np.float32) + src = src * 224 / 112 + + dst = landmark.astype(np.float32) + tform = trans.SimilarityTransform() + tform.estimate(dst, src) + M = tform.params[0:2, :] + warped = cv2.warpAffine(img, M, (224, 224), borderValue=0.0) + return warped + + +def landmark_68_to_5(t68): + le = t68[36:42, :].mean(axis=0, keepdims=True) + re = t68[42:48, :].mean(axis=0, keepdims=True) + no = t68[31:32, :] + lm = t68[48:49, :] + rm = t68[54:55, :] + t5 = np.concatenate([le, re, no, lm, rm], axis=0) + t5 = t5.reshape(10) + return t5 + + +def save_img(img, save_path): + image_numpy = util.tensor2im(img) + util.save_image(image_numpy, save_path, create_dir=True) + return image_numpy + + +def main(save_path, val_yaw, val_pitch): + import algorithm.Rotate_and_Render.data as data + + opt = TestOptions().parse() + data_info = data.dataset_info() + print(val_yaw) + opt.yaw_poses = [float(x) for x in val_yaw] + opt.pitch_poses = [float(x) for x in val_pitch] + opt.save_path = save_path + if not opt.isTrain: + # change radian to angle + if opt.yaw_poses is not None: + for pose in opt.yaw_poses: + assert abs(pose) <= 90, "yaw pose must be between [-90, 90]" + opt.yaw_poses = [round(x / 180.0 * math.pi, 2) for x in opt.yaw_poses] + if opt.pitch_poses is not None: + for pose in opt.pitch_poses: + assert abs(pose) <= 90, "pitch pose must be between [-90, 90]" + opt.pitch_poses = [round(x / 180.0 * math.pi, 2) for x in opt.pitch_poses] + datanum = data_info.get_dataset(opt)[0] + folderlevel = data_info.folder_level[datanum] + dataloaders = data.create_dataloader_test(opt) + Visualizer(opt) + iter_counter = IterationCounter(opt, len(dataloaders[0]) * opt.render_thread) + # create a webpage that summarizes the all results + + testing_queue = Queue(10) + + ngpus = opt.device_count + + render_gpu_ids = list(range(ngpus - opt.render_thread, ngpus)) + render_layer_list = [] + for gpu in render_gpu_ids: + opt.gpu_ids = gpu + render_layer = TestRender(opt) + render_layer_list.append(render_layer) + + opt.gpu_ids = list(range(0, ngpus - opt.render_thread + 1)) + print('Testing gpu ', opt.gpu_ids) + if opt.names is None: + model = TestModel(opt) + model.eval() + model = torch.nn.DataParallel(model.cuda(), + device_ids=opt.gpu_ids, + output_device=opt.gpu_ids[-1], + ) + models = [model] + names = [opt.name] + save_path = create_path(create_path(opt.save_path, opt.name), opt.dataset) + save_paths = [save_path] + f = [open( + os.path.join(save_path, opt.dataset + str(opt.list_start) + str(opt.list_end) + '_rotate_lmk.txt'), 'w')] + else: + models = [] + names = [] + save_paths = [] + f = [] + for name in opt.names.split(','): + opt.name = name + model = TestModel(opt) + model.eval() + model = torch.nn.DataParallel(model.cuda(), + device_ids=opt.gpu_ids, + output_device=opt.gpu_ids[-1], + ) + models.append(model) + names.append(name) + save_path = create_path(create_path(opt.save_path, opt.name), opt.dataset) + save_paths.append(save_path) + f_rotated = open( + os.path.join(save_path, opt.dataset + str(opt.list_start) + str(opt.list_end) + '_rotate_lmk.txt'), 'w') + f.append(f_rotated) + + init_parallel_jobs(testing_queue, dataloaders, iter_counter, opt, render_layer_list) + # test + # landmarks = [] + + process_num = opt.list_start + # first_time = time.time() + try: + for i, data_i in enumerate(range(len(dataloaders[0]) * opt.render_thread)): + # if i * opt.batchSize >= opt.how_many: + # break + # data = trainer.get_input(data_i) + start_time = time.time() + data = testing_queue.get(block=True) + + current_time = time.time() + time_per_iter = (current_time - start_time) / opt.batchSize + message = '(************* each image render time: %.3f *****************) ' % (time_per_iter) + print(message) + + img_path = data['path'] + # print(img_path) + poses = data['pose_list'] + rotated_landmarks = data['rotated_landmarks'][:, :, :2].cpu().numpy().astype(np.float) + # rotated_landmarks_106 = data['rotated_landmarks_106'][:, :, :2].cpu().numpy().astype(np.float) + + generate_rotateds = [] + for model in models: + generate_rotated = model.forward(data, mode='single') + generate_rotateds.append(generate_rotated) + + for n, name in enumerate(names): + opt.name = name + for b in range(generate_rotateds[n].shape[0]): + # get 5 key points + rotated_keypoints = landmark_68_to_5(rotated_landmarks[b]) + # get savepaths + IDname = img_path[b].split("/")[4] + # print(IDname) + FID = IDname.split("_")[0] # CelebA + # FID= IDname.split("_")[0]+"_"+IDname.split("_")[1]#LFW + # print(FID) + rotated_file_savepath = create_paths(save_paths[n], img_path[b], FID + '_orig', + folderlevel=folderlevel, pose=poses[b]) + + image_numpy = save_img(generate_rotateds[n][b], rotated_file_savepath) + rotated_keypoints_str = rotated_file_savepath + ' 1 ' + ' '.join( + [str(int(n)) for n in rotated_keypoints]) + '\n' + print('process image...' + rotated_file_savepath) + f[n].write(rotated_keypoints_str) + + current_time = time.time() + if n == 0: + if b <= opt.batchSize: + process_num += 1 + print('processed num ' + str(process_num)) + if opt.align: + aligned_file_savepath = create_paths(save_paths[n], img_path[b], FID + '_aligned', + folderlevel=folderlevel, pose=poses[b]) + warped = affine_align(image_numpy, rotated_keypoints.reshape(5, 2)) + util.save_image(warped, aligned_file_savepath, create_dir=True) + + # save 106 landmarks + # rotated_keypoints_106 = rotated_landmarks_106[b] # shape: 106 * 2 + + current_time = time.time() + time_per_iter = (current_time - start_time) / opt.batchSize + message = '(************* each image time total: %.3f *****************) ' % (time_per_iter) + print(message) + + except KeyboardInterrupt: + print("Interrupted!") + for fs in f: + fs.close() + pass + + except Exception as e: + print(e) + for fs in f: + fs.close() + + else: + print('finished') + for fs in f: + fs.close() + + +if __name__ == '__main__': + main() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/train.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/train.py new file mode 100644 index 0000000000..f76a1fe8b4 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/train.py @@ -0,0 +1,99 @@ +import torch.multiprocessing as multiprocessing +import sys +from options.train_options import TrainOptions +import data +from trainers import create_trainer +from util.iter_counter import IterationCounter +from util.visualizer import Visualizer +from torch.multiprocessing import Queue +from data.data_utils import init_parallel_jobs +from models.networks.render import Render +multiprocessing.set_start_method('spawn', force=True) + + +if __name__ == '__main__': + + # parse options + opt = TrainOptions().parse() + + # print options to help debugging + print(' '.join(sys.argv)) + + # load the dataset + dataloader = data.create_dataloader_test(opt) + + # create tool for counting iterations + + if type(dataloader) == list: + data_loader_size = len(dataloader[0]) * opt.render_thread + else: + data_loader_size = len(dataloader) + iter_counter = IterationCounter(opt, data_loader_size) + + ngpus = opt.device_count + + training_queue = Queue(10) + + # render layers + + render_gpu_ids = list(range(ngpus - opt.render_thread, ngpus)) + render_layer_list = [] + for gpu in render_gpu_ids: + opt.gpu_ids = gpu + render_layer = Render(opt) + render_layer_list.append(render_layer) + + training_tasks = init_parallel_jobs(training_queue, dataloader, iter_counter, opt, render_layer_list) + + opt.gpu_ids = list(range(0, ngpus - opt.render_thread)) + print('Training gpu ', opt.gpu_ids) + # create trainer for our model + trainer = create_trainer(opt) + # create tool for visualization + visualizer = Visualizer(opt) + + for epoch in iter_counter.training_epochs(): + iter_counter.record_epoch_start(epoch) + for i, data_i in enumerate(range(data_loader_size), start=iter_counter.epoch_iter): + iter_counter.record_one_iteration() + + # data = trainer.get_input(data_i) + data = training_queue.get(block=True) + # Training + # train generator + if i % opt.D_steps_per_G == 0: + trainer.run_generator_one_step(data) + + # train discriminator + trainer.run_discriminator_one_step(data) + + # Visualizations + if iter_counter.needs_printing(): + losses = trainer.get_latest_losses() + visualizer.print_current_errors(epoch, iter_counter.epoch_iter, + losses, iter_counter.time_per_iter) + visualizer.plot_current_errors(losses, iter_counter.total_steps_so_far) + + if iter_counter.needs_displaying(): + visuals = trainer.get_current_visuals(data) + visualizer.display_current_results(visuals, epoch, iter_counter.total_steps_so_far) + + if iter_counter.needs_saving(): + print('saving the latest model (epoch %d, total_steps %d)' % + (epoch, iter_counter.total_steps_so_far)) + trainer.save('latest') + iter_counter.record_current_iter() + + trainer.update_learning_rate(epoch) + iter_counter.record_epoch_end() + + if epoch % opt.save_epoch_freq == 0 or \ + epoch == iter_counter.total_epochs: + print('saving the model at the end of epoch %d, iters %d' % + (epoch, iter_counter.total_steps_so_far)) + trainer.save('latest') + trainer.save(epoch) + + for training_task in training_tasks: + training_task.terminate() + print('Training was successfully finished.') diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/__init__.py new file mode 100644 index 0000000000..6170993aa3 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/__init__.py @@ -0,0 +1,36 @@ +import importlib + + +def find_trainer_using_name(trainer_name): + # Given the option --model [modelname], + # the file "models/modelname_model.py" + # will be imported. + trainer_filename = "trainers." + trainer_name + "_trainer" + modellib = importlib.import_module(trainer_filename) + + # In the file, the class called ModelNameModel() will + # be instantiated. It has to be a subclass of torch.nn.Module, + # and it is case-insensitive. + trainer = None + target_model_name = trainer_name.replace('_', '') + 'trainer' + for name, cls in modellib.__dict__.items(): + if name.lower() == target_model_name.lower(): + trainer = cls + + if trainer is None: + print("In %s.py, there should be a trainer name that matches %s in lowercase." % (trainer_filename, target_model_name)) + exit(0) + + return trainer + + +def get_option_setter(trainer_name): + model_class = find_trainer_using_name(trainer_name) + return model_class.modify_commandline_options + + +def create_trainer(opt): + trainer = find_trainer_using_name(opt.trainer) + instance = trainer(opt) + print("trainer was created") + return instance diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotate_trainer.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotate_trainer.py new file mode 100644 index 0000000000..e337ce7538 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotate_trainer.py @@ -0,0 +1,110 @@ +import torch +from models.networks.sync_batchnorm import DataParallelWithCallback +from models import create_model +from collections import OrderedDict + + +class RotateTrainer(object): + """ + Trainer creates the model and optimizers, and uses them to + updates the weights of the network while reporting losses + and the latest visuals to visualize the progress in training. + """ + + def __init__(self, opt): + self.opt = opt + self.pix2pix_model = create_model(opt) + if len(opt.gpu_ids) > 0: + self.pix2pix_model = DataParallelWithCallback(self.pix2pix_model, + device_ids=opt.gpu_ids, + output_device=opt.gpu_ids[-1], + chunk_size=opt.chunk_size) + self.pix2pix_model_on_one_gpu = self.pix2pix_model.module + else: + self.pix2pix_model_on_one_gpu = self.pix2pix_model + # self.Render = networks.Render(opt, render_size=opt.crop_size) + self.generated = None + if opt.isTrain: + self.optimizer_G, self.optimizer_D = \ + self.pix2pix_model_on_one_gpu.create_optimizers(opt) + self.old_lr = opt.lr + + def use_gpu(self): + return len(self.opt.gpu_ids) > 0 + + def run_generator_one_step(self, data): + self.optimizer_G.zero_grad() + g_losses, generated = self.pix2pix_model.forward(data=data, mode='generator') + if not self.opt.train_rotate: + with torch.no_grad(): + g_rotate_losses, generated_rotate = self.pix2pix_model.forward(data=data, mode='generator_rotated') + + else: + g_rotate_losses, generated_rotate = self.pix2pix_model.forward(data=data, mode='generator_rotated') + g_losses['GAN_rotate'] = g_rotate_losses['GAN'] + g_loss = sum(g_losses.values()).mean() + g_loss.backward() + # g_rotate_loss = sum(g_rotate_losses.values()).mean() + # g_rotate_loss.backward() + self.optimizer_G.step() + self.g_losses = g_losses + # self.g_rotate_losses = g_rotate_losses + self.generated = generated + self.generated_rotate = generated_rotate + + def run_discriminator_one_step(self, data): + self.optimizer_D.zero_grad() + d_losses = self.pix2pix_model.forward(data=data, mode='discriminator') + if self.opt.train_rotate: + d_rotated_losses = self.pix2pix_model.forward(data=data, mode='discriminator_rotated') + d_losses['D_rotate_Fake'] = d_rotated_losses['D_Fake'] + d_losses['D_rotate_real'] = d_rotated_losses['D_real'] + d_loss = sum(d_losses.values()).mean() + d_loss.backward() + self.optimizer_D.step() + self.d_losses = d_losses + + def get_latest_generated(self): + return self.generated + + def get_latest_generated_rotate(self): + return self.generated_rotate + + def get_latest_losses(self): + return {**self.g_losses, **self.d_losses} + + def get_current_visuals(self, data): + return OrderedDict([('input_mesh', data['mesh']), + ('input_rotated_mesh', data['rotated_mesh']), + ('synthesized_image', self.get_latest_generated()), + ('synthesized_rotated_image', self.get_latest_generated_rotate()), + ('real_image', data['image'])]) + + def save(self, epoch): + self.pix2pix_model_on_one_gpu.save(epoch) + + ################################################################## + # Helper functions + ################################################################## + + def update_learning_rate(self, epoch): + if epoch > self.opt.niter: + lrd = self.opt.lr / self.opt.niter_decay + new_lr = self.old_lr - lrd + else: + new_lr = self.old_lr + + if new_lr != self.old_lr: + if self.opt.no_TTUR: + new_lr_G = new_lr + new_lr_D = new_lr + else: + new_lr_G = new_lr / 2 + new_lr_D = new_lr * 2 + + for param_group in self.optimizer_D.param_groups: + param_group['lr'] = new_lr_D + for param_group in self.optimizer_G.param_groups: + param_group['lr'] = new_lr_G + print('update learning rate: %f -> %f' % (self.old_lr, new_lr)) + self.old_lr = new_lr diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotatespade_trainer.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotatespade_trainer.py new file mode 100644 index 0000000000..f89850673c --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/trainers/rotatespade_trainer.py @@ -0,0 +1,46 @@ +from trainers.rotate_trainer import RotateTrainer +from collections import OrderedDict +import torch + + +class RotateSPADETrainer(RotateTrainer): + """ + Trainer creates the model and optimizers, and uses them to + updates the weights of the network while reporting losses + and the latest visuals to visualize the progress in training. + """ + + def __init__(self, opt): + super(RotateSPADETrainer, self).__init__(opt) + + def run_generator_one_step(self, data): + self.optimizer_G.zero_grad() + g_losses, generated, self.input_mesh = self.pix2pix_model.forward(data=data, mode='generator') + if not self.opt.train_rotate: + with torch.no_grad(): + g_rotate_losses, generated_rotate, self.input_rotated_mesh =\ + self.pix2pix_model.forward(data=data, mode='generator_rotated') + + else: + g_rotate_losses, generated_rotate, self.input_rotated_mesh = self.pix2pix_model.forward(data=data, + mode='generator_rotated') + g_losses['GAN_rotate'] = g_rotate_losses['GAN'] + g_loss = sum(g_losses.values()).mean() + g_loss.backward() + # g_rotate_loss = sum(g_rotate_losses.values()).mean() + # g_rotate_loss.backward() + self.optimizer_G.step() + self.g_losses = g_losses + # self.g_rotate_losses = g_rotate_losses + self.generated = generated + self.generated_rotate = generated_rotate + + def get_current_visuals(self, data): + return OrderedDict([('input_mesh', self.input_mesh), + ('input_rotated_mesh', self.input_rotated_mesh), + ('synthesized_image', self.get_latest_generated()), + ('synthesized_rotated_image', self.get_latest_generated_rotate()), + ('input_images_erode', data['rendered_images_erode']), + ('rendered_images_rotate_artifacts', data['rendered_images_rotate_artifacts']), + ('Rd_a', data['Rd_a']), + ('real_image', data['image'])]) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/__init__.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/html.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/html.py new file mode 100644 index 0000000000..d7372e6617 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/html.py @@ -0,0 +1,71 @@ +import datetime +import dominate +from dominate.tags import p, br, img, a, td, tr, table, h3, meta, h1 +import os + + +class HTML: + def __init__(self, web_dir, title, refresh=0): + if web_dir.endswith('.html'): + web_dir, html_name = os.path.split(web_dir) + else: + web_dir, html_name = web_dir, 'index.html' + self.title = title + self.web_dir = web_dir + self.html_name = html_name + self.img_dir = os.path.join(self.web_dir, 'images') + if len(self.web_dir) > 0 and not os.path.exists(self.web_dir): + os.makedirs(self.web_dir) + if len(self.web_dir) > 0 and not os.path.exists(self.img_dir): + os.makedirs(self.img_dir) + + self.doc = dominate.document(title=title) + with self.doc: + h1(datetime.datetime.now().strftime("%I:%M%p on %B %d, %Y")) + if refresh > 0: + with self.doc.head: + meta(http_equiv="refresh", content=str(refresh)) + + def get_image_dir(self): + return self.img_dir + + def add_header(self, str): + with self.doc: + h3(str) + + def add_table(self, border=1): + self.t = table(border=border, style="table-layout: fixed;") + self.doc.add(self.t) + + def add_images(self, ims, txts, links, width=512): + self.add_table() + with self.t: + with tr(): + for im, txt, link in zip(ims, txts, links): + with td(style="word-wrap: break-word;", halign="center", valign="top"): + with p(): + with a(href=os.path.join('images', link)): + img(style="width:%dpx" % (width), src=os.path.join('images', im)) + br() + p(txt.encode('utf-8')) + + def save(self): + html_file = os.path.join(self.web_dir, self.html_name) + f = open(html_file, 'wt') + f.write(self.doc.render()) + f.close() + + +if __name__ == '__main__': + html = HTML('web/', 'test_html') + html.add_header('hello world') + + ims = [] + txts = [] + links = [] + for n in range(4): + ims.append('image_%d.jpg' % n) + txts.append('text_%d' % n) + links.append('image_%d.jpg' % n) + html.add_images(ims, txts, links) + html.save() diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/iter_counter.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/iter_counter.py new file mode 100644 index 0000000000..4cdae6377f --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/iter_counter.py @@ -0,0 +1,69 @@ +import os +import time +import numpy as np + + +# Helper class that keeps track of training iterations +class IterationCounter(): + def __init__(self, opt, dataset_size): + self.opt = opt + self.dataset_size = dataset_size + + self.first_epoch = 1 + self.total_epochs = opt.niter + opt.niter_decay if opt.isTrain else 1 + self.epoch_iter = 0 # iter number within each epoch + self.iter_record_path = os.path.join(self.opt.checkpoints_dir, self.opt.name, 'iter.txt') + if opt.isTrain and opt.continue_train: + try: + self.first_epoch, self.epoch_iter = np.loadtxt( + self.iter_record_path, delimiter=',', dtype=int) + print('Resuming from epoch %d at iteration %d' % (self.first_epoch, self.epoch_iter)) + except: + print('Could not load iteration record at %s. Starting from beginning.' % + self.iter_record_path) + + self.total_steps_so_far = (self.first_epoch - 1) * dataset_size + self.epoch_iter + + # return the iterator of epochs for the training + def training_epochs(self): + return range(self.first_epoch, self.total_epochs + 1) + + def record_epoch_start(self, epoch): + self.epoch_start_time = time.time() + self.epoch_iter = 0 + self.last_iter_time = time.time() + self.current_epoch = epoch + + def record_one_iteration(self): + current_time = time.time() + + # the last remaining batch is dropped (see data/__init__.py), + # so we can assume batch size is always opt.batchSize + self.time_per_iter = (current_time - self.last_iter_time) / self.opt.batchSize + self.last_iter_time = current_time + self.total_steps_so_far += self.opt.batchSize + self.epoch_iter += self.opt.batchSize + + def record_epoch_end(self): + current_time = time.time() + self.time_per_epoch = current_time - self.epoch_start_time + print('End of epoch %d / %d \t Time Taken: %d sec' % + (self.current_epoch, self.total_epochs, self.time_per_epoch)) + if self.current_epoch % self.opt.save_epoch_freq == 0: + np.savetxt(self.iter_record_path, (self.current_epoch + 1, 0), + delimiter=',', fmt='%d') + print('Saved current iteration count at %s.' % self.iter_record_path) + + def record_current_iter(self): + np.savetxt(self.iter_record_path, (self.current_epoch, self.epoch_iter), + delimiter=',', fmt='%d') + print('Saved current iteration count at %s.' % self.iter_record_path) + + def needs_saving(self): + return (self.total_steps_so_far % self.opt.save_latest_freq) < self.opt.batchSize + + def needs_printing(self): + return (self.total_steps_so_far % self.opt.print_freq) < self.opt.batchSize + + def needs_displaying(self): + return (self.total_steps_so_far % self.opt.display_freq) < self.opt.batchSize diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/util.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/util.py new file mode 100644 index 0000000000..a66ba460b6 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/util.py @@ -0,0 +1,206 @@ +import re +import importlib +import torch +import numpy as np +from PIL import Image +import os +import argparse +import dill as pickle + + +def save_obj(obj, name): + with open(name, 'wb') as f: + pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL) + + +def load_obj(name): + with open(name, 'rb') as f: + return pickle.load(f) + + +# returns a configuration for creating a generator +# |default_opt| should be the opt of the current experiment +# |**kwargs|: if any configuration should be overriden, it can be specified here + + +def copyconf(default_opt, **kwargs): + conf = argparse.Namespace(**vars(default_opt)) + for key in kwargs: + print(key, kwargs[key]) + setattr(conf, key, kwargs[key]) + return conf + + +def tile_images(imgs, picturesPerRow=4): + """ Code borrowed from + https://stackoverflow.com/questions/26521365/cleanly-tile-numpy-array-of-images-stored-in-a-flattened-1d-format/26521997 + """ + + # Padding + if imgs.shape[0] % picturesPerRow == 0: + rowPadding = 0 + else: + rowPadding = picturesPerRow - imgs.shape[0] % picturesPerRow + if rowPadding > 0: + imgs = np.concatenate([imgs, np.zeros((rowPadding, *imgs.shape[1:]), dtype=imgs.dtype)], axis=0) + + # Tiling Loop (The conditionals are not necessary anymore) + tiled = [] + for i in range(0, imgs.shape[0], picturesPerRow): + tiled.append(np.concatenate([imgs[j] for j in range(i, i + picturesPerRow)], axis=1)) + + tiled = np.concatenate(tiled, axis=0) + return tiled + + +# Converts a Tensor into a Numpy array +# |imtype|: the desired type of the converted numpy array +def tensor2im(image_tensor, imtype=np.uint8, normalize=True, tile=False): + if isinstance(image_tensor, list): + image_numpy = [] + for i in range(len(image_tensor)): + image_numpy.append(tensor2im(image_tensor[i], imtype, normalize)) + return image_numpy + + if image_tensor.dim() == 4: + # transform each image in the batch + images_np = [] + for b in range(image_tensor.size(0)): + one_image = image_tensor[b] + one_image_np = tensor2im(one_image) + images_np.append(one_image_np.reshape(1, *one_image_np.shape)) + images_np = np.concatenate(images_np, axis=0) + if tile: + images_tiled = tile_images(images_np) + return images_tiled + else: + return images_np + + if image_tensor.dim() == 2: + image_tensor = image_tensor.unsqueeze(0) + image_numpy = image_tensor.detach().cpu().float().numpy() + if normalize: + image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + 1) / 2.0 * 255.0 + else: + image_numpy = np.transpose(image_numpy, (1, 2, 0)) * 255.0 + image_numpy = np.clip(image_numpy, 0, 255) + if image_numpy.shape[2] == 1: + image_numpy = image_numpy[:, :, 0] + return image_numpy.astype(imtype) + + +def save_image(image_numpy, image_path, create_dir=False): + if create_dir: + os.makedirs(os.path.dirname(image_path), exist_ok=True) + if len(image_numpy.shape) == 2: + image_numpy = np.expand_dims(image_numpy, axis=2) + if image_numpy.shape[2] == 1: + image_numpy = np.repeat(image_numpy, 3, 2) + image_pil = Image.fromarray(image_numpy) + + # save to png + image_pil.save(image_path) + # image_pil.save(image_path.replace('.jpg', '.png')) + + +def mkdirs(paths): + if isinstance(paths, list) and not isinstance(paths, str): + for path in paths: + mkdir(path) + else: + mkdir(paths) + + +def mkdir(path): + if not os.path.exists(path): + os.makedirs(path) + + +def atoi(text): + return int(text) if text.isdigit() else text + + +def natural_keys(text): + ''' + alist.sort(key=natural_keys) sorts in human order + http://nedbatchelder.com/blog/200712/human_sorting.html + (See Toothy's implementation in the comments) + ''' + return [atoi(c) for c in re.split('(\d+)', text)] + + +def natural_sort(items): + items.sort(key=natural_keys) + + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + + +def find_class_in_module(target_cls_name, module): + target_cls_name = target_cls_name.replace('_', '').lower() + clslib = importlib.import_module(module) + cls = None + for name, clsobj in clslib.__dict__.items(): + if name.lower() == target_cls_name: + cls = clsobj + + if cls is None: + print("In %s, there should be a class whose name matches %s in lowercase without underscore(_)" % (module, + target_cls_name)) + exit(0) + + return cls + + +def save_network(net, label, epoch, opt): + save_filename = '%s_net_%s.pth' % (epoch, label) + save_path = os.path.join(opt.checkpoints_dir, opt.name, save_filename) + torch.save(net.cpu().state_dict(), save_path) + if len(opt.gpu_ids) and torch.cuda.is_available(): + net.cuda() + + +def load_network(net, label, epoch, opt): + save_filename = '%s_net_%s.pth' % (epoch, label) + save_dir = os.path.join(opt.checkpoints_dir, opt.name) + save_path = os.path.join(save_dir, save_filename) + weights = torch.load(save_path) + net.load_state_dict(weights) + return net + + +def copy_state_dict(state_dict, model, strip=None): + tgt_state = model.state_dict() + copied_names = set() + for name, param in state_dict.items(): + if strip is not None and name.startswith(strip): + name = name[len(strip):] + if name not in tgt_state: + continue + if isinstance(param, torch.nn.Parameter): + param = param.data + if param.size() != tgt_state[name].size(): + print('mismatch:', name, param.size(), tgt_state[name].size()) + continue + tgt_state[name].copy_(param) + copied_names.add(name) + + missing = set(tgt_state.keys()) - copied_names + if len(missing) > 0: + print("missing keys in state_dict:", missing) + + +############################################################################### +# Code from +# https://github.com/ycszen/pytorch-seg/blob/master/transform.py +# Modified so it complies with the Citscape label map colors +############################################################################### +def uint82bin(n, count=8): + """returns the binary of integer n, count refers to amount of bits""" + return ''.join([str((n >> y) & 1) for y in range(count - 1, -1, -1)]) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/visualizer.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/visualizer.py new file mode 100644 index 0000000000..305a8ecd62 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm/Rotate_and_Render/util/visualizer.py @@ -0,0 +1,187 @@ +import os +import ntpath +import time +from . import util +from . import html +import scipy.misc +import torchvision.utils as vutils +from torch.utils.tensorboard import SummaryWriter + +try: + from StringIO import StringIO # Python 2.7 +except ImportError: + from io import BytesIO # Python 3.x + + +class Visualizer(): + def __init__(self, opt): + self.opt = opt + self.tf_log = opt.isTrain and opt.tf_log + self.tensorboard = opt.isTrain and opt.tensorboard + self.use_html = opt.isTrain and not opt.no_html + self.win_size = opt.display_winsize + self.name = opt.name + if self.tf_log: + import tensorflow as tf + self.tf = tf + self.log_dir = os.path.join(opt.checkpoints_dir, opt.name, 'logs') + self.writer = tf.summary.FileWriter(self.log_dir) + + if self.tensorboard: + self.log_dir = os.path.join(opt.checkpoints_dir, opt.name, 'logs') + self.writer = SummaryWriter(self.log_dir, comment=opt.name) + + if self.use_html: + self.web_dir = os.path.join(opt.checkpoints_dir, opt.name, 'web') + self.img_dir = os.path.join(self.web_dir, 'images') + print('create web directory %s...' % self.web_dir) + util.mkdirs([self.web_dir, self.img_dir]) + if opt.isTrain: + self.log_name = os.path.join(opt.checkpoints_dir, opt.name, 'loss_log.txt') + with open(self.log_name, "a") as log_file: + now = time.strftime("%c") + log_file.write('================ Training Loss (%s) ================\n' % now) + + # |visuals|: dictionary of images to display or save + def display_current_results(self, visuals, epoch, step): + + # convert tensors to numpy arrays + + if self.tf_log: # show images in tensorboard output + img_summaries = [] + visuals = self.convert_visuals_to_numpy(visuals) + for label, image_numpy in visuals.items(): + # Write the image to a string + try: + s = StringIO() + except: + s = BytesIO() + if len(image_numpy.shape) >= 4: + image_numpy = image_numpy[0] + scipy.misc.toimage(image_numpy).save(s, format="jpeg") + # Create an Image object + img_sum = self.tf.Summary.Image(encoded_image_string=s.getvalue(), height=image_numpy.shape[0], + width=image_numpy.shape[1]) + # Create a Summary value + img_summaries.append(self.tf.Summary.Value(tag=label, image=img_sum)) + + # Create and write Summary + summary = self.tf.Summary(value=img_summaries) + self.writer.add_summary(summary, step) + + if self.tensorboard: # show images in tensorboard output + img_summaries = [] + for label, image_numpy in visuals.items(): + # Write the image to a string + try: + s = StringIO() + except: + s = BytesIO() + # if len(image_numpy.shape) >= 4: + # image_numpy = image_numpy[0] + # scipy.misc.toimage(image_numpy).save(s, format="jpeg") + # Create an Image object + # self.writer.add_image(tag=label, img_tensor=image_numpy, global_step=step, dataformats='HWC') + # Create a Summary value + batch_size = image_numpy.size(0) + x = vutils.make_grid(image_numpy[:min(batch_size, 16)], normalize=True, scale_each=True) + self.writer.add_image(label, x, step) + + if self.use_html: # save images to a html file + for label, image_numpy in visuals.items(): + if isinstance(image_numpy, list): + for i in range(len(image_numpy)): + img_path = os.path.join(self.img_dir, 'epoch%.3d_iter%.3d_%s_%d.png' % (epoch, step, label, i)) + util.save_image(image_numpy[i], img_path) + else: + img_path = os.path.join(self.img_dir, 'epoch%.3d_iter%.3d_%s.png' % (epoch, step, label)) + if len(image_numpy.shape) >= 4: + image_numpy = image_numpy[0] + util.save_image(image_numpy, img_path) + + # update website + webpage = html.HTML(self.web_dir, 'Experiment name = %s' % self.name, refresh=5) + for n in range(epoch, 0, -1): + webpage.add_header('epoch [%d]' % n) + ims = [] + txts = [] + links = [] + + for label, image_numpy in visuals.items(): + if isinstance(image_numpy, list): + for i in range(len(image_numpy)): + img_path = 'epoch%.3d_iter%.3d_%s_%d.png' % (n, step, label, i) + ims.append(img_path) + txts.append(label + str(i)) + links.append(img_path) + else: + img_path = 'epoch%.3d_iter%.3d_%s.png' % (n, step, label) + ims.append(img_path) + txts.append(label) + links.append(img_path) + if len(ims) < 10: + webpage.add_images(ims, txts, links, width=self.win_size) + else: + num = int(round(len(ims) / 2.0)) + webpage.add_images(ims[:num], txts[:num], links[:num], width=self.win_size) + webpage.add_images(ims[num:], txts[num:], links[num:], width=self.win_size) + webpage.save() + + # errors: dictionary of error labels and values + def plot_current_errors(self, errors, step): + if self.tf_log: + for tag, value in errors.items(): + value = value.mean().float() + summary = self.tf.Summary(value=[self.tf.Summary.Value(tag=tag, simple_value=value)]) + self.writer.add_summary(summary, step) + + if self.tensorboard: + for tag, value in errors.items(): + value = value.mean().float() + self.writer.add_scalar(tag=tag, scalar_value=value, global_step=step) + + # errors: same format as |errors| of plotCurrentErrors + def print_current_errors(self, epoch, i, errors, t): + message = '(epoch: %d, iters: %d, time: %.3f) ' % (epoch, i, t) + for k, v in errors.items(): + # print(v) + # if v != 0: + v = v.mean().float() + message += '%s: %.3f ' % (k, v) + + print(message) + with open(self.log_name, "a") as log_file: + log_file.write('%s\n' % message) + + def convert_visuals_to_numpy(self, visuals): + for key, t in visuals.items(): + tile = self.opt.batchSize > 8 + if 'input_label' == key: + t = util.tensor2label(t, self.opt.label_nc + 2, tile=tile) + else: + t = util.tensor2im(t, tile=tile) + visuals[key] = t + return visuals + + # save image to the disk + def save_images(self, webpage, visuals, image_path): + visuals = self.convert_visuals_to_numpy(visuals) + + image_dir = webpage.get_image_dir() + short_path = ntpath.basename(image_path[0]) + name = os.path.splitext(short_path)[0] + + webpage.add_header(name) + ims = [] + txts = [] + links = [] + + for label, image_numpy in visuals.items(): + image_name = os.path.join(label, '%s.png' % (name)) + save_path = os.path.join(image_dir, image_name) + util.save_image(image_numpy, save_path, create_dir=True) + + ims.append(image_name) + txts.append(label) + links.append(image_name) + webpage.add_images(ims, txts, links, width=self.win_size) diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/demos/imgs_input/person01145+0-15.jpg b/projects/data_generation/synthetic_multi_view_facial_image_generation/demos/imgs_input/person01145+0-15.jpg new file mode 100644 index 0000000000..5250dc7dc7 Binary files /dev/null and b/projects/data_generation/synthetic_multi_view_facial_image_generation/demos/imgs_input/person01145+0-15.jpg differ diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/requirements.txt b/projects/data_generation/synthetic_multi_view_facial_image_generation/requirements.txt new file mode 100644 index 0000000000..3f74a7cee4 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/requirements.txt @@ -0,0 +1,11 @@ +torch>=1.0.0 +torchvision +dominate>=2.3.1 +dill +scikit-image +numpy>=1.15.4 +scipy>=1.1.0 +matplotlib>=2.2.2 +opencv-python>=3.4.3.18 +tensorboard>=1.14.0 +face-alignment==1.0.0 diff --git a/projects/data_generation/synthetic_multi_view_facial_image_generation/tool_synthetic_facial_generation.py b/projects/data_generation/synthetic_multi_view_facial_image_generation/tool_synthetic_facial_generation.py new file mode 100755 index 0000000000..ccf35746d1 --- /dev/null +++ b/projects/data_generation/synthetic_multi_view_facial_image_generation/tool_synthetic_facial_generation.py @@ -0,0 +1,79 @@ +# Copyright 2020-2022 OpenDR European Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch +import matplotlib +import os +import argparse +from SyntheticDataGeneration import MultiviewDataGeneration +from algorithm.DDFA.utils.ddfa import str2bool + +matplotlib.use('Agg') +__all__ = ['torch'] + +if __name__ == '__main__': + print("\n\n**********************************\nTEST Multiview Data Generation Learner\n" + "**********************************") + parser = argparse.ArgumentParser() + parser.add_argument("-device", default="cuda", type=str, help="choose between cuda or cpu ") + parser.add_argument("-path_in", default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "demos", "imgs_input"), + type=str, help='Give the path of image folder') + parser.add_argument('-path_3ddfa', default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "algorithm", "DDFA"), + type=str, help='Give the path of DDFA folder') + parser.add_argument('-save_path', default=os.path.join("opendr_internal", "projects", + "data_generation", + "", + "results"), + type=str, help='Give the path of results folder') + parser.add_argument('-val_yaw', default="10 20", nargs='+', type=str, help='yaw poses list between [-90,90] ') + parser.add_argument('-val_pitch', default="30 40", nargs='+', type=str, + help='pitch poses list between [-90,90] ') + parser.add_argument('-f', '--files', nargs='+', + help='image files paths fed into network, single or multiple images') + parser.add_argument('--show_flg', default='false', type=str2bool, help='whether show the visualization result') + parser.add_argument('--dump_res', default='true', type=str2bool, + help='whether write out the visualization image') + parser.add_argument('--dump_vertex', default='false', type=str2bool, + help='whether write out the dense face vertices to mat') + parser.add_argument('--dump_ply', default='true', type=str2bool) + parser.add_argument('--dump_pts', default='true', type=str2bool) + parser.add_argument('--dump_roi_box', default='false', type=str2bool) + parser.add_argument('--dump_pose', default='true', type=str2bool) + parser.add_argument('--dump_depth', default='true', type=str2bool) + parser.add_argument('--dump_pncc', default='true', type=str2bool) + parser.add_argument('--dump_paf', default='true', type=str2bool) + parser.add_argument('--paf_size', default=3, type=int, help='PAF feature kernel size') + parser.add_argument('--dump_obj', default='true', type=str2bool) + parser.add_argument('--dlib_bbox', default='true', type=str2bool, help='whether use dlib to predict bbox') + parser.add_argument('--dlib_landmark', default='true', type=str2bool, + help='whether use dlib landmark to crop image') + parser.add_argument('-m', '--mode', default='gpu', type=str, help='gpu or cpu mode') + parser.add_argument('--bbox_init', default='two', type=str, help='one|two: one-step bbox initialization or two-step') + parser.add_argument('--dump_2d_img', default='true', type=str2bool, help='whether to save 3d rendered image') + parser.add_argument('--dump_param', default='true', type=str2bool, help='whether to save param') + parser.add_argument('--dump_lmk', default='true', type=str2bool, help='whether to save landmarks') + parser.add_argument('--save_dir', default='./algorithm/DDFA/results', type=str, help='dir to save result') + parser.add_argument('--save_lmk_dir', default='./example', type=str, help='dir to save landmark result') + parser.add_argument('--img_list', default='./txt_name_batch.txt', type=str, help='test image list file') + parser.add_argument('--rank', default=0, type=int, help='used when parallel run') + parser.add_argument('--world_size', default=1, type=int, help='used when parallel run') + parser.add_argument('--resume_idx', default=0, type=int) + args = parser.parse_args() + synthetic = MultiviewDataGeneration(args) + synthetic.eval() diff --git a/projects/opendr_ws/src/data_generation/CMakeLists.txt b/projects/opendr_ws/src/data_generation/CMakeLists.txt new file mode 100644 index 0000000000..2a43cfdb27 --- /dev/null +++ b/projects/opendr_ws/src/data_generation/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.0.2) +project(data_generation) + +find_package(catkin REQUIRED COMPONENTS + roscpp + rospy + sensor_msgs + std_msgs +) + +################################### +## catkin specific configuration ## +################################### + +catkin_package() + +########### +## Build ## +########### + +include_directories( + ${catkin_INCLUDE_DIRS} +) + +############# +## Install ## +############# + +catkin_install_python(PROGRAMS + scripts/synthetic_facial_generation.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + ) diff --git a/projects/opendr_ws/src/data_generation/README.md b/projects/opendr_ws/src/data_generation/README.md new file mode 100644 index 0000000000..523347f6a0 --- /dev/null +++ b/projects/opendr_ws/src/data_generation/README.md @@ -0,0 +1,28 @@ +# Perception Package + +This package contains ROS nodes related to data generation package of OpenDR. + +## Pose Estimation ROS Node +Assuming that you have already [built your workspace](../../README.md) and started roscore (i.e., just run `roscore`), then you can + + +1. Add OpenDR to `PYTHONPATH` (please make sure you do not overwrite `PYTHONPATH` ), e.g., +```shell +export PYTHONPATH="/home/user/opendr/src:$PYTHONPATH" +``` + +2. Start the node responsible for publishing images. If you have a usb camera, then you can use the corresponding node (assuming you have installed the corresponding package): + +```shell +rosrun usb_cam usb_cam_node +``` + +3. You are then ready to start the synthetic data generation node + +```shell +rosrun data_generation synthetic_facial_generation.py +``` + +3. You can examine the published multiview facial images stream using `rosrun rqt_image_view rqt_image_view` (select the topic `/opendr/synthetic_facial_images`) or `rostopic echo /opendr/synthetic_facial_images` + + diff --git a/projects/opendr_ws/src/data_generation/package.xml b/projects/opendr_ws/src/data_generation/package.xml new file mode 100644 index 0000000000..cd332807fb --- /dev/null +++ b/projects/opendr_ws/src/data_generation/package.xml @@ -0,0 +1,25 @@ + + + data_generation + 1.0.0 + OpenDR's ROS nodes for data generation package + OpenDR Project Coordinator + Apache License v2.0 + opendr.eu + catkin + roscpp + rospy + std_msgs + sensor_msgs + roscpp + rospy + std_msgs + sensor_msgs + roscpp + rospy + std_msgs + sensor_msgs + + + + diff --git a/projects/opendr_ws/src/data_generation/scripts/synthetic_facial_generation.py b/projects/opendr_ws/src/data_generation/scripts/synthetic_facial_generation.py new file mode 100644 index 0000000000..4f25fffd65 --- /dev/null +++ b/projects/opendr_ws/src/data_generation/scripts/synthetic_facial_generation.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3.6 +# Copyright 2020-2022 OpenDR European Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import rospy +import torch +import numpy as np +from sensor_msgs.msg import Image as ROS_Image +from opendr_bridge import ROSBridge +from SyntheticDataGeneration import MultiviewDataGenerationLearner +import os +import cv2 +import argparse +from src.opendr.engine.data import Image + + +class Synthetic_Data_Generation: + + def __init__(self, input_image_topic="/usb_cam/image_raw", output_image_topic="/opendr/synthetic_facial_images", + device="cuda"): + """ + Creates a ROS Node for SyntheticDataGeneration + :param input_image_topic: Topic from which we are reading the input image + :type input_image_topic: str + :param output_image_topic: Topic to which we are publishing the synthetic facial image (if None, we are not publishing + any image) + :type output_image_topic: str + :param device: device on which we are running eval ('cpu' or 'cuda') + :type device: str + """ + + if output_image_topic is not None: + self.image_publisher = rospy.Publisher(output_image_topic, ROS_Image, queue_size=10) + else: + self.image_publisher = None + rospy.Subscriber(input_image_topic, ROS_Image, self.callback) + + self.bridge = ROSBridge() + self.ID = 0 + + # Initialize the SyntheticDataGeneration + self.parser = argparse.ArgumentParser() + self.parser.add_argument('-path_in', default='/home/ekakalet/Pictures/TEST', type=str, + help='Give the path of image folder') + self.parser.add_argument('-path_3ddfa', default='./', type=str, help='Give the path of DDFA folder') + self.parser.add_argument('-save_path', default='./results/', type=str, help='Give the path of results folder') + self.parser.add_argument('-val_yaw', default="15,-15", nargs='+', type=str, + help='yaw poses list between [-90,90] ') + self.parser.add_argument('-val_pitch', default="15,-15", nargs='+', type=str, + help='pitch poses list between [-90,90] ') + self.args = self.parser.parse_args() + self.synthetic = MultiviewDataGenerationLearner(path_in=self.args.path_in, path_3ddfa=self.args.path_3ddfa, + save_path=self.args.save_path, + val_yaw=self.args.val_yaw, val_pitch=self.args.val_pitch) + + def listen(self): + """ + Start the node and begin processing input data + """ + rospy.init_node('opendr_SyntheticDataGeneration', anonymous=True) + rospy.loginfo("SyntheticDataGeneration node started!") + rospy.spin() + + def callback(self, data): + """ + Callback that process the input data and publishes to the corresponding topics + :param data: input message + :type data: sensor_msgs.msg.Image + """ + + # Convert sensor_msgs.msg.Image into OpenDR Image + image = self.bridge.from_ros_image(data) + self.ID = self.ID + 1 + # Get an OpenCV image back + image = np.float32(image.numpy()) + name = str(f"{self.ID:02d}"+"_single.jpg") + cv2.imwrite(os.path.join(self.args.path_in, name), image) + + if (self.ID == 5): + # Run SyntheticDataGeneration + self.synthetic.eval() + self.ID = 0 + # Annotate image and publish results + current_directory_path = os.path.join(self.args.save_path, str("/Documents_orig/")) + for file in os.listdir(current_directory_path): + name, ext = os.path.splitext(file) + if ext == ".jpg": + image_file_savepath = os.path.join(current_directory_path, file) + cv_image = cv2.imread(image_file_savepath) + cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB) + if self.image_publisher is not None: + image = Image(np.array(cv_image, dtype=np.uint8)) + message = self.bridge.to_ros_image(image, encoding="bgr8") + self.image_publisher.publish(message) + for f in os.listdir(self.args.path_in): + os.remove(os.path.join(self.args.path_in, f)) + +if __name__ == '__main__': + # Select the device for running the + try: + if torch.cuda.is_available(): + print("GPU found.") + device = 'cuda' + else: + print("GPU not found. Using CPU instead.") + device = 'cpu' + except: + device = 'cpu' + + syntheticdatageneration_node = Synthetic_Data_Generation(device=device) + syntheticdatageneration_node.listen() diff --git a/src/opendr/_version.py b/src/opendr/_version.py index 4c67cd2681..c98a588823 100644 --- a/src/opendr/_version.py +++ b/src/opendr/_version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.0" +__version__ = "1.0.0" diff --git a/tests/test_license.py b/tests/test_license.py index c13a325101..71204177ba 100755 --- a/tests/test_license.py +++ b/tests/test_license.py @@ -98,6 +98,7 @@ def setUp(self): 'src/opendr/simulation/human_model_generation/utilities/PIFu', 'src/opendr/perception/multimodal_human_centric/rgbd_hand_gesture_learner/algorithm/architectures', 'src/opendr/perception/skeleton_based_action_recognition/algorithm', + 'projects/data_generation/synthetic_multi_view_facial_image_generation/algorithm', 'src/opendr/perception/semantic_segmentation/bisenet/algorithm', 'src/opendr/perception/object_detection_2d/retinaface/algorithm', 'src/opendr/perception/object_detection_2d/gem/algorithm',