Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.  
							See raw diff
- .gitattributes +3 -0
- .gitignore +199 -0
- LICENSE +21 -0
- README-zh.md +144 -0
- README.md +149 -0
- TalkingHead-1KH/.gitignore +2 -0
- TalkingHead-1KH/LICENSE.txt +42 -0
- TalkingHead-1KH/README.md +84 -0
- TalkingHead-1KH/data_list.zip +3 -0
- TalkingHead-1KH/data_list/small_video_ids.txt +2 -0
- TalkingHead-1KH/data_list/small_video_tubes.txt +4 -0
- TalkingHead-1KH/data_list/train_video_ids.txt +2872 -0
- TalkingHead-1KH/data_list/train_video_tubes.txt +3 -0
- TalkingHead-1KH/data_list/val_video_ids.txt +28 -0
- TalkingHead-1KH/data_list/val_video_tubes.txt +38 -0
- TalkingHead-1KH/requirements.txt +4 -0
- TalkingHead-1KH/teaser.gif +3 -0
- TalkingHead-1KH/videos_crop.py +79 -0
- TalkingHead-1KH/videos_download.py +56 -0
- TalkingHead-1KH/videos_download_and_crop.sh +10 -0
- TalkingHead-1KH/videos_split.sh +11 -0
- checkpoints/.gitkeep +0 -0
- data_gen/eg3d/convert_to_eg3d_convention.py +146 -0
- data_gen/runs/binarizer_nerf.py +335 -0
- data_gen/runs/binarizer_th1kh.py +100 -0
- data_gen/runs/nerf/process_guide.md +49 -0
- data_gen/runs/nerf/run.sh +51 -0
- data_gen/utils/mp_feature_extractors/face_landmarker.py +130 -0
- data_gen/utils/mp_feature_extractors/face_landmarker.task +3 -0
- data_gen/utils/mp_feature_extractors/mp_segmenter.py +303 -0
- data_gen/utils/mp_feature_extractors/selfie_multiclass_256x256.tflite +3 -0
- data_gen/utils/path_converter.py +24 -0
- data_gen/utils/process_audio/extract_hubert.py +95 -0
- data_gen/utils/process_audio/extract_mel_f0.py +148 -0
- data_gen/utils/process_audio/resample_audio_to_16k.py +49 -0
- data_gen/utils/process_image/extract_lm2d.py +197 -0
- data_gen/utils/process_image/extract_segment_imgs.py +114 -0
- data_gen/utils/process_image/fit_3dmm_landmark.py +369 -0
- data_gen/utils/process_video/euler2quaterion.py +35 -0
- data_gen/utils/process_video/extract_blink.py +50 -0
- data_gen/utils/process_video/extract_lm2d.py +164 -0
- data_gen/utils/process_video/extract_segment_imgs.py +494 -0
- data_gen/utils/process_video/fit_3dmm_landmark.py +565 -0
- data_gen/utils/process_video/inpaint_torso_imgs.py +193 -0
- data_gen/utils/process_video/resample_video_to_25fps_resize_to_512.py +87 -0
- data_gen/utils/process_video/split_video_to_imgs.py +53 -0
- data_util/face3d_helper.py +309 -0
- deep_3drecon/BFM/.gitkeep +0 -0
- deep_3drecon/BFM/basel_53201.txt +0 -0
- deep_3drecon/BFM/index_mp468_from_mesh35709_v1.npy +3 -0
    	
        .gitattributes
    CHANGED
    
    | @@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text | |
| 33 | 
             
            *.zip filter=lfs diff=lfs merge=lfs -text
         | 
| 34 | 
             
            *.zst filter=lfs diff=lfs merge=lfs -text
         | 
| 35 | 
             
            *tfevents* filter=lfs diff=lfs merge=lfs -text
         | 
|  | |
|  | |
|  | 
|  | |
| 33 | 
             
            *.zip filter=lfs diff=lfs merge=lfs -text
         | 
| 34 | 
             
            *.zst filter=lfs diff=lfs merge=lfs -text
         | 
| 35 | 
             
            *tfevents* filter=lfs diff=lfs merge=lfs -text
         | 
| 36 | 
            +
            TalkingHead-1KH/data_list/train_video_tubes.txt filter=lfs diff=lfs merge=lfs -text
         | 
| 37 | 
            +
            TalkingHead-1KH/teaser.gif filter=lfs diff=lfs merge=lfs -text
         | 
| 38 | 
            +
            data_gen/utils/mp_feature_extractors/face_landmarker.task filter=lfs diff=lfs merge=lfs -text
         | 
    	
        .gitignore
    ADDED
    
    | @@ -0,0 +1,199 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # big files
         | 
| 2 | 
            +
            data_util/face_tracking/3DMM/01_MorphableModel.mat
         | 
| 3 | 
            +
            data_util/face_tracking/3DMM/3DMM_info.npy
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            !/deep_3drecon/BFM/.gitkeep
         | 
| 6 | 
            +
            deep_3drecon/BFM/Exp_Pca.bin
         | 
| 7 | 
            +
            deep_3drecon/BFM/01_MorphableModel.mat
         | 
| 8 | 
            +
            deep_3drecon/BFM/BFM_model_front.mat
         | 
| 9 | 
            +
            deep_3drecon/network/FaceReconModel.pb
         | 
| 10 | 
            +
            deep_3drecon/checkpoints/*
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            .vscode
         | 
| 13 | 
            +
            ### Project ignore
         | 
| 14 | 
            +
            /checkpoints/*
         | 
| 15 | 
            +
            !/checkpoints/.gitkeep
         | 
| 16 | 
            +
            /data/*
         | 
| 17 | 
            +
            !/data/.gitkeep
         | 
| 18 | 
            +
            infer_out
         | 
| 19 | 
            +
            rsync
         | 
| 20 | 
            +
            .idea
         | 
| 21 | 
            +
            .DS_Store
         | 
| 22 | 
            +
            bak
         | 
| 23 | 
            +
            tmp
         | 
| 24 | 
            +
            *.tar.gz
         | 
| 25 | 
            +
            mos
         | 
| 26 | 
            +
            nbs
         | 
| 27 | 
            +
            /configs_usr/*
         | 
| 28 | 
            +
            !/configs_usr/.gitkeep
         | 
| 29 | 
            +
            /egs_usr/*
         | 
| 30 | 
            +
            !/egs_usr/.gitkeep
         | 
| 31 | 
            +
            /rnnoise
         | 
| 32 | 
            +
            #/usr/*
         | 
| 33 | 
            +
            #!/usr/.gitkeep
         | 
| 34 | 
            +
            scripts_usr
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            # Created by .ignore support plugin (hsz.mobi)
         | 
| 37 | 
            +
            ### Python template
         | 
| 38 | 
            +
            # Byte-compiled / optimized / DLL files
         | 
| 39 | 
            +
            __pycache__/
         | 
| 40 | 
            +
            *.py[cod]
         | 
| 41 | 
            +
            *$py.class
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            # C extensions
         | 
| 44 | 
            +
            *.so
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            # Distribution / packaging
         | 
| 47 | 
            +
            .Python
         | 
| 48 | 
            +
            build/
         | 
| 49 | 
            +
            develop-eggs/
         | 
| 50 | 
            +
            dist/
         | 
| 51 | 
            +
            downloads/
         | 
| 52 | 
            +
            eggs/
         | 
| 53 | 
            +
            .eggs/
         | 
| 54 | 
            +
            lib/
         | 
| 55 | 
            +
            lib64/
         | 
| 56 | 
            +
            parts/
         | 
| 57 | 
            +
            sdist/
         | 
| 58 | 
            +
            var/
         | 
| 59 | 
            +
            wheels/
         | 
| 60 | 
            +
            pip-wheel-metadata/
         | 
| 61 | 
            +
            share/python-wheels/
         | 
| 62 | 
            +
            *.egg-info/
         | 
| 63 | 
            +
            .installed.cfg
         | 
| 64 | 
            +
            *.egg
         | 
| 65 | 
            +
            MANIFEST
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            # PyInstaller
         | 
| 68 | 
            +
            #  Usually these files are written by a python script from a template
         | 
| 69 | 
            +
            #  before PyInstaller builds the exe, so as to inject date/other infos into it.
         | 
| 70 | 
            +
            *.manifest
         | 
| 71 | 
            +
            *.spec
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            # Installer logs
         | 
| 74 | 
            +
            pip-log.txt
         | 
| 75 | 
            +
            pip-delete-this-directory.txt
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            # Unit test / coverage reports
         | 
| 78 | 
            +
            htmlcov/
         | 
| 79 | 
            +
            .tox/
         | 
| 80 | 
            +
            .nox/
         | 
| 81 | 
            +
            .coverage
         | 
| 82 | 
            +
            .coverage.*
         | 
| 83 | 
            +
            .cache
         | 
| 84 | 
            +
            nosetests.xml
         | 
| 85 | 
            +
            coverage.xml
         | 
| 86 | 
            +
            *.cover
         | 
| 87 | 
            +
            .hypothesis/
         | 
| 88 | 
            +
            .pytest_cache/
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            # Translations
         | 
| 91 | 
            +
            *.mo
         | 
| 92 | 
            +
            *.pot
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            # Django stuff:
         | 
| 95 | 
            +
            *.log
         | 
| 96 | 
            +
            local_settings.py
         | 
| 97 | 
            +
            db.sqlite3
         | 
| 98 | 
            +
            db.sqlite3-journal
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            # Flask stuff:
         | 
| 101 | 
            +
            instance/
         | 
| 102 | 
            +
            .webassets-cache
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            # Scrapy stuff:
         | 
| 105 | 
            +
            .scrapy
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            # Sphinx documentation
         | 
| 108 | 
            +
            docs/_build/
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            # PyBuilder
         | 
| 111 | 
            +
            target/
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            # Jupyter Notebook
         | 
| 114 | 
            +
            .ipynb_checkpoints
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            # IPython
         | 
| 117 | 
            +
            profile_default/
         | 
| 118 | 
            +
            ipython_config.py
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            # pyenv
         | 
| 121 | 
            +
            .python-version
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            # pipenv
         | 
| 124 | 
            +
            #   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
         | 
| 125 | 
            +
            #   However, in case of collaboration, if having platform-specific dependencies or dependencies
         | 
| 126 | 
            +
            #   having no cross-platform support, pipenv may install dependencies that don't work, or not
         | 
| 127 | 
            +
            #   install all needed dependencies.
         | 
| 128 | 
            +
            #Pipfile.lock
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            # celery beat schedule file
         | 
| 131 | 
            +
            celerybeat-schedule
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            # SageMath parsed files
         | 
| 134 | 
            +
            *.sage.py
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            # Environments
         | 
| 137 | 
            +
            .env
         | 
| 138 | 
            +
            .venv
         | 
| 139 | 
            +
            env/
         | 
| 140 | 
            +
            venv/
         | 
| 141 | 
            +
            ENV/
         | 
| 142 | 
            +
            env.bak/
         | 
| 143 | 
            +
            venv.bak/
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            # Spyder project settings
         | 
| 146 | 
            +
            .spyderproject
         | 
| 147 | 
            +
            .spyproject
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            # Rope project settings
         | 
| 150 | 
            +
            .ropeproject
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            # mkdocs documentation
         | 
| 153 | 
            +
            /site
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            # mypy
         | 
| 156 | 
            +
            .mypy_cache/
         | 
| 157 | 
            +
            .dmypy.json
         | 
| 158 | 
            +
            dmypy.json
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            # Pyre type checker
         | 
| 161 | 
            +
            .pyre/
         | 
| 162 | 
            +
            data_util/deepspeech_features/deepspeech-0.9.2-models.pbmm
         | 
| 163 | 
            +
            deep_3drecon/mesh_renderer/bazel-bin
         | 
| 164 | 
            +
            deep_3drecon/mesh_renderer/bazel-mesh_renderer
         | 
| 165 | 
            +
            deep_3drecon/mesh_renderer/bazel-out
         | 
| 166 | 
            +
            deep_3drecon/mesh_renderer/bazel-testlogs
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            .nfs*
         | 
| 169 | 
            +
            infer_outs/*
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            *.pth
         | 
| 172 | 
            +
            venv_113/*
         | 
| 173 | 
            +
            *.pt
         | 
| 174 | 
            +
            experiments/trials
         | 
| 175 | 
            +
            flame_3drecon/*
         | 
| 176 | 
            +
             | 
| 177 | 
            +
            temp/
         | 
| 178 | 
            +
            /kill.sh
         | 
| 179 | 
            +
            /datasets
         | 
| 180 | 
            +
            data_util/imagenet_classes.txt
         | 
| 181 | 
            +
            process_data_May.sh
         | 
| 182 | 
            +
            /env_prepare_reproduce.md
         | 
| 183 | 
            +
            /my_debug.py
         | 
| 184 | 
            +
             | 
| 185 | 
            +
            utils/metrics/shape_predictor_68_face_landmarks.dat
         | 
| 186 | 
            +
            *.mp4
         | 
| 187 | 
            +
            _torchshow/
         | 
| 188 | 
            +
            *.png
         | 
| 189 | 
            +
            *.jpg
         | 
| 190 | 
            +
             | 
| 191 | 
            +
            *.mrc
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            deep_3drecon/BFM/BFM_exp_idx.mat
         | 
| 194 | 
            +
            deep_3drecon/BFM/BFM_front_idx.mat
         | 
| 195 | 
            +
            deep_3drecon/BFM/facemodel_info.mat
         | 
| 196 | 
            +
            deep_3drecon/BFM/index_mp468_from_mesh35709.npy
         | 
| 197 | 
            +
            deep_3drecon/BFM/mediapipe_in_bfm53201.npy
         | 
| 198 | 
            +
            deep_3drecon/BFM/std_exp.txt
         | 
| 199 | 
            +
            !data/raw/examples/*
         | 
    	
        LICENSE
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            MIT License
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2024 ZhenhuiYe
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 7 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 8 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 9 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 10 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            The above copyright notice and this permission notice shall be included in all
         | 
| 13 | 
            +
            copies or substantial portions of the Software.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 16 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 17 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 18 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 19 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 20 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         | 
| 21 | 
            +
            SOFTWARE.
         | 
    	
        README-zh.md
    ADDED
    
    | @@ -0,0 +1,144 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # Real3D-Portrait: One-shot Realistic 3D Talking Portrait Synthesis | ICLR 2024 Spotlight
         | 
| 2 | 
            +
            [](https://arxiv.org/abs/2401.08503)| [](https://github.com/yerfor/Real3DPortrait) | [English Readme](./README.md)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            这个仓库是Real3D-Portrait的官方PyTorch实现, 用于实现单参考图(one-shot)、高视频真实度(video reality)的虚拟人视频合成。您可以访问我们的[项目页面](https://real3dportrait.github.io/)以观看Demo视频, 阅读我们的[论文](https://arxiv.org/pdf/2401.08503.pdf)以了解技术细节。
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <p align="center">
         | 
| 8 | 
            +
                <br>
         | 
| 9 | 
            +
                <img src="assets/real3dportrait.png" width="100%"/>
         | 
| 10 | 
            +
                <br>
         | 
| 11 | 
            +
            </p>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ## 您可能同样感兴趣
         | 
| 14 | 
            +
            - 我们发布了GeneFace++([https://github.com/yerfor/GeneFacePlusPlus](https://github.com/yerfor/GeneFacePlusPlus)), 一个专注于提升单个特定说话人效果的说话人合成系统,它实现了高嘴形对齐、高视频质量和高系统效率。
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
            # 快速上手!
         | 
| 18 | 
            +
            ## 安装环境
         | 
| 19 | 
            +
            请参照[环境配置文档](docs/prepare_env/install_guide-zh.md),配置Conda环境`real3dportrait`
         | 
| 20 | 
            +
            ## 下载预训练与第三方模型
         | 
| 21 | 
            +
            ### 3DMM BFM模型
         | 
| 22 | 
            +
            下载3DMM BFM模型:[Google Drive](https://drive.google.com/drive/folders/1o4t5YIw7w4cMUN4bgU9nPf6IyWVG1bEk?usp=sharing) 或 [BaiduYun Disk](https://pan.baidu.com/s/1aqv1z_qZ23Vp2VP4uxxblQ?pwd=m9q5 ) 提取码: m9q5
         | 
| 23 | 
            +
             | 
| 24 | 
            +
             | 
| 25 | 
            +
            下载完成后,放置全部的文件到`deep_3drecon/BFM`里,文件结构如下:
         | 
| 26 | 
            +
            ```
         | 
| 27 | 
            +
            deep_3drecon/BFM/
         | 
| 28 | 
            +
            ├── 01_MorphableModel.mat
         | 
| 29 | 
            +
            ├── BFM_exp_idx.mat
         | 
| 30 | 
            +
            ├── BFM_front_idx.mat
         | 
| 31 | 
            +
            ├── BFM_model_front.mat
         | 
| 32 | 
            +
            ├── Exp_Pca.bin
         | 
| 33 | 
            +
            ├── facemodel_info.mat
         | 
| 34 | 
            +
            ├── index_mp468_from_mesh35709.npy
         | 
| 35 | 
            +
            ├── mediapipe_in_bfm53201.npy
         | 
| 36 | 
            +
            └── std_exp.txt
         | 
| 37 | 
            +
            ```
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            ### 预训练模型
         | 
| 40 | 
            +
            下载预训练的Real3D-Portrait:[Google Drive](https://drive.google.com/drive/folders/1MAveJf7RvJ-Opg1f5qhLdoRoC_Gc6nD9?usp=sharing) 或 [BaiduYun Disk](https://pan.baidu.com/s/1Mjmbn0UtA1Zm9owZ7zWNgQ?pwd=6x4f ) 提取码: 6x4f
         | 
| 41 | 
            +
              
         | 
| 42 | 
            +
            下载完成后,放置全部的文件到`checkpoints`里并解压,文件结构如下:
         | 
| 43 | 
            +
            ```
         | 
| 44 | 
            +
            checkpoints/
         | 
| 45 | 
            +
            ├── 240210_real3dportrait_orig
         | 
| 46 | 
            +
            │   ├── audio2secc_vae
         | 
| 47 | 
            +
            │   │   ├── config.yaml
         | 
| 48 | 
            +
            │   │   └── model_ckpt_steps_400000.ckpt
         | 
| 49 | 
            +
            │   └── secc2plane_torso_orig
         | 
| 50 | 
            +
            │       ├── config.yaml
         | 
| 51 | 
            +
            │       └── model_ckpt_steps_100000.ckpt
         | 
| 52 | 
            +
            └── pretrained_ckpts
         | 
| 53 | 
            +
                └── mit_b0.pth
         | 
| 54 | 
            +
            ```
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            ## 推理测试
         | 
| 57 | 
            +
            我们目前提供了**命令行(CLI)**, **Gradio WebUI**与**Google Colab**推理方式。我们同时支持音频驱动(Audio-Driven)与视频驱动(Video-Driven):
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            - 音频驱动场景下,需要至少提供`source image`与`driving audio`
         | 
| 60 | 
            +
            - 视频驱动场景下,需要至少提供`source image`与`driving expression video`
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            ### Gradio WebUI推理
         | 
| 63 | 
            +
            启动Gradio WebUI,按照提示上传素材,点击`Generate`按钮即可推理:
         | 
| 64 | 
            +
            ```bash
         | 
| 65 | 
            +
            python inference/app_real3dportrait.py
         | 
| 66 | 
            +
            ```
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            ### Google Colab推理
         | 
| 69 | 
            +
            运行这个[Colab](https://colab.research.google.com/github/yerfor/Real3DPortrait/blob/main/inference/real3dportrait_demo.ipynb)中的所有cell。
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            ### 命令行推理
         | 
| 72 | 
            +
            首先,切换至项目根目录并启用Conda环境:
         | 
| 73 | 
            +
            ```bash
         | 
| 74 | 
            +
            cd <Real3DPortraitRoot>
         | 
| 75 | 
            +
            conda activate real3dportrait
         | 
| 76 | 
            +
            export PYTHON_PATH=./
         | 
| 77 | 
            +
            ```
         | 
| 78 | 
            +
            音频驱动场景下,需要至少提供source image与driving audio,推理指令:
         | 
| 79 | 
            +
            ```bash
         | 
| 80 | 
            +
            python inference/real3d_infer.py \
         | 
| 81 | 
            +
            --src_img <PATH_TO_SOURCE_IMAGE> \
         | 
| 82 | 
            +
            --drv_aud <PATH_TO_AUDIO> \
         | 
| 83 | 
            +
            --drv_pose <PATH_TO_POSE_VIDEO, OPTIONAL> \
         | 
| 84 | 
            +
            --bg_img <PATH_TO_BACKGROUND_IMAGE, OPTIONAL> \
         | 
| 85 | 
            +
            --out_name <PATH_TO_OUTPUT_VIDEO, OPTIONAL>
         | 
| 86 | 
            +
            ```
         | 
| 87 | 
            +
            视频驱动场景下,需要至少提供source image与driving expression video(作为drv_aud参数),推理指令:
         | 
| 88 | 
            +
            ```bash
         | 
| 89 | 
            +
            python inference/real3d_infer.py \
         | 
| 90 | 
            +
            --src_img <PATH_TO_SOURCE_IMAGE> \
         | 
| 91 | 
            +
            --drv_aud <PATH_TO_EXP_VIDEO> \
         | 
| 92 | 
            +
            --drv_pose <PATH_TO_POSE_VIDEO, OPTIONAL> \
         | 
| 93 | 
            +
            --bg_img <PATH_TO_BACKGROUND_IMAGE, OPTIONAL> \
         | 
| 94 | 
            +
            --out_name <PATH_TO_OUTPUT_VIDEO, OPTIONAL>
         | 
| 95 | 
            +
            ```
         | 
| 96 | 
            +
            一些可选参数注释:
         | 
| 97 | 
            +
            - `--drv_pose` 指定时提供了运动pose信息,不指定则为静态运动
         | 
| 98 | 
            +
            - `--bg_img` 指定时提供了背景信息,不指定则为source image提取的背景
         | 
| 99 | 
            +
            - `--mouth_amp` 嘴部张幅参数,值越大张幅越大
         | 
| 100 | 
            +
            - `--map_to_init_pose` 值为`True`时,首帧的pose将被映射到source pose,后续帧也作相同变换
         | 
| 101 | 
            +
            - `--temperature` 代表audio2motion的采样温度,值越大结果越多样,但同时精确度越低
         | 
| 102 | 
            +
            - `--out_name` 不指定时,结果将保存在`infer_out/tmp/`中
         | 
| 103 | 
            +
            - `--out_mode` 值为`final`时,只输出说话人视频;值为`concat_debug`时,同时输出一些可视化的中间结果
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            指令示例:
         | 
| 106 | 
            +
            ```bash
         | 
| 107 | 
            +
            python inference/real3d_infer.py \
         | 
| 108 | 
            +
            --src_img data/raw/examples/Macron.png \
         | 
| 109 | 
            +
            --drv_aud data/raw/examples/Obama_5s.wav \
         | 
| 110 | 
            +
            --drv_pose data/raw/examples/May_5s.mp4 \
         | 
| 111 | 
            +
            --bg_img data/raw/examples/bg.png \
         | 
| 112 | 
            +
            --out_name output.mp4 \
         | 
| 113 | 
            +
            --out_mode concat_debug
         | 
| 114 | 
            +
            ```
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            ## ToDo
         | 
| 117 | 
            +
            - [x] **Release Pre-trained weights of Real3D-Portrait.**
         | 
| 118 | 
            +
            - [x] **Release Inference Code of Real3D-Portrait.**
         | 
| 119 | 
            +
            - [x] **Release Gradio Demo of Real3D-Portrait..**
         | 
| 120 | 
            +
            - [x] **Release Google Colab of Real3D-Portrait..**
         | 
| 121 | 
            +
            - [ ] **Release Training Code of Real3D-Portrait.**
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            # 引用我们
         | 
| 124 | 
            +
            如果这个仓库对你有帮助,请考虑引用我们的工作:
         | 
| 125 | 
            +
            ```
         | 
| 126 | 
            +
            @article{ye2024real3d,
         | 
| 127 | 
            +
              title={Real3D-Portrait: One-shot Realistic 3D Talking Portrait Synthesis},
         | 
| 128 | 
            +
              author={Ye, Zhenhui and Zhong, Tianyun and Ren, Yi and Yang, Jiaqi and Li, Weichuang and Huang, Jiawei and Jiang, Ziyue and He, Jinzheng and Huang, Rongjie and Liu, Jinglin and others},
         | 
| 129 | 
            +
              journal={arXiv preprint arXiv:2401.08503},
         | 
| 130 | 
            +
              year={2024}
         | 
| 131 | 
            +
            }
         | 
| 132 | 
            +
            @article{ye2023geneface++,
         | 
| 133 | 
            +
              title={GeneFace++: Generalized and Stable Real-Time Audio-Driven 3D Talking Face Generation},
         | 
| 134 | 
            +
              author={Ye, Zhenhui and He, Jinzheng and Jiang, Ziyue and Huang, Rongjie and Huang, Jiawei and Liu, Jinglin and Ren, Yi and Yin, Xiang and Ma, Zejun and Zhao, Zhou},
         | 
| 135 | 
            +
              journal={arXiv preprint arXiv:2305.00787},
         | 
| 136 | 
            +
              year={2023}
         | 
| 137 | 
            +
            }
         | 
| 138 | 
            +
            @article{ye2023geneface,
         | 
| 139 | 
            +
              title={GeneFace: Generalized and High-Fidelity Audio-Driven 3D Talking Face Synthesis},
         | 
| 140 | 
            +
              author={Ye, Zhenhui and Jiang, Ziyue and Ren, Yi and Liu, Jinglin and He, Jinzheng and Zhao, Zhou},
         | 
| 141 | 
            +
              journal={arXiv preprint arXiv:2301.13430},
         | 
| 142 | 
            +
              year={2023}
         | 
| 143 | 
            +
            }
         | 
| 144 | 
            +
            ```
         | 
    	
        README.md
    ADDED
    
    | @@ -0,0 +1,149 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # Real3D-Portrait: One-shot Realistic 3D Talking Portrait Synthesis | ICLR 2024 Spotlight
         | 
| 2 | 
            +
            [](https://arxiv.org/abs/2401.08503)| [](https://github.com/yerfor/Real3DPortrait) | [中文文档](./README-zh.md)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            This is the official repo of Real3D-Portrait with Pytorch implementation, for one-shot and high video reality talking portrait synthesis. You can visit our [Demo Page](https://real3dportrait.github.io/) for watching demo videos, and read our [Paper](https://arxiv.org/pdf/2401.08503.pdf) for technical details.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <p align="center">
         | 
| 8 | 
            +
                <br>
         | 
| 9 | 
            +
                <img src="assets/real3dportrait.png" width="100%"/>
         | 
| 10 | 
            +
                <br>
         | 
| 11 | 
            +
            </p>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ## 🔥 Update
         | 
| 14 | 
            +
            - \[2024.07.02\] We release the training code of the whole system, including audio-to-motion model, image-to-plane model, secc2plane model, and the secc2plane_torso model, please refer to `docs/train_models`. We also release the code to preprocess and binarize the dataset, please refer to `docs/process_data`. Thanks for your patience!
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ## You may also interested in 
         | 
| 17 | 
            +
            - We release the code of GeneFace++, ([https://github.com/yerfor/GeneFacePlusPlus](https://github.com/yerfor/GeneFacePlusPlus)), a NeRF-based person-specific talking face system, which aims at producing high-quality talking face videos with extreme idenetity-similarity of the target person.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # Quick Start!
         | 
| 20 | 
            +
            ## Environment Installation
         | 
| 21 | 
            +
            Please refer to [Installation Guide](docs/prepare_env/install_guide.md), prepare a Conda environment `real3dportrait`.
         | 
| 22 | 
            +
            ## Download Pre-trained & Third-Party Models
         | 
| 23 | 
            +
            ### 3DMM BFM Model
         | 
| 24 | 
            +
            Download 3DMM BFM Model from [Google Drive](https://drive.google.com/drive/folders/1o4t5YIw7w4cMUN4bgU9nPf6IyWVG1bEk?usp=sharing) or [BaiduYun Disk](https://pan.baidu.com/s/1aqv1z_qZ23Vp2VP4uxxblQ?pwd=m9q5 ) with Password m9q5. 
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            Put all the files in `deep_3drecon/BFM`, the file structure will be like this:
         | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
            deep_3drecon/BFM/
         | 
| 30 | 
            +
            ├── 01_MorphableModel.mat
         | 
| 31 | 
            +
            ├── BFM_exp_idx.mat
         | 
| 32 | 
            +
            ├── BFM_front_idx.mat
         | 
| 33 | 
            +
            ├── BFM_model_front.mat
         | 
| 34 | 
            +
            ├── Exp_Pca.bin
         | 
| 35 | 
            +
            ├── facemodel_info.mat
         | 
| 36 | 
            +
            ├── index_mp468_from_mesh35709.npy
         | 
| 37 | 
            +
            ├── mediapipe_in_bfm53201.npy
         | 
| 38 | 
            +
            └── std_exp.txt
         | 
| 39 | 
            +
            ```
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            ### Pre-trained Real3D-Portrait
         | 
| 42 | 
            +
            Download Pre-trained Real3D-Portrait:[Google Drive](https://drive.google.com/drive/folders/1MAveJf7RvJ-Opg1f5qhLdoRoC_Gc6nD9?usp=sharing) or [BaiduYun Disk](https://pan.baidu.com/s/1Mjmbn0UtA1Zm9owZ7zWNgQ?pwd=6x4f ) with Password 6x4f
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
            Put the zip files in `checkpoints` and unzip them, the file structure will be like this:
         | 
| 45 | 
            +
            ```
         | 
| 46 | 
            +
            checkpoints/
         | 
| 47 | 
            +
            ├── 240210_real3dportrait_orig
         | 
| 48 | 
            +
            │   ├── audio2secc_vae
         | 
| 49 | 
            +
            │   │   ├── config.yaml
         | 
| 50 | 
            +
            │   │   └── model_ckpt_steps_400000.ckpt
         | 
| 51 | 
            +
            │   └── secc2plane_torso_orig
         | 
| 52 | 
            +
            │       ├── config.yaml
         | 
| 53 | 
            +
            │       └── model_ckpt_steps_100000.ckpt
         | 
| 54 | 
            +
            └── pretrained_ckpts
         | 
| 55 | 
            +
                └── mit_b0.pth
         | 
| 56 | 
            +
            ```
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            ## Inference
         | 
| 59 | 
            +
            Currently, we provide **CLI**, **Gradio WebUI** and **Google Colab** for inference. We support both Audio-Driven and Video-Driven methods:
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            - For audio-driven, at least prepare `source image` and `driving audio`
         | 
| 62 | 
            +
            - For video-driven, at least prepare `source image` and `driving expression video`
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ### Gradio WebUI
         | 
| 65 | 
            +
            Run Gradio WebUI demo, upload resouces in webpage,click `Generate` button to inference:
         | 
| 66 | 
            +
            ```bash
         | 
| 67 | 
            +
            python inference/app_real3dportrait.py
         | 
| 68 | 
            +
            ```
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            ### Google Colab
         | 
| 71 | 
            +
            Run all the cells in this [Colab](https://colab.research.google.com/github/yerfor/Real3DPortrait/blob/main/inference/real3dportrait_demo.ipynb).
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            ### CLI Inference
         | 
| 74 | 
            +
            Firstly, switch to project folder and activate conda environment:
         | 
| 75 | 
            +
            ```bash
         | 
| 76 | 
            +
            cd <Real3DPortraitRoot>
         | 
| 77 | 
            +
            conda activate real3dportrait
         | 
| 78 | 
            +
            export PYTHONPATH=./
         | 
| 79 | 
            +
            ```
         | 
| 80 | 
            +
            For audio-driven, provide source image and driving audio:
         | 
| 81 | 
            +
            ```bash
         | 
| 82 | 
            +
            python inference/real3d_infer.py \
         | 
| 83 | 
            +
            --src_img <PATH_TO_SOURCE_IMAGE> \
         | 
| 84 | 
            +
            --drv_aud <PATH_TO_AUDIO> \
         | 
| 85 | 
            +
            --drv_pose <PATH_TO_POSE_VIDEO, OPTIONAL> \
         | 
| 86 | 
            +
            --bg_img <PATH_TO_BACKGROUND_IMAGE, OPTIONAL> \
         | 
| 87 | 
            +
            --out_name <PATH_TO_OUTPUT_VIDEO, OPTIONAL>
         | 
| 88 | 
            +
            ```
         | 
| 89 | 
            +
            For video-driven, provide source image and driving expression video(as `--drv_aud` parameter):
         | 
| 90 | 
            +
            ```bash
         | 
| 91 | 
            +
            python inference/real3d_infer.py \
         | 
| 92 | 
            +
            --src_img <PATH_TO_SOURCE_IMAGE> \
         | 
| 93 | 
            +
            --drv_aud <PATH_TO_EXP_VIDEO> \
         | 
| 94 | 
            +
            --drv_pose <PATH_TO_POSE_VIDEO, OPTIONAL> \
         | 
| 95 | 
            +
            --bg_img <PATH_TO_BACKGROUND_IMAGE, OPTIONAL> \
         | 
| 96 | 
            +
            --out_name <PATH_TO_OUTPUT_VIDEO, OPTIONAL>
         | 
| 97 | 
            +
            ```
         | 
| 98 | 
            +
            Some optional parameters:
         | 
| 99 | 
            +
            - `--drv_pose` provide motion pose information, default to be static poses
         | 
| 100 | 
            +
            - `--bg_img` provide background information, default to be image extracted from source
         | 
| 101 | 
            +
            - `--mouth_amp` mouth amplitude, higher value leads to wider mouth
         | 
| 102 | 
            +
            - `--map_to_init_pose` when set to `True`, the initial pose will be mapped to source pose, and other poses will be equally transformed
         | 
| 103 | 
            +
            - `--temperature` stands for the sampling temperature of audio2motion, higher for more diverse results at the expense of lower accuracy
         | 
| 104 | 
            +
            - `--out_name` When not assigned, the results will be stored at `infer_out/tmp/`.
         | 
| 105 | 
            +
            - `--out_mode` When `final`, only outputs the final result; when `concat_debug`, also outputs visualization of several intermediate process.
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            Commandline example:
         | 
| 108 | 
            +
            ```bash
         | 
| 109 | 
            +
            python inference/real3d_infer.py \
         | 
| 110 | 
            +
            --src_img data/raw/examples/Macron.png \
         | 
| 111 | 
            +
            --drv_aud data/raw/examples/Obama_5s.wav \
         | 
| 112 | 
            +
            --drv_pose data/raw/examples/May_5s.mp4 \
         | 
| 113 | 
            +
            --bg_img data/raw/examples/bg.png \
         | 
| 114 | 
            +
            --out_name output.mp4 \
         | 
| 115 | 
            +
            --out_mode concat_debug
         | 
| 116 | 
            +
            ```
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            # ToDo
         | 
| 119 | 
            +
            - [x] **Release Pre-trained weights of Real3D-Portrait.**
         | 
| 120 | 
            +
            - [x] **Release Inference Code of Real3D-Portrait.**
         | 
| 121 | 
            +
            - [x] **Release Gradio Demo of Real3D-Portrait..**
         | 
| 122 | 
            +
            - [x] **Release Google Colab of Real3D-Portrait..**
         | 
| 123 | 
            +
            - [ ] **Release Training Code of Real3D-Portrait.**
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            # Disclaimer
         | 
| 126 | 
            +
            Any organization or individual is prohibited from using any technology mentioned in this paper to generate someone's talking video without his/her consent, including but not limited to government leaders, political figures, and celebrities. If you do not comply with this item, you could be in violation of copyright laws.
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            # Citation
         | 
| 129 | 
            +
            If you found this repo helpful to your work, please consider cite us:
         | 
| 130 | 
            +
            ```
         | 
| 131 | 
            +
            @article{ye2024real3d,
         | 
| 132 | 
            +
              title={Real3D-Portrait: One-shot Realistic 3D Talking Portrait Synthesis},
         | 
| 133 | 
            +
              author={Ye, Zhenhui and Zhong, Tianyun and Ren, Yi and Yang, Jiaqi and Li, Weichuang and Huang, Jiawei and Jiang, Ziyue and He, Jinzheng and Huang, Rongjie and Liu, Jinglin and others},
         | 
| 134 | 
            +
              journal={arXiv preprint arXiv:2401.08503},
         | 
| 135 | 
            +
              year={2024}
         | 
| 136 | 
            +
            }
         | 
| 137 | 
            +
            @article{ye2023geneface++,
         | 
| 138 | 
            +
              title={GeneFace++: Generalized and Stable Real-Time Audio-Driven 3D Talking Face Generation},
         | 
| 139 | 
            +
              author={Ye, Zhenhui and He, Jinzheng and Jiang, Ziyue and Huang, Rongjie and Huang, Jiawei and Liu, Jinglin and Ren, Yi and Yin, Xiang and Ma, Zejun and Zhao, Zhou},
         | 
| 140 | 
            +
              journal={arXiv preprint arXiv:2305.00787},
         | 
| 141 | 
            +
              year={2023}
         | 
| 142 | 
            +
            }
         | 
| 143 | 
            +
            @article{ye2023geneface,
         | 
| 144 | 
            +
              title={GeneFace: Generalized and High-Fidelity Audio-Driven 3D Talking Face Synthesis},
         | 
| 145 | 
            +
              author={Ye, Zhenhui and Jiang, Ziyue and Ren, Yi and Liu, Jinglin and He, Jinzheng and Zhao, Zhou},
         | 
| 146 | 
            +
              journal={arXiv preprint arXiv:2301.13430},
         | 
| 147 | 
            +
              year={2023}
         | 
| 148 | 
            +
            }
         | 
| 149 | 
            +
            ```
         | 
    	
        TalkingHead-1KH/.gitignore
    ADDED
    
    | @@ -0,0 +1,2 @@ | |
|  | |
|  | 
|  | |
| 1 | 
            +
            data/
         | 
| 2 | 
            +
            .DS_Store
         | 
    	
        TalkingHead-1KH/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,42 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
         | 
| 2 | 
            +
            # SPDX-License-Identifier: MIT
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Permission is hereby granted, free of charge, to any person obtaining a
         | 
| 5 | 
            +
            # copy of this software and associated documentation files (the "Software"),
         | 
| 6 | 
            +
            # to deal in the Software without restriction, including without limitation
         | 
| 7 | 
            +
            # the rights to use, copy, modify, merge, publish, distribute, sublicense,
         | 
| 8 | 
            +
            # and/or sell copies of the Software, and to permit persons to whom the
         | 
| 9 | 
            +
            # Software is furnished to do so, subject to the following conditions:
         | 
| 10 | 
            +
            #
         | 
| 11 | 
            +
            # The above copyright notice and this permission notice shall be included in
         | 
| 12 | 
            +
            # all copies or substantial portions of the Software.
         | 
| 13 | 
            +
            #
         | 
| 14 | 
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 15 | 
            +
            # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 16 | 
            +
            # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
         | 
| 17 | 
            +
            # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 18 | 
            +
            # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
         | 
| 19 | 
            +
            # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
         | 
| 20 | 
            +
            # DEALINGS IN THE SOFTWARE.
         | 
| 21 | 
            +
            /*
         | 
| 22 | 
            +
             * SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
         | 
| 23 | 
            +
             * SPDX-License-Identifier: MIT
         | 
| 24 | 
            +
             *
         | 
| 25 | 
            +
             * Permission is hereby granted, free of charge, to any person obtaining a
         | 
| 26 | 
            +
             * copy of this software and associated documentation files (the "Software"),
         | 
| 27 | 
            +
             * to deal in the Software without restriction, including without limitation
         | 
| 28 | 
            +
             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
         | 
| 29 | 
            +
             * and/or sell copies of the Software, and to permit persons to whom the
         | 
| 30 | 
            +
             * Software is furnished to do so, subject to the following conditions:
         | 
| 31 | 
            +
             *
         | 
| 32 | 
            +
             * The above copyright notice and this permission notice shall be included in
         | 
| 33 | 
            +
             * all copies or substantial portions of the Software.
         | 
| 34 | 
            +
             *
         | 
| 35 | 
            +
             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 36 | 
            +
             * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 37 | 
            +
             * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
         | 
| 38 | 
            +
             * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 39 | 
            +
             * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
         | 
| 40 | 
            +
             * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
         | 
| 41 | 
            +
             * DEALINGS IN THE SOFTWARE.
         | 
| 42 | 
            +
             */
         | 
    	
        TalkingHead-1KH/README.md
    ADDED
    
    | @@ -0,0 +1,84 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            ## TalkingHead-1KH Dataset
         | 
| 2 | 
            +
            
         | 
| 3 | 
            +
            
         | 
| 4 | 
            +
            
         | 
| 5 | 
            +
            
         | 
| 6 | 
            +
            
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            <img src='teaser.gif' width='800'/>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            TalkingHead-1KH is a talking-head dataset consisting of YouTube videos, originally created as a benchmark for face-vid2vid:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            > **One-Shot Free-View Neural Talking-Head Synthesis for Video Conferencing**<br>
         | 
| 14 | 
            +
            > Ting-Chun Wang (NVIDIA), Arun Mallya (NVIDIA), Ming-Yu Liu (NVIDIA)<br>
         | 
| 15 | 
            +
            > https://nvlabs.github.io/face-vid2vid/<br>
         | 
| 16 | 
            +
            > https://arxiv.org/abs/2011.15126.pdf
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            The dataset consists of 500k video clips, of which about 80k are greater than 512x512 resolution. Only videos under permissive licenses are included. Note that the number of videos differ from that in the original paper because a more robust preprocessing script was used to split the videos.
         | 
| 19 | 
            +
            For business inquiries, please visit our website and submit the form: [NVIDIA Research Licensing](https://www.nvidia.com/en-us/research/inquiries/).
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## Download
         | 
| 23 | 
            +
            ### Unzip the video metadata
         | 
| 24 | 
            +
            First, unzip the metadata and put it under the root directory:
         | 
| 25 | 
            +
            ```bash
         | 
| 26 | 
            +
            unzip data_list.zip
         | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            ### Unit test
         | 
| 30 | 
            +
            This step downloads a small subset of the dataset to verify the scripts are working on your computer. You can also skip this step if you want to directly download the entire dataset.
         | 
| 31 | 
            +
            ```bash
         | 
| 32 | 
            +
            bash videos_download_and_crop.sh small
         | 
| 33 | 
            +
            ```
         | 
| 34 | 
            +
            The processed clips should appear in `small/cropped_clips`.
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            ### Download the entire dataset
         | 
| 37 | 
            +
            Please run
         | 
| 38 | 
            +
            ```bash
         | 
| 39 | 
            +
            bash videos_download_and_crop.sh train
         | 
| 40 | 
            +
            ```
         | 
| 41 | 
            +
            The script will automatically download the YouTube videos, split them into short clips, and then crop and trim them to include only the face regions. The final processed clips should appear in `train/cropped_clips`.
         | 
| 42 | 
            +
             | 
| 43 | 
            +
             | 
| 44 | 
            +
            ## Evaluation
         | 
| 45 | 
            +
            To download the evaluation set which consists of only 1080p videos, please run
         | 
| 46 | 
            +
            ```bash
         | 
| 47 | 
            +
            bash videos_download_and_crop.sh val
         | 
| 48 | 
            +
            ```
         | 
| 49 | 
            +
            The processed clips should appear in `val/cropped_clips`.
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            We also provide the reconstruction results synthesized by our model [here](https://drive.google.com/file/d/1BX9zaNL_zowTDruvRB3KvebaSUi3WHWc/view?usp=sharing).
         | 
| 52 | 
            +
            For each video, we use only the first frame to reconstruct all the following frames.
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            Furthermore, for models trained using the VoxCeleb2 dataset, we also provide comparisons using another model trained on the VoxCeleb2 dataset.
         | 
| 55 | 
            +
            Please find the reconstruction results [here](https://drive.google.com/file/d/1HVCFj7WOy9KHP1J76wn-ZExh-nQnff9g/view?usp=sharing).
         | 
| 56 | 
            +
             | 
| 57 | 
            +
             | 
| 58 | 
            +
            ## Licenses
         | 
| 59 | 
            +
            The individual videos were published in YouTube by their respective authors under [Creative Commons BY 3.0](https://creativecommons.org/licenses/by/3.0/legalcode) license.
         | 
| 60 | 
            +
            The metadata file, the download script file, the processing script file, and the documentation file are made available under [MIT](LICENSE.txt) license. You can **use, redistribute, and adapt it**, as long as you (a) give appropriate credit by **citing our paper**, (b) **indicate any changes** that you've made, and (c) distribute any derivative works **under the same license**.
         | 
| 61 | 
            +
             | 
| 62 | 
            +
             | 
| 63 | 
            +
            ## Privacy
         | 
| 64 | 
            +
            When collecting the data, we were careful to only include videos that – to the best of our knowledge – were intended for free use and redistribution by their respective authors. That said, we are committed to protecting the privacy of individuals who do not wish their videos to be included.
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            If you would like to remove your video from the dataset, you can either
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            1. Go to YouTube and change the license of your video, or remove your video entirely.
         | 
| 69 | 
            +
            2. Contact [[email protected]](mailto:[email protected]). Please include your YouTube video link in the email.
         | 
| 70 | 
            +
             | 
| 71 | 
            +
             | 
| 72 | 
            +
            ## Acknowledgements
         | 
| 73 | 
            +
            This webpage borrows heavily from the [FFHQ-dataset](https://github.com/NVlabs/ffhq-dataset) page.
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            ## Citation
         | 
| 76 | 
            +
            If you use this dataset for your work, please cite
         | 
| 77 | 
            +
            ```
         | 
| 78 | 
            +
            @inproceedings{wang2021facevid2vid,
         | 
| 79 | 
            +
              title={One-Shot Free-View Neural Talking-Head Synthesis for Video Conferencing},
         | 
| 80 | 
            +
              author={Ting-Chun Wang and Arun Mallya and Ming-Yu Liu},
         | 
| 81 | 
            +
              booktitle={CVPR},
         | 
| 82 | 
            +
              year={2021}
         | 
| 83 | 
            +
            }
         | 
| 84 | 
            +
            ```
         | 
    	
        TalkingHead-1KH/data_list.zip
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:fb6179ecac9f08c7c2d960cb8a36354e9fa2edde7215d1fc5a20d6a342050f1a
         | 
| 3 | 
            +
            size 6822806
         | 
    	
        TalkingHead-1KH/data_list/small_video_ids.txt
    ADDED
    
    | @@ -0,0 +1,2 @@ | |
|  | |
|  | 
|  | |
| 1 | 
            +
            --Y9imYnfBw
         | 
| 2 | 
            +
            -7TMJtnhiPM
         | 
    	
        TalkingHead-1KH/data_list/small_video_tubes.txt
    ADDED
    
    | @@ -0,0 +1,4 @@ | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            --Y9imYnfBw_0000, 720, 1280, 0, 271, 504, 63, 792, 351
         | 
| 2 | 
            +
            --Y9imYnfBw_0000, 720, 1280, 1015, 1107, 488, 23, 824, 359
         | 
| 3 | 
            +
            -7TMJtnhiPM_0000, 720, 1280, 1202, 1607, 345, 26, 857, 538
         | 
| 4 | 
            +
            -7TMJtnhiPM_0000, 720, 1280, 1608, 1674, 467, 52, 851, 436
         | 
    	
        TalkingHead-1KH/data_list/train_video_ids.txt
    ADDED
    
    | @@ -0,0 +1,2872 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            --Y9imYnfBw
         | 
| 2 | 
            +
            -5Lm-oibjJQ
         | 
| 3 | 
            +
            -7TMJtnhiPM
         | 
| 4 | 
            +
            -8lgFak3RwU
         | 
| 5 | 
            +
            -9qRhqjD7PY
         | 
| 6 | 
            +
            -A0jrCGS_TE
         | 
| 7 | 
            +
            -B1Z9vrjpgg
         | 
| 8 | 
            +
            -B9PTg7XynE
         | 
| 9 | 
            +
            -BNR218UFX4
         | 
| 10 | 
            +
            -BPwyGVD2ec
         | 
| 11 | 
            +
            -DiIOp80LOo
         | 
| 12 | 
            +
            -EM2xi5Jnd0
         | 
| 13 | 
            +
            -FbPk4SmV0M
         | 
| 14 | 
            +
            -GZFS7r2GJ0
         | 
| 15 | 
            +
            -GtLyhxJ4V4
         | 
| 16 | 
            +
            -II0hSGU52I
         | 
| 17 | 
            +
            -J3Z1m6vrCs
         | 
| 18 | 
            +
            -J9ECsMrNkY
         | 
| 19 | 
            +
            -KBiHKx54sg
         | 
| 20 | 
            +
            -KL3wSSFx10
         | 
| 21 | 
            +
            -Qi6_EcnYEI
         | 
| 22 | 
            +
            -RuxUoQQaT0
         | 
| 23 | 
            +
            -TNWOtcCbOU
         | 
| 24 | 
            +
            -UrrtxGsmoU
         | 
| 25 | 
            +
            -ZqVCfsj3yg
         | 
| 26 | 
            +
            -_A67wxucLo
         | 
| 27 | 
            +
            -_KOlZjGD9c
         | 
| 28 | 
            +
            -a7oWdSyePY
         | 
| 29 | 
            +
            -acp9Dk7Ve4
         | 
| 30 | 
            +
            -axp0KRQJYc
         | 
| 31 | 
            +
            -ayP3gFLy9s
         | 
| 32 | 
            +
            -cNe_z2qsGQ
         | 
| 33 | 
            +
            -dvajjXM2dg
         | 
| 34 | 
            +
            -dxGq0Mu0oY
         | 
| 35 | 
            +
            -flEiFmuh64
         | 
| 36 | 
            +
            -gnJtZFyzZA
         | 
| 37 | 
            +
            -hLsqlKm-A4
         | 
| 38 | 
            +
            -mingboa4sM
         | 
| 39 | 
            +
            -n-HQiT-mkw
         | 
| 40 | 
            +
            -o8Ns4hvhr0
         | 
| 41 | 
            +
            -qsTrNdfd1w
         | 
| 42 | 
            +
            -r-ckuF3JSg
         | 
| 43 | 
            +
            -tIO8GnrSJM
         | 
| 44 | 
            +
            -xlo-qTzC7s
         | 
| 45 | 
            +
            -yhJf04a1mI
         | 
| 46 | 
            +
            -zqAjBpG0Jw
         | 
| 47 | 
            +
            0-FQbhkWYuY
         | 
| 48 | 
            +
            04-JxYnzcq0
         | 
| 49 | 
            +
            04BN6UOVKOM
         | 
| 50 | 
            +
            04WJEEb33CY
         | 
| 51 | 
            +
            04fidgplUXU
         | 
| 52 | 
            +
            05e4nROsPHM
         | 
| 53 | 
            +
            06RuVZUbUc8
         | 
| 54 | 
            +
            07F4x2eeD1k
         | 
| 55 | 
            +
            0B5ojfWryqA
         | 
| 56 | 
            +
            0Fz4oferM-c
         | 
| 57 | 
            +
            0H-cSZFZq_4
         | 
| 58 | 
            +
            0ND-w_eEOQw
         | 
| 59 | 
            +
            0NLQfXOo0dM
         | 
| 60 | 
            +
            0OaM12UIeVA
         | 
| 61 | 
            +
            0OzxymzEo-A
         | 
| 62 | 
            +
            0P-9yxO2df4
         | 
| 63 | 
            +
            0PffDSC_cLU
         | 
| 64 | 
            +
            0PtUxdA35Zs
         | 
| 65 | 
            +
            0RQl9e11aeE
         | 
| 66 | 
            +
            0S269HFjKx0
         | 
| 67 | 
            +
            0SKHozldsNM
         | 
| 68 | 
            +
            0S_QNLx2S7E
         | 
| 69 | 
            +
            0X6ZN_eRaSI
         | 
| 70 | 
            +
            0_Jci9-d2VY
         | 
| 71 | 
            +
            0_udiqKlYuU
         | 
| 72 | 
            +
            0aHSV7nbEvE
         | 
| 73 | 
            +
            0aZJJHF4K8U
         | 
| 74 | 
            +
            0aiKZGqjvL4
         | 
| 75 | 
            +
            0bA8z8qYmdo
         | 
| 76 | 
            +
            0beHbJDqlOs
         | 
| 77 | 
            +
            0cSDEZ6NxM8
         | 
| 78 | 
            +
            0cfM5xNaaSQ
         | 
| 79 | 
            +
            0ez7IiBfCGE
         | 
| 80 | 
            +
            0hhbwkQ06EI
         | 
| 81 | 
            +
            0hmQbZUYG4o
         | 
| 82 | 
            +
            0kLlrDNq9RA
         | 
| 83 | 
            +
            0lOkJkh2Hwg
         | 
| 84 | 
            +
            0lcaZupVMmo
         | 
| 85 | 
            +
            0oE11MGQRZM
         | 
| 86 | 
            +
            0pQvRqU43eU
         | 
| 87 | 
            +
            0pe-7C_c-fY
         | 
| 88 | 
            +
            0rZJhc1FeU4
         | 
| 89 | 
            +
            0t9j7CfXTcM
         | 
| 90 | 
            +
            0uGzSXRi7qQ
         | 
| 91 | 
            +
            0ueGFLVFi80
         | 
| 92 | 
            +
            0zTkQXcIaqc
         | 
| 93 | 
            +
            1-YOlGoKxeM
         | 
| 94 | 
            +
            13FSE5dCvvM
         | 
| 95 | 
            +
            1653Kz-SnxA
         | 
| 96 | 
            +
            16uK2Gbyk2k
         | 
| 97 | 
            +
            18Kl4qkvGUU
         | 
| 98 | 
            +
            18Ts-YxUIts
         | 
| 99 | 
            +
            19baUOGVR2M
         | 
| 100 | 
            +
            1ADqe6vt0xE
         | 
| 101 | 
            +
            1BQNyk_BgDQ
         | 
| 102 | 
            +
            1BuXth0dz5s
         | 
| 103 | 
            +
            1C7do4tIrfo
         | 
| 104 | 
            +
            1DgBEF9zbvc
         | 
| 105 | 
            +
            1FBVcxb4PQA
         | 
| 106 | 
            +
            1FmSxmpitBA
         | 
| 107 | 
            +
            1HIHu4mxDLE
         | 
| 108 | 
            +
            1IJ3ISINhnU
         | 
| 109 | 
            +
            1JSocaAw--A
         | 
| 110 | 
            +
            1JwEvzz-kf0
         | 
| 111 | 
            +
            1MibRcX7KUM
         | 
| 112 | 
            +
            1MvtBdLyAKc
         | 
| 113 | 
            +
            1O3ghiyirvU
         | 
| 114 | 
            +
            1OUkXFsyyP0
         | 
| 115 | 
            +
            1PDs1mL7TG0
         | 
| 116 | 
            +
            1PV7Hy_8fhA
         | 
| 117 | 
            +
            1R5dPw4sYrE
         | 
| 118 | 
            +
            1SLkDhvOnNQ
         | 
| 119 | 
            +
            1UHlG0puRUM
         | 
| 120 | 
            +
            1UyhO1hMhrU
         | 
| 121 | 
            +
            1WOs6S0VrlA
         | 
| 122 | 
            +
            1_rRguH_Vx4
         | 
| 123 | 
            +
            1aQGw_-I25I
         | 
| 124 | 
            +
            1aY5n5H0ugE
         | 
| 125 | 
            +
            1bMYn6Vb-Mk
         | 
| 126 | 
            +
            1bwUe85Mg4U
         | 
| 127 | 
            +
            1h3J3fDsupc
         | 
| 128 | 
            +
            1hd5majTxeQ
         | 
| 129 | 
            +
            1i8607wMy68
         | 
| 130 | 
            +
            1iXuJgqZhik
         | 
| 131 | 
            +
            1izPOehU6zA
         | 
| 132 | 
            +
            1k3DrJOQ008
         | 
| 133 | 
            +
            1lPU8Tw928Q
         | 
| 134 | 
            +
            1mAMa9hn-18
         | 
| 135 | 
            +
            1oPgMsUmC6Y
         | 
| 136 | 
            +
            1q7yGJbX1sI
         | 
| 137 | 
            +
            1rxyrZUtm_g
         | 
| 138 | 
            +
            1tZaTf21D64
         | 
| 139 | 
            +
            1wKWC0EzK_s
         | 
| 140 | 
            +
            1wsOU17LXTU
         | 
| 141 | 
            +
            1yHWhXaXxFk
         | 
| 142 | 
            +
            1yP_MElLiKM
         | 
| 143 | 
            +
            1z-0ranXCyc
         | 
| 144 | 
            +
            1z2ZTPZEx1E
         | 
| 145 | 
            +
            1z8sqW5xIrA
         | 
| 146 | 
            +
            216-fEvtTag
         | 
| 147 | 
            +
            2250kOXVaGE
         | 
| 148 | 
            +
            22AUNaHGGz8
         | 
| 149 | 
            +
            22tF3y_epZs
         | 
| 150 | 
            +
            23eZ2Hjh3gY
         | 
| 151 | 
            +
            24paFjOVKoE
         | 
| 152 | 
            +
            264aaUUvB9U
         | 
| 153 | 
            +
            2CQgBtUJNBc
         | 
| 154 | 
            +
            2CRIlwxj6uo
         | 
| 155 | 
            +
            2ChRXYtCCXs
         | 
| 156 | 
            +
            2DXm-gBAbDQ
         | 
| 157 | 
            +
            2EgGqTDAiC4
         | 
| 158 | 
            +
            2H7qsNMyxvU
         | 
| 159 | 
            +
            2HPH4qtE95k
         | 
| 160 | 
            +
            2Ix4h6gaa1w
         | 
| 161 | 
            +
            2JgN7AZO_6Y
         | 
| 162 | 
            +
            2KTA78QK5-A
         | 
| 163 | 
            +
            2KmXllrBNHw
         | 
| 164 | 
            +
            2L-QZfbDm_s
         | 
| 165 | 
            +
            2LdAF2dHHFU
         | 
| 166 | 
            +
            2Li-PLW3Aew
         | 
| 167 | 
            +
            2NV_nn8apOA
         | 
| 168 | 
            +
            2O_SN4pg-lk
         | 
| 169 | 
            +
            2ObBpwabNmg
         | 
| 170 | 
            +
            2OfVzz2aZ8c
         | 
| 171 | 
            +
            2PejNMim-YQ
         | 
| 172 | 
            +
            2PqqZcC31ys
         | 
| 173 | 
            +
            2R3GNE3ob-4
         | 
| 174 | 
            +
            2Rtp8zWE6nQ
         | 
| 175 | 
            +
            2T2f2cENuiM
         | 
| 176 | 
            +
            2TmfeHf8Rqw
         | 
| 177 | 
            +
            2VLez1fkVq4
         | 
| 178 | 
            +
            2VdwqgI2l2o
         | 
| 179 | 
            +
            2bAuuK1uU1M
         | 
| 180 | 
            +
            2d9BcdLC4dA
         | 
| 181 | 
            +
            2dt6XZlI-Lg
         | 
| 182 | 
            +
            2e6a4eog8jc
         | 
| 183 | 
            +
            2eZgkkbNq54
         | 
| 184 | 
            +
            2eaxjEpQPkk
         | 
| 185 | 
            +
            2ep9Eb36OCY
         | 
| 186 | 
            +
            2gIkmyxa2ds
         | 
| 187 | 
            +
            2gMaIjvjCFo
         | 
| 188 | 
            +
            2k7VhqEg7ws
         | 
| 189 | 
            +
            2llLx_WkF3Q
         | 
| 190 | 
            +
            2llMolwKs88
         | 
| 191 | 
            +
            2mLsOuOve8k
         | 
| 192 | 
            +
            2nhDjEnUslE
         | 
| 193 | 
            +
            2nj6tpVKUxQ
         | 
| 194 | 
            +
            2qDH4bPvfMw
         | 
| 195 | 
            +
            2qVqaA1hn7A
         | 
| 196 | 
            +
            2rxU553pKgs
         | 
| 197 | 
            +
            30QwIdz8Vjc
         | 
| 198 | 
            +
            30gEiweaAVQ
         | 
| 199 | 
            +
            32DCEzpcVEY
         | 
| 200 | 
            +
            35ELLdyGmpc
         | 
| 201 | 
            +
            37QWwuNFVmU
         | 
| 202 | 
            +
            39Axc3FIu9A
         | 
| 203 | 
            +
            3AJdjwSsKoI
         | 
| 204 | 
            +
            3AoYXlMCioI
         | 
| 205 | 
            +
            3BkL0UXgNDs
         | 
| 206 | 
            +
            3C0T230n-mo
         | 
| 207 | 
            +
            3CGECvfakGM
         | 
| 208 | 
            +
            3EFiRh-y4L0
         | 
| 209 | 
            +
            3EJtdIIh43s
         | 
| 210 | 
            +
            3EYU3VTI3IU
         | 
| 211 | 
            +
            3EsqpF-W_wQ
         | 
| 212 | 
            +
            3FKX7kcU4hA
         | 
| 213 | 
            +
            3GUcVRz_JyA
         | 
| 214 | 
            +
            3I2jJpnw_xY
         | 
| 215 | 
            +
            3KNGPFM4d6c
         | 
| 216 | 
            +
            3KtIBPwaRkk
         | 
| 217 | 
            +
            3NJN-C1R9gA
         | 
| 218 | 
            +
            3Qlr9YoHBkg
         | 
| 219 | 
            +
            3RITVJy7ogI
         | 
| 220 | 
            +
            3Tyan5xgQ4Y
         | 
| 221 | 
            +
            3UYOtcC00L4
         | 
| 222 | 
            +
            3YE8YLldLu8
         | 
| 223 | 
            +
            3Yepui-bWyw
         | 
| 224 | 
            +
            3ZLYs6Wj51s
         | 
| 225 | 
            +
            3ZQL-3ElxpY
         | 
| 226 | 
            +
            3ZlXiEZb3k0
         | 
| 227 | 
            +
            3_celBcyBJE
         | 
| 228 | 
            +
            3fyphrZ-yUc
         | 
| 229 | 
            +
            3gCA0Z4y7wA
         | 
| 230 | 
            +
            3hPHW74cBRM
         | 
| 231 | 
            +
            3jESlqRuLw0
         | 
| 232 | 
            +
            3kyzHQL4s1c
         | 
| 233 | 
            +
            3l_puRAIDDU
         | 
| 234 | 
            +
            3lpnoDrt5Tw
         | 
| 235 | 
            +
            3nJexBvb5UY
         | 
| 236 | 
            +
            3oV_cljdDs8
         | 
| 237 | 
            +
            3pIR5nfFNQM
         | 
| 238 | 
            +
            3qBW_x5fatI
         | 
| 239 | 
            +
            3tKwbLJEYZg
         | 
| 240 | 
            +
            3v1tt9mD6cg
         | 
| 241 | 
            +
            3viekW3AnRA
         | 
| 242 | 
            +
            3vudNvflufc
         | 
| 243 | 
            +
            3ytLt3BDqFU
         | 
| 244 | 
            +
            3zhCbaVBEjg
         | 
| 245 | 
            +
            4-1Nci8AkAc
         | 
| 246 | 
            +
            4-7ABAFvCZE
         | 
| 247 | 
            +
            41Q97FiM2n8
         | 
| 248 | 
            +
            43wXnwHo_qU
         | 
| 249 | 
            +
            465Wt-eX2RY
         | 
| 250 | 
            +
            47OtSe4dffo
         | 
| 251 | 
            +
            47slfR-Knq0
         | 
| 252 | 
            +
            4A9OeOEnFyA
         | 
| 253 | 
            +
            4BPibf6C35E
         | 
| 254 | 
            +
            4DdTNSKleK4
         | 
| 255 | 
            +
            4Hg2Eu-F9mU
         | 
| 256 | 
            +
            4NXUGnLbl5Y
         | 
| 257 | 
            +
            4Q6NknbHNiQ
         | 
| 258 | 
            +
            4QQyjqtHwlY
         | 
| 259 | 
            +
            4QgmM1dcHMw
         | 
| 260 | 
            +
            4R4aN98Qrbo
         | 
| 261 | 
            +
            4RN-c0HdJOI
         | 
| 262 | 
            +
            4cz4pq_N--g
         | 
| 263 | 
            +
            4gxMVLXmBiE
         | 
| 264 | 
            +
            4kR-Fev28po
         | 
| 265 | 
            +
            4l515yNhqxg
         | 
| 266 | 
            +
            4lB_x0kLffU
         | 
| 267 | 
            +
            4lOnYQCxbOM
         | 
| 268 | 
            +
            4neIRMYUT0U
         | 
| 269 | 
            +
            4nqMZX542bU
         | 
| 270 | 
            +
            4oXZCuXwrXo
         | 
| 271 | 
            +
            4q7lHy-1U6o
         | 
| 272 | 
            +
            4qGWz9v-UXk
         | 
| 273 | 
            +
            4rJ_RB3Iwws
         | 
| 274 | 
            +
            4tbkGu8boyo
         | 
| 275 | 
            +
            4u7y4RPfV5c
         | 
| 276 | 
            +
            4udsKgSP7UA
         | 
| 277 | 
            +
            4ujhmvsSE9c
         | 
| 278 | 
            +
            4x234xeqtHg
         | 
| 279 | 
            +
            4xlKjVPFFv4
         | 
| 280 | 
            +
            4zzVjonyHcQ
         | 
| 281 | 
            +
            50zJWKotPP4
         | 
| 282 | 
            +
            51Qp9Z3ZlHs
         | 
| 283 | 
            +
            58GcsaJhTzM
         | 
| 284 | 
            +
            58K7XpkuMCM
         | 
| 285 | 
            +
            5JG5xwguT6I
         | 
| 286 | 
            +
            5K4dtC2A_bw
         | 
| 287 | 
            +
            5OXy29bFfPk
         | 
| 288 | 
            +
            5PGVFUADgGY
         | 
| 289 | 
            +
            5PUTMuJxqZQ
         | 
| 290 | 
            +
            5TfPoq3lkso
         | 
| 291 | 
            +
            5WZmSJYYxPk
         | 
| 292 | 
            +
            5Yz7ssYCa8Y
         | 
| 293 | 
            +
            5Z8x06jnjSk
         | 
| 294 | 
            +
            5ZYrc-3gQVo
         | 
| 295 | 
            +
            5db6EORa_0U
         | 
| 296 | 
            +
            5dsxC8M7vCM
         | 
| 297 | 
            +
            5gx3WNfa56g
         | 
| 298 | 
            +
            5icAa3G2X8E
         | 
| 299 | 
            +
            5kas2jBObUY
         | 
| 300 | 
            +
            5kuqWp4gjV4
         | 
| 301 | 
            +
            5l2j8k759-4
         | 
| 302 | 
            +
            5leH4t1V9LY
         | 
| 303 | 
            +
            5llwjtJDqMo
         | 
| 304 | 
            +
            5meC4Z61qGg
         | 
| 305 | 
            +
            5okG5zh9ePY
         | 
| 306 | 
            +
            5oybklNuCZU
         | 
| 307 | 
            +
            5qaBD538C9k
         | 
| 308 | 
            +
            5r2Y6QsFACY
         | 
| 309 | 
            +
            5s9UdpT0TOo
         | 
| 310 | 
            +
            5shU5ZVQuEc
         | 
| 311 | 
            +
            5t4cwPdsVgQ
         | 
| 312 | 
            +
            5ty6o1t2emk
         | 
| 313 | 
            +
            5u-Aw6NOIy0
         | 
| 314 | 
            +
            5vAj_wY8c7s
         | 
| 315 | 
            +
            5xeVIgWq7s4
         | 
| 316 | 
            +
            5yZEtG_r-wI
         | 
| 317 | 
            +
            6-6m2H_aE-s
         | 
| 318 | 
            +
            6-O4gWLQkgk
         | 
| 319 | 
            +
            60bkwhHzols
         | 
| 320 | 
            +
            60dSEN1RIbE
         | 
| 321 | 
            +
            627Ufg0PVkg
         | 
| 322 | 
            +
            62OgF2Pw09o
         | 
| 323 | 
            +
            62aDb2JgFQc
         | 
| 324 | 
            +
            63gG5qmwREo
         | 
| 325 | 
            +
            63iL92MjDT4
         | 
| 326 | 
            +
            63stDIiwraM
         | 
| 327 | 
            +
            64Yx3Odqo9c
         | 
| 328 | 
            +
            67zz9OzY07c
         | 
| 329 | 
            +
            681IyvC_JAg
         | 
| 330 | 
            +
            685CK3xr0jg
         | 
| 331 | 
            +
            68pNYnDuoQA
         | 
| 332 | 
            +
            69pi63RgeJ4
         | 
| 333 | 
            +
            6CIMXUDzKtQ
         | 
| 334 | 
            +
            6CS50XMGV0o
         | 
| 335 | 
            +
            6Dtn8MfMPVE
         | 
| 336 | 
            +
            6Fd-CsvZQX8
         | 
| 337 | 
            +
            6IA7AuXVSxQ
         | 
| 338 | 
            +
            6IdeRRqG1ak
         | 
| 339 | 
            +
            6JIUlIwX3Pw
         | 
| 340 | 
            +
            6JmuCmI7Iqo
         | 
| 341 | 
            +
            6KKDqqV8OUk
         | 
| 342 | 
            +
            6LljU1cDSbI
         | 
| 343 | 
            +
            6MhEveLVeO4
         | 
| 344 | 
            +
            6Nyz_yd_GJw
         | 
| 345 | 
            +
            6QgRw4lDN10
         | 
| 346 | 
            +
            6R08SayU3bU
         | 
| 347 | 
            +
            6SA9lGH3JN4
         | 
| 348 | 
            +
            6SsIE00duz0
         | 
| 349 | 
            +
            6T5iJ6TjWj0
         | 
| 350 | 
            +
            6V3kI3QBWK8
         | 
| 351 | 
            +
            6VVCVtxeq1g
         | 
| 352 | 
            +
            6YBDqpgpVck
         | 
| 353 | 
            +
            6aAa8M4vg2k
         | 
| 354 | 
            +
            6bm6Y9TaX1w
         | 
| 355 | 
            +
            6bnxY8W5otQ
         | 
| 356 | 
            +
            6frz5TaAIto
         | 
| 357 | 
            +
            6gyKLNQH44I
         | 
| 358 | 
            +
            6iXGqEq_cpI
         | 
| 359 | 
            +
            6lMj2CGW6u0
         | 
| 360 | 
            +
            6lzxVmBJIlk
         | 
| 361 | 
            +
            6mL4rjxEnbo
         | 
| 362 | 
            +
            6nDOJdyJDk0
         | 
| 363 | 
            +
            6nPPyCrkwSE
         | 
| 364 | 
            +
            6ng7_H8pdBo
         | 
| 365 | 
            +
            6oHmiJLrEAk
         | 
| 366 | 
            +
            6oLStjIxffE
         | 
| 367 | 
            +
            6p6boxrvbZk
         | 
| 368 | 
            +
            6pCBqmPozE4
         | 
| 369 | 
            +
            6ptI5B4a-ag
         | 
| 370 | 
            +
            6rKSZPwHTf8
         | 
| 371 | 
            +
            6tx3pU5F1x8
         | 
| 372 | 
            +
            6wyDTrAPV7s
         | 
| 373 | 
            +
            6xSxXiHwMrg
         | 
| 374 | 
            +
            6yt3pqCQn6s
         | 
| 375 | 
            +
            6zXMtU6jgc8
         | 
| 376 | 
            +
            7-AfS9rehcM
         | 
| 377 | 
            +
            7-ByRppD-EE
         | 
| 378 | 
            +
            7-QzoS-dW-c
         | 
| 379 | 
            +
            702SXH0JdaQ
         | 
| 380 | 
            +
            73hls2GdB5o
         | 
| 381 | 
            +
            75cv2PgOmX4
         | 
| 382 | 
            +
            75mMPO0x4Gs
         | 
| 383 | 
            +
            78UIF4JCcYc
         | 
| 384 | 
            +
            798S4UbhNE4
         | 
| 385 | 
            +
            7AjsnSEhZ-w
         | 
| 386 | 
            +
            7DJdGbYHll4
         | 
| 387 | 
            +
            7KcRJyXmuzo
         | 
| 388 | 
            +
            7MBqGLvoQG0
         | 
| 389 | 
            +
            7ONrAflL5Oc
         | 
| 390 | 
            +
            7PQ0QmUGpvw
         | 
| 391 | 
            +
            7Q2Qe-zid24
         | 
| 392 | 
            +
            7Qu_ETu3vi0
         | 
| 393 | 
            +
            7Rgh8v8Qmzg
         | 
| 394 | 
            +
            7STjD4eWMs8
         | 
| 395 | 
            +
            7UQMqOkGD8M
         | 
| 396 | 
            +
            7W9ACrwLn1A
         | 
| 397 | 
            +
            7_ppXSABYLY
         | 
| 398 | 
            +
            7bAPKKE_tzA
         | 
| 399 | 
            +
            7bC_8QTdbHM
         | 
| 400 | 
            +
            7bXAZfRTZQk
         | 
| 401 | 
            +
            7c0wYvntu8M
         | 
| 402 | 
            +
            7c7ccOHMK8o
         | 
| 403 | 
            +
            7dLu8wqYpJw
         | 
| 404 | 
            +
            7dmNo3X-Lus
         | 
| 405 | 
            +
            7eOwm6nBBGA
         | 
| 406 | 
            +
            7elaTVxAEX4
         | 
| 407 | 
            +
            7f6b7b_yzQY
         | 
| 408 | 
            +
            7flG_V2SHc0
         | 
| 409 | 
            +
            7g7RpRl-Pi8
         | 
| 410 | 
            +
            7hHOLdgvG-4
         | 
| 411 | 
            +
            7hfFxTbLFWs
         | 
| 412 | 
            +
            7jyokhjUCyk
         | 
| 413 | 
            +
            7l7GryUZGvY
         | 
| 414 | 
            +
            7mHwsV3Mb-Y
         | 
| 415 | 
            +
            7o8NcTiXGYI
         | 
| 416 | 
            +
            7oKjW1OIjuw
         | 
| 417 | 
            +
            7pg_Dgs0wUU
         | 
| 418 | 
            +
            7s_Sb4-mwes
         | 
| 419 | 
            +
            7uwUj4aX2YA
         | 
| 420 | 
            +
            7w68Up6F9ZI
         | 
| 421 | 
            +
            7zWswXer8i4
         | 
| 422 | 
            +
            8-RmR1XmaxE
         | 
| 423 | 
            +
            8-hAwTTVYFM
         | 
| 424 | 
            +
            80It12pD4j8
         | 
| 425 | 
            +
            829gaOsl7Z8
         | 
| 426 | 
            +
            86OqcZtLtgE
         | 
| 427 | 
            +
            8BZC5UBidm0
         | 
| 428 | 
            +
            8C5cn_Qj0G8
         | 
| 429 | 
            +
            8CTEl-Zhv38
         | 
| 430 | 
            +
            8DzVNa_BjOI
         | 
| 431 | 
            +
            8HbsSkuiPmg
         | 
| 432 | 
            +
            8J6FseCtEXc
         | 
| 433 | 
            +
            8JtWrFwQ-h0
         | 
| 434 | 
            +
            8KD2cPzxF3U
         | 
| 435 | 
            +
            8Kux1TQWdLU
         | 
| 436 | 
            +
            8LSK5wIjZMk
         | 
| 437 | 
            +
            8MPjG8RMYJY
         | 
| 438 | 
            +
            8N-x9QC50m0
         | 
| 439 | 
            +
            8NJ74aVTZMc
         | 
| 440 | 
            +
            8P3rViI8Xw8
         | 
| 441 | 
            +
            8SIWlQ0ZUqY
         | 
| 442 | 
            +
            8ToIwnP2a-g
         | 
| 443 | 
            +
            8TunLMoE9Xw
         | 
| 444 | 
            +
            8Uij8BYDuf8
         | 
| 445 | 
            +
            8WfV93go5TM
         | 
| 446 | 
            +
            8XJp2c05iVk
         | 
| 447 | 
            +
            8XlrNlfd-9M
         | 
| 448 | 
            +
            8_yb_nW5x6I
         | 
| 449 | 
            +
            8aafXYh_gHA
         | 
| 450 | 
            +
            8bQPi0ssTLw
         | 
| 451 | 
            +
            8dI7AzzZLXw
         | 
| 452 | 
            +
            8e1BMiU951c
         | 
| 453 | 
            +
            8gg-oKufUo4
         | 
| 454 | 
            +
            8gtpnlVb31U
         | 
| 455 | 
            +
            8lrlXoXGQo0
         | 
| 456 | 
            +
            8pcELaZV2b0
         | 
| 457 | 
            +
            8qUQwmwC7Oc
         | 
| 458 | 
            +
            8quGD9W7B2I
         | 
| 459 | 
            +
            8rwcfIrAXtA
         | 
| 460 | 
            +
            8uyPpy2ejA4
         | 
| 461 | 
            +
            8vzKZVqXmo4
         | 
| 462 | 
            +
            8xhqhC_PHzE
         | 
| 463 | 
            +
            8xo4s6tYzzs
         | 
| 464 | 
            +
            9-EtiWDJbJw
         | 
| 465 | 
            +
            9-a3sSZeXDE
         | 
| 466 | 
            +
            9-nsXlNXRDw
         | 
| 467 | 
            +
            90dka2zrP1Y
         | 
| 468 | 
            +
            90sJHDwKmSg
         | 
| 469 | 
            +
            91Zu4JRnfxc
         | 
| 470 | 
            +
            91z62p7t-AU
         | 
| 471 | 
            +
            95hYfRw1aHA
         | 
| 472 | 
            +
            95zvFw1VkqQ
         | 
| 473 | 
            +
            97C_sZ2821s
         | 
| 474 | 
            +
            9Dm1Sekkcdw
         | 
| 475 | 
            +
            9G4s_qIxJYk
         | 
| 476 | 
            +
            9I8mQpFAJ50
         | 
| 477 | 
            +
            9IGRsXq9Wis
         | 
| 478 | 
            +
            9ITi5C8vHpw
         | 
| 479 | 
            +
            9JJ3ullABD8
         | 
| 480 | 
            +
            9K4A7e3clMM
         | 
| 481 | 
            +
            9KPyflyHP6s
         | 
| 482 | 
            +
            9KisGZnflBc
         | 
| 483 | 
            +
            9MOleOgz5To
         | 
| 484 | 
            +
            9O2D9K7l-FU
         | 
| 485 | 
            +
            9Pj-QPlN2CU
         | 
| 486 | 
            +
            9QeqkUN0bNU
         | 
| 487 | 
            +
            9S9O2T1B6xE
         | 
| 488 | 
            +
            9SflFku0eKo
         | 
| 489 | 
            +
            9UaAyI-uI30
         | 
| 490 | 
            +
            9Wb409Nlhlw
         | 
| 491 | 
            +
            9WkYKiltzJU
         | 
| 492 | 
            +
            9XYx1vUd-v8
         | 
| 493 | 
            +
            9Zb8e6nE5QI
         | 
| 494 | 
            +
            9Zuk9Huqdrg
         | 
| 495 | 
            +
            9_VLbfRXTss
         | 
| 496 | 
            +
            9awtQRbMhG4
         | 
| 497 | 
            +
            9c7zctYTBLA
         | 
| 498 | 
            +
            9dCHp07it-Q
         | 
| 499 | 
            +
            9eHXo_KFvJ0
         | 
| 500 | 
            +
            9f0eB75r-Y8
         | 
| 501 | 
            +
            9h3m1jzWWEU
         | 
| 502 | 
            +
            9kUljb9G-MY
         | 
| 503 | 
            +
            9kgiApzKDMw
         | 
| 504 | 
            +
            9mAiyn6gMJw
         | 
| 505 | 
            +
            9mnTCYsbKfw
         | 
| 506 | 
            +
            9n7hn-M4GpI
         | 
| 507 | 
            +
            9oMmZIJijgY
         | 
| 508 | 
            +
            9p8z1A3TsxU
         | 
| 509 | 
            +
            9r8yZ-68pkY
         | 
| 510 | 
            +
            9s3BPDNEJek
         | 
| 511 | 
            +
            9t7ujBSH3WM
         | 
| 512 | 
            +
            9ujM2nAMK0g
         | 
| 513 | 
            +
            9uyYxs79EcY
         | 
| 514 | 
            +
            9ychKZIG8ms
         | 
| 515 | 
            +
            9ydk7zFmOxU
         | 
| 516 | 
            +
            9ydusnvBSys
         | 
| 517 | 
            +
            A-QOg-tFApA
         | 
| 518 | 
            +
            A0AViKj8EGk
         | 
| 519 | 
            +
            A2B-b-nfCqk
         | 
| 520 | 
            +
            A2DdRsUdFeU
         | 
| 521 | 
            +
            A2lEI0kaf3k
         | 
| 522 | 
            +
            A3uNIgDmqwI
         | 
| 523 | 
            +
            A6xjN8BqDjk
         | 
| 524 | 
            +
            A7ktYbVwr90
         | 
| 525 | 
            +
            AAprf4PLDM4
         | 
| 526 | 
            +
            ACsoFzXDE3Q
         | 
| 527 | 
            +
            ADQSqUBZjvE
         | 
| 528 | 
            +
            AEKZERIDiUk
         | 
| 529 | 
            +
            AHKGGtJ15o8
         | 
| 530 | 
            +
            AIXQngEnJgY
         | 
| 531 | 
            +
            AJa2DO_woJ4
         | 
| 532 | 
            +
            AKkYU-fExWc
         | 
| 533 | 
            +
            AL1pISpcG2Q
         | 
| 534 | 
            +
            AP0S21vT3Co
         | 
| 535 | 
            +
            AQe2ANirwW4
         | 
| 536 | 
            +
            AQuAGO9ceIU
         | 
| 537 | 
            +
            ARXYGhV5VFg
         | 
| 538 | 
            +
            ATgNzwHSfjw
         | 
| 539 | 
            +
            AUtRgfFUCl8
         | 
| 540 | 
            +
            AVc5fXa0oMs
         | 
| 541 | 
            +
            AWJcd3F-HPY
         | 
| 542 | 
            +
            AXfRrHD4Cps
         | 
| 543 | 
            +
            Ac8Fsu0WVKg
         | 
| 544 | 
            +
            AccPbM4JhFI
         | 
| 545 | 
            +
            Ad5je4UNgDw
         | 
| 546 | 
            +
            Adgif4D3ujk
         | 
| 547 | 
            +
            AfZNZ3bfJvA
         | 
| 548 | 
            +
            Afy7H04X9Us
         | 
| 549 | 
            +
            Ag-zqjX1TV8
         | 
| 550 | 
            +
            Ag1AKIl_2GM
         | 
| 551 | 
            +
            AglvA1tduMA
         | 
| 552 | 
            +
            AkU94JdXbQ0
         | 
| 553 | 
            +
            AnxrJiS5uKU
         | 
| 554 | 
            +
            AptPjGKdaDU
         | 
| 555 | 
            +
            Aqu7R_7vFKM
         | 
| 556 | 
            +
            AuLoMmjFONE
         | 
| 557 | 
            +
            AwvReatHB2g
         | 
| 558 | 
            +
            AygCTeXnJ6o
         | 
| 559 | 
            +
            AzECoalJ4WU
         | 
| 560 | 
            +
            AziRcPo6rm0
         | 
| 561 | 
            +
            B-8ovk81nNM
         | 
| 562 | 
            +
            B-qxGhkRojc
         | 
| 563 | 
            +
            B0KlNLkO3qE
         | 
| 564 | 
            +
            B5uSsp0Rbbc
         | 
| 565 | 
            +
            B7HzMw9rSMs
         | 
| 566 | 
            +
            BAj3fHStRGI
         | 
| 567 | 
            +
            BB4bpEKrOlM
         | 
| 568 | 
            +
            BBWIPL66Fpc
         | 
| 569 | 
            +
            BDLtYpLZfbU
         | 
| 570 | 
            +
            BE4Y5Uc53Nc
         | 
| 571 | 
            +
            BElqXjOG5Gk
         | 
| 572 | 
            +
            BErluP3jDjw
         | 
| 573 | 
            +
            BF7hcsKb1WA
         | 
| 574 | 
            +
            BFWbo17t-Ig
         | 
| 575 | 
            +
            BFat39XKT2E
         | 
| 576 | 
            +
            BFoqBnl5XNw
         | 
| 577 | 
            +
            BGJuAODr8Ks
         | 
| 578 | 
            +
            BH7-eZYnJkE
         | 
| 579 | 
            +
            BIuRA0GGIgk
         | 
| 580 | 
            +
            BK1VxSDsCu8
         | 
| 581 | 
            +
            BLcZAhQzQF0
         | 
| 582 | 
            +
            BM2mqrIXY2w
         | 
| 583 | 
            +
            BNgmYFwUjjw
         | 
| 584 | 
            +
            BNyCZJOTRZA
         | 
| 585 | 
            +
            BPLCiXRSBNk
         | 
| 586 | 
            +
            BQL5wkJS4y0
         | 
| 587 | 
            +
            BUouNsjhTTc
         | 
| 588 | 
            +
            BXT72YlkQrA
         | 
| 589 | 
            +
            BY2ADlTxdZI
         | 
| 590 | 
            +
            BYgCS4of0TI
         | 
| 591 | 
            +
            BYvQek24Kbs
         | 
| 592 | 
            +
            Bb3XWac-WuM
         | 
| 593 | 
            +
            Bc7WoDXhcjM
         | 
| 594 | 
            +
            BcTOSxcv2_o
         | 
| 595 | 
            +
            BcjJjiE4Ivs
         | 
| 596 | 
            +
            BfdcdAIJh4g
         | 
| 597 | 
            +
            BhEio_W1LU4
         | 
| 598 | 
            +
            Bio8ZpEFlqY
         | 
| 599 | 
            +
            BjrDmB15S-M
         | 
| 600 | 
            +
            BkTiMi0Owuw
         | 
| 601 | 
            +
            BlCoAfks8kk
         | 
| 602 | 
            +
            BoWXd-LNnm4
         | 
| 603 | 
            +
            BoXR8KrAfIQ
         | 
| 604 | 
            +
            Boj9eD0Wug8
         | 
| 605 | 
            +
            BowyM_Wlsd8
         | 
| 606 | 
            +
            Bq0vohH2pL4
         | 
| 607 | 
            +
            BsDYAcOsWqk
         | 
| 608 | 
            +
            BsgJuviWgJI
         | 
| 609 | 
            +
            Bv3taVzLZZU
         | 
| 610 | 
            +
            Bv7wdHRhifM
         | 
| 611 | 
            +
            BzAzXDgqKzc
         | 
| 612 | 
            +
            Bzb0FhMqaU8
         | 
| 613 | 
            +
            C2TLW8MS33E
         | 
| 614 | 
            +
            C2rVYklWl8I
         | 
| 615 | 
            +
            C3589eDY5rU
         | 
| 616 | 
            +
            C4bevJm-MbI
         | 
| 617 | 
            +
            C5WNr5vzUPs
         | 
| 618 | 
            +
            C7c1LAUbSho
         | 
| 619 | 
            +
            CA-0cn2Dbgo
         | 
| 620 | 
            +
            CBYhVcO4WgI
         | 
| 621 | 
            +
            CEJTBzMKcuk
         | 
| 622 | 
            +
            CFUGsvVC9mQ
         | 
| 623 | 
            +
            CG0OnKUqziA
         | 
| 624 | 
            +
            CIIsZt9c8nA
         | 
| 625 | 
            +
            CMAiUAvqIh4
         | 
| 626 | 
            +
            CNFTLmMYY1c
         | 
| 627 | 
            +
            CPckick_ioM
         | 
| 628 | 
            +
            CQUP1LhDLPM
         | 
| 629 | 
            +
            CWLEHmYHNro
         | 
| 630 | 
            +
            CZjbKqbYS-A
         | 
| 631 | 
            +
            CaD5TRQQNsI
         | 
| 632 | 
            +
            Cd4ZxGNbwTw
         | 
| 633 | 
            +
            CfA30p4X9g4
         | 
| 634 | 
            +
            CfKy85LA_bs
         | 
| 635 | 
            +
            CjnVq4zLT6s
         | 
| 636 | 
            +
            Ckrrk5oBneA
         | 
| 637 | 
            +
            ClVtccpCs6g
         | 
| 638 | 
            +
            Clsy0PuGl2A
         | 
| 639 | 
            +
            Cptzvn3nM0Q
         | 
| 640 | 
            +
            Cr0cBSpnn40
         | 
| 641 | 
            +
            Cr2VggKQrQg
         | 
| 642 | 
            +
            CsG0Or6-SiI
         | 
| 643 | 
            +
            CtpXTXjQk4o
         | 
| 644 | 
            +
            CuZnbR4fb_M
         | 
| 645 | 
            +
            CuoCrLWcsjI
         | 
| 646 | 
            +
            CuyAI82HFe0
         | 
| 647 | 
            +
            Cymmi8L0O1E
         | 
| 648 | 
            +
            CyyImnREpbg
         | 
| 649 | 
            +
            D0TgSpsBabY
         | 
| 650 | 
            +
            D17AYqYPFDk
         | 
| 651 | 
            +
            D2UT1AmyZFE
         | 
| 652 | 
            +
            D4T0Ffg1I_Y
         | 
| 653 | 
            +
            D5ZZUHKPC10
         | 
| 654 | 
            +
            D5gW_X-Db74
         | 
| 655 | 
            +
            D7wvFZjtVOw
         | 
| 656 | 
            +
            D7zgzpc_PVI
         | 
| 657 | 
            +
            D8TFETlLRdA
         | 
| 658 | 
            +
            D9aRZXIOX5k
         | 
| 659 | 
            +
            D9ocoySPGOk
         | 
| 660 | 
            +
            DA2mx0793uI
         | 
| 661 | 
            +
            DCUnruZponA
         | 
| 662 | 
            +
            DChlO5fNMGw
         | 
| 663 | 
            +
            DFqDbrTGTnY
         | 
| 664 | 
            +
            DGKY7K-pyqw
         | 
| 665 | 
            +
            DGoTdntvKfs
         | 
| 666 | 
            +
            DKnHYcKfz6Q
         | 
| 667 | 
            +
            DMVduTyjp1k
         | 
| 668 | 
            +
            DPDF4odJrq8
         | 
| 669 | 
            +
            DRHNdWF4Kho
         | 
| 670 | 
            +
            DSoKEFb8R_w
         | 
| 671 | 
            +
            DStiXbf9Mk0
         | 
| 672 | 
            +
            D_obsdDVv20
         | 
| 673 | 
            +
            Ddltu_Cq4E0
         | 
| 674 | 
            +
            DdtEInQEQ-s
         | 
| 675 | 
            +
            DeeRqZd7sCE
         | 
| 676 | 
            +
            DgGKe3kCx74
         | 
| 677 | 
            +
            DgpbuHAOgf8
         | 
| 678 | 
            +
            Di9AwmKtblo
         | 
| 679 | 
            +
            DjHPXW6Crac
         | 
| 680 | 
            +
            DnOLvKEYIQI
         | 
| 681 | 
            +
            DrDOMMmwPvI
         | 
| 682 | 
            +
            Dtfi2BHWwaY
         | 
| 683 | 
            +
            DtuJ55tmjps
         | 
| 684 | 
            +
            DuNW0KQ_GZM
         | 
| 685 | 
            +
            E-hVDqrQq6M
         | 
| 686 | 
            +
            E-qQNDCVSnk
         | 
| 687 | 
            +
            E1QbVtkza54
         | 
| 688 | 
            +
            E1gXzYA0tFA
         | 
| 689 | 
            +
            E2uUfyT64VY
         | 
| 690 | 
            +
            E3Q61rKXhrM
         | 
| 691 | 
            +
            E4zPYb7O2EU
         | 
| 692 | 
            +
            E7XkvbCu-jU
         | 
| 693 | 
            +
            E9tUCuAZ-LU
         | 
| 694 | 
            +
            EAc4WhNQZ30
         | 
| 695 | 
            +
            EB_d1jK1R44
         | 
| 696 | 
            +
            ECfLtssUZa0
         | 
| 697 | 
            +
            EEq8OK4BUyM
         | 
| 698 | 
            +
            EFLh9Vqr-YU
         | 
| 699 | 
            +
            EGCqtu8qujE
         | 
| 700 | 
            +
            EH6q2YGx45M
         | 
| 701 | 
            +
            EHp_I9ETmtQ
         | 
| 702 | 
            +
            EHrbAhrbw9Y
         | 
| 703 | 
            +
            EJMlBT6jptE
         | 
| 704 | 
            +
            EJZvz09LVa4
         | 
| 705 | 
            +
            EK3WoT1Gqvs
         | 
| 706 | 
            +
            ENXP9HEul98
         | 
| 707 | 
            +
            EQJN03a6M28
         | 
| 708 | 
            +
            EQLg-kHxwCA
         | 
| 709 | 
            +
            EQ_VlFQT9hg
         | 
| 710 | 
            +
            EUS1m5MSt9k
         | 
| 711 | 
            +
            EUqWrqb9Oug
         | 
| 712 | 
            +
            EVBOSk6kEwg
         | 
| 713 | 
            +
            EWSp2QMzKv8
         | 
| 714 | 
            +
            EYaKFlWd2MY
         | 
| 715 | 
            +
            E_LYrCtoTIA
         | 
| 716 | 
            +
            EaHZLUWwxfQ
         | 
| 717 | 
            +
            EaQOEXTkKYg
         | 
| 718 | 
            +
            EckpALTiYhE
         | 
| 719 | 
            +
            Ed4bxiP1RPM
         | 
| 720 | 
            +
            EeqwFjqFvJA
         | 
| 721 | 
            +
            EiW4lKrMXQ4
         | 
| 722 | 
            +
            EjB9J20nulw
         | 
| 723 | 
            +
            EjBkTt0LHbU
         | 
| 724 | 
            +
            EnPJk_9Ug7I
         | 
| 725 | 
            +
            EnU6HVRC4s0
         | 
| 726 | 
            +
            EoHwvsJcBNg
         | 
| 727 | 
            +
            Eojazns82hw
         | 
| 728 | 
            +
            Eotj0EeepoQ
         | 
| 729 | 
            +
            Eoxazjg1NUA
         | 
| 730 | 
            +
            Erso0HgtV5A
         | 
| 731 | 
            +
            Esu34JYC2YQ
         | 
| 732 | 
            +
            EtctGvH92Ww
         | 
| 733 | 
            +
            EuVBpqBgmvM
         | 
| 734 | 
            +
            Eup2Ca9Kiis
         | 
| 735 | 
            +
            EwXXD0uLj8I
         | 
| 736 | 
            +
            Eylcb4rbLSo
         | 
| 737 | 
            +
            F-GzNvvs-lU
         | 
| 738 | 
            +
            F-nsVjM7FmU
         | 
| 739 | 
            +
            F07fXd4vVlg
         | 
| 740 | 
            +
            F0InXG0ln4Y
         | 
| 741 | 
            +
            F2G-buBtp7w
         | 
| 742 | 
            +
            F2yK5VkHRaA
         | 
| 743 | 
            +
            F4xgvj4kSnU
         | 
| 744 | 
            +
            F5KV-iaMKK0
         | 
| 745 | 
            +
            F63B6wWXGtA
         | 
| 746 | 
            +
            F6ShWjU7GaI
         | 
| 747 | 
            +
            F7oit5SKxdw
         | 
| 748 | 
            +
            FAf0YtSelug
         | 
| 749 | 
            +
            FBQDiiEbknE
         | 
| 750 | 
            +
            FBbfCBOJOt4
         | 
| 751 | 
            +
            FEc-U45TzKM
         | 
| 752 | 
            +
            FGgMrNSmMn4
         | 
| 753 | 
            +
            FICT79cA3U4
         | 
| 754 | 
            +
            FL9qpSH5eKw
         | 
| 755 | 
            +
            FLI0WmBWWv4
         | 
| 756 | 
            +
            FLIippwrXSc
         | 
| 757 | 
            +
            FMIDAWVPq7c
         | 
| 758 | 
            +
            FNErh9EogUg
         | 
| 759 | 
            +
            FTN_93Px-Qc
         | 
| 760 | 
            +
            FUSU_WYPwx4
         | 
| 761 | 
            +
            FV4aEpanJ2I
         | 
| 762 | 
            +
            FV7tKSeGr3Y
         | 
| 763 | 
            +
            FXbC_3_8tGM
         | 
| 764 | 
            +
            FYo5E7zT-vM
         | 
| 765 | 
            +
            FZLwYiceIOU
         | 
| 766 | 
            +
            FaoVpVXcZsA
         | 
| 767 | 
            +
            FlCNvBBqIyU
         | 
| 768 | 
            +
            FloFzFl0jZc
         | 
| 769 | 
            +
            FnKhFaijBBI
         | 
| 770 | 
            +
            FoYce_3oUGs
         | 
| 771 | 
            +
            Fpo6nvSZirI
         | 
| 772 | 
            +
            Ft1Nw-Hy8Ao
         | 
| 773 | 
            +
            Fwh0r8YNLIU
         | 
| 774 | 
            +
            FxBLtp7UpTI
         | 
| 775 | 
            +
            FxQchGBQpZA
         | 
| 776 | 
            +
            FxoOE2dTCHE
         | 
| 777 | 
            +
            FxrCNf8utsE
         | 
| 778 | 
            +
            FyPFdBhklEw
         | 
| 779 | 
            +
            FzXWP7ZHs-Q
         | 
| 780 | 
            +
            G-6OXtSMyNI
         | 
| 781 | 
            +
            G0n970JRNII
         | 
| 782 | 
            +
            G2tfebkUbPo
         | 
| 783 | 
            +
            G4SMtaNDtfk
         | 
| 784 | 
            +
            G5hOJXZmqPc
         | 
| 785 | 
            +
            G66ClBEmWdY
         | 
| 786 | 
            +
            G7GI04txkOM
         | 
| 787 | 
            +
            G7T6dTs5YKw
         | 
| 788 | 
            +
            G9CHdvWwzQ0
         | 
| 789 | 
            +
            GAS_7760FSo
         | 
| 790 | 
            +
            GBvfnfwGq5Q
         | 
| 791 | 
            +
            GG0F0uXuIqQ
         | 
| 792 | 
            +
            GGIZzL-1gZ0
         | 
| 793 | 
            +
            GHjjXhd6WAc
         | 
| 794 | 
            +
            GJar81QVmQk
         | 
| 795 | 
            +
            GKCxRcuLm8o
         | 
| 796 | 
            +
            GLUdt99wUY8
         | 
| 797 | 
            +
            GMndqLvTqhA
         | 
| 798 | 
            +
            GNx4EbTu10w
         | 
| 799 | 
            +
            GOQWmjLkqOU
         | 
| 800 | 
            +
            GPEavB9GXHc
         | 
| 801 | 
            +
            GS1UT0mSks4
         | 
| 802 | 
            +
            GTsSe03hPxY
         | 
| 803 | 
            +
            GUZ4T_xFtwQ
         | 
| 804 | 
            +
            GVFq0_6imAA
         | 
| 805 | 
            +
            GXldrjxDZqQ
         | 
| 806 | 
            +
            GZRbKJMEdk0
         | 
| 807 | 
            +
            GZVxh8CQFkg
         | 
| 808 | 
            +
            GbUfu1wF02s
         | 
| 809 | 
            +
            GcNJkyYSmW8
         | 
| 810 | 
            +
            GcayBgPOr04
         | 
| 811 | 
            +
            Gd_zypjbv9E
         | 
| 812 | 
            +
            Gf8lUImdL3g
         | 
| 813 | 
            +
            GiShqIyw-_0
         | 
| 814 | 
            +
            GnwqktjWrVM
         | 
| 815 | 
            +
            GoZ6KwuAdT0
         | 
| 816 | 
            +
            GpAOMD6Z_Cs
         | 
| 817 | 
            +
            GsYl_thySnM
         | 
| 818 | 
            +
            GtzbWxb9nuQ
         | 
| 819 | 
            +
            GuVNl_oEMuQ
         | 
| 820 | 
            +
            GwU1VXsDXbc
         | 
| 821 | 
            +
            GxDeY_UiGBg
         | 
| 822 | 
            +
            GxRgKs4TpWo
         | 
| 823 | 
            +
            Gzo5PEGQpe8
         | 
| 824 | 
            +
            H2LhBAi-Q8I
         | 
| 825 | 
            +
            H450lZb-Mdg
         | 
| 826 | 
            +
            H4TYEoft_rM
         | 
| 827 | 
            +
            H6L04OEm71w
         | 
| 828 | 
            +
            H6ODJtcqyTg
         | 
| 829 | 
            +
            H8t_snz8B5A
         | 
| 830 | 
            +
            H91qCYIfZuQ
         | 
| 831 | 
            +
            HA8PjarK2mo
         | 
| 832 | 
            +
            HAFKRtBHFlQ
         | 
| 833 | 
            +
            HC-zhWIIC5w
         | 
| 834 | 
            +
            HCMZ4s2A_k8
         | 
| 835 | 
            +
            HFCmCsxt1xw
         | 
| 836 | 
            +
            HFTVP9qIMPE
         | 
| 837 | 
            +
            HLXDpFYmyqo
         | 
| 838 | 
            +
            HNdh6Valoys
         | 
| 839 | 
            +
            HOpKzDhCFtE
         | 
| 840 | 
            +
            HPHNakev2ss
         | 
| 841 | 
            +
            HQpZQj3TY80
         | 
| 842 | 
            +
            HSjvtpwKyhU
         | 
| 843 | 
            +
            HSu21_qc2kA
         | 
| 844 | 
            +
            HTJyZwYPQOI
         | 
| 845 | 
            +
            HUoUVlK_bHI
         | 
| 846 | 
            +
            HVMqm9jlUDM
         | 
| 847 | 
            +
            HWNwvBrUUGQ
         | 
| 848 | 
            +
            HXSxHJO6Srg
         | 
| 849 | 
            +
            HZ0pn4ijwnQ
         | 
| 850 | 
            +
            HZuhPDbZtcg
         | 
| 851 | 
            +
            HbKvcTZqNA0
         | 
| 852 | 
            +
            Hb_SVDUmWzo
         | 
| 853 | 
            +
            Hc6K7g7wqrs
         | 
| 854 | 
            +
            Hcy27nbeNWY
         | 
| 855 | 
            +
            HdzDCZ28cI4
         | 
| 856 | 
            +
            Hg0qN4cNJfY
         | 
| 857 | 
            +
            HhFPSCGRFHY
         | 
| 858 | 
            +
            HhNo_IOPOtU
         | 
| 859 | 
            +
            HhljUdMUbs0
         | 
| 860 | 
            +
            HkfLT86wPkM
         | 
| 861 | 
            +
            HmexkGBB428
         | 
| 862 | 
            +
            HsGbFpi3xtk
         | 
| 863 | 
            +
            Hy6QRP3ENl8
         | 
| 864 | 
            +
            HyzD8pNlpwI
         | 
| 865 | 
            +
            HztoBDblr8o
         | 
| 866 | 
            +
            HzzUW9y9FCQ
         | 
| 867 | 
            +
            I-9uLKZmxOw
         | 
| 868 | 
            +
            I-HFjHKJJ7E
         | 
| 869 | 
            +
            I0lqvxqEKhU
         | 
| 870 | 
            +
            I1fZdwFStnY
         | 
| 871 | 
            +
            I25TYNMclKk
         | 
| 872 | 
            +
            I2Z6LNkwijk
         | 
| 873 | 
            +
            I3RMF_9xW1o
         | 
| 874 | 
            +
            I68lZ9jptWU
         | 
| 875 | 
            +
            I8tkl9kVfaI
         | 
| 876 | 
            +
            I9taZpV2JfU
         | 
| 877 | 
            +
            IAYJhZS231s
         | 
| 878 | 
            +
            IB6_L9xsnAo
         | 
| 879 | 
            +
            IBESpBTIQTQ
         | 
| 880 | 
            +
            IC3EX6ipxFo
         | 
| 881 | 
            +
            IGEJo3QHvSI
         | 
| 882 | 
            +
            IGgpoI_0oPs
         | 
| 883 | 
            +
            IKMjg2fEGgE
         | 
| 884 | 
            +
            ILQii0-r-bE
         | 
| 885 | 
            +
            IM-TQHJKefA
         | 
| 886 | 
            +
            IM1xpnkmG7o
         | 
| 887 | 
            +
            IMEIBu0uULg
         | 
| 888 | 
            +
            IMFI8waM8rs
         | 
| 889 | 
            +
            IPPVWl-jPqk
         | 
| 890 | 
            +
            IRBAZJ4lF0U
         | 
| 891 | 
            +
            ISip9JRbYNs
         | 
| 892 | 
            +
            ITBbGDndjGM
         | 
| 893 | 
            +
            ITjHgkTTX_s
         | 
| 894 | 
            +
            IaHioK3Ljz0
         | 
| 895 | 
            +
            IahmVXN7xEQ
         | 
| 896 | 
            +
            Iam-aEiQOeI
         | 
| 897 | 
            +
            IatKu7sngG8
         | 
| 898 | 
            +
            IdZPa5vWdtc
         | 
| 899 | 
            +
            If2Fw0z6uxY
         | 
| 900 | 
            +
            IfnTz7vZyVg
         | 
| 901 | 
            +
            Iib7x8rYE7E
         | 
| 902 | 
            +
            ImCLzPvVKTI
         | 
| 903 | 
            +
            InL3YA_6P6s
         | 
| 904 | 
            +
            InP5DEpeVSU
         | 
| 905 | 
            +
            InSvBuHK4vI
         | 
| 906 | 
            +
            Io6JjgckHbg
         | 
| 907 | 
            +
            IsMFdiLsqbg
         | 
| 908 | 
            +
            Is_C4-xmayE
         | 
| 909 | 
            +
            IuuRvopzIf8
         | 
| 910 | 
            +
            IxYu1FAY5qc
         | 
| 911 | 
            +
            J1OGqF5Eo1k
         | 
| 912 | 
            +
            J3-ySSl7ceM
         | 
| 913 | 
            +
            J44SPYSVAAc
         | 
| 914 | 
            +
            J4vKu-s3OqM
         | 
| 915 | 
            +
            J71SYNCcRQI
         | 
| 916 | 
            +
            J78srd3-odQ
         | 
| 917 | 
            +
            J7BLQbvZyrU
         | 
| 918 | 
            +
            J7ei1-rYHMU
         | 
| 919 | 
            +
            J8ifUEgXF-o
         | 
| 920 | 
            +
            JC6pZ92y-hk
         | 
| 921 | 
            +
            JFkqEW-sz1c
         | 
| 922 | 
            +
            JGwMIlpgR2A
         | 
| 923 | 
            +
            JIEgN3las5E
         | 
| 924 | 
            +
            JIvGXG4z9X4
         | 
| 925 | 
            +
            JKg4o6SHbCY
         | 
| 926 | 
            +
            JLEPOAlZ7LU
         | 
| 927 | 
            +
            JP5ywOknF-8
         | 
| 928 | 
            +
            JPP_3u8gD-U
         | 
| 929 | 
            +
            JPmZtJ8vgAo
         | 
| 930 | 
            +
            JQTxw8OdBKw
         | 
| 931 | 
            +
            JTq75Se8vRA
         | 
| 932 | 
            +
            JUM_s4uQDW4
         | 
| 933 | 
            +
            JUSVl1JXYl0
         | 
| 934 | 
            +
            JVSwiQ0tNLM
         | 
| 935 | 
            +
            JZTlzyHnQeA
         | 
| 936 | 
            +
            Je69HPxSd_c
         | 
| 937 | 
            +
            JeZ5gAUnlFk
         | 
| 938 | 
            +
            JfjLKBO27nw
         | 
| 939 | 
            +
            JgwRwOWyR0Y
         | 
| 940 | 
            +
            JjSIRfrDKF4
         | 
| 941 | 
            +
            JmWnjvHEM38
         | 
| 942 | 
            +
            JmjxtqnhzHI
         | 
| 943 | 
            +
            JpL__knumpM
         | 
| 944 | 
            +
            JqQtOGCWrQM
         | 
| 945 | 
            +
            JrIwV6YniCg
         | 
| 946 | 
            +
            JrXU1owDEVs
         | 
| 947 | 
            +
            Jriq9eOSu7g
         | 
| 948 | 
            +
            JsFEIvtKCns
         | 
| 949 | 
            +
            Jtu5eFsIPmw
         | 
| 950 | 
            +
            Juen1iIJQTE
         | 
| 951 | 
            +
            Juv1TqsYiV4
         | 
| 952 | 
            +
            JvpxC406_jA
         | 
| 953 | 
            +
            JxR5EZ_GY1o
         | 
| 954 | 
            +
            JxUqtbpjpqg
         | 
| 955 | 
            +
            JxWjxAqCrCQ
         | 
| 956 | 
            +
            K-FG2oWl-2k
         | 
| 957 | 
            +
            K1hPyYEMp3s
         | 
| 958 | 
            +
            K2POkUf2EUQ
         | 
| 959 | 
            +
            K2QS3ZvjPMM
         | 
| 960 | 
            +
            K2bh3ZJOFnI
         | 
| 961 | 
            +
            K2pUtcVSXEo
         | 
| 962 | 
            +
            K3c6AMXsam8
         | 
| 963 | 
            +
            KAsvI2qAzlc
         | 
| 964 | 
            +
            KBQRetXolA8
         | 
| 965 | 
            +
            KCcenWMXQQ8
         | 
| 966 | 
            +
            KD6bh5ZfS2k
         | 
| 967 | 
            +
            KFDlZxR4yG4
         | 
| 968 | 
            +
            KIiKNpySv6w
         | 
| 969 | 
            +
            KK5120o36GM
         | 
| 970 | 
            +
            KNjgy1o65SA
         | 
| 971 | 
            +
            KP3ToVHnOZY
         | 
| 972 | 
            +
            KQQbMdsFsdQ
         | 
| 973 | 
            +
            KQkK8ThNsOY
         | 
| 974 | 
            +
            KTxhy419vto
         | 
| 975 | 
            +
            KZvz22uAVM4
         | 
| 976 | 
            +
            K_vUbBQzFjw
         | 
| 977 | 
            +
            KcdTad5fztE
         | 
| 978 | 
            +
            Kd9RcLW7knw
         | 
| 979 | 
            +
            Kgs0QbthCEU
         | 
| 980 | 
            +
            Khnx2cNTiu0
         | 
| 981 | 
            +
            Ki9AHohJpIc
         | 
| 982 | 
            +
            KihglmOX7j0
         | 
| 983 | 
            +
            KjMe0TXyQzM
         | 
| 984 | 
            +
            KjWVlz6cAyY
         | 
| 985 | 
            +
            KlC5HJFI40M
         | 
| 986 | 
            +
            KlcZwSsceL0
         | 
| 987 | 
            +
            KmmMz3NfoU4
         | 
| 988 | 
            +
            KoqaUANGvpA
         | 
| 989 | 
            +
            KqygzQmEuhA
         | 
| 990 | 
            +
            Kr3OvLakOgk
         | 
| 991 | 
            +
            Kr4Xe-BghFU
         | 
| 992 | 
            +
            KrEzYXCjJDQ
         | 
| 993 | 
            +
            KtHgPTAdfYM
         | 
| 994 | 
            +
            KtVfCgNJdeg
         | 
| 995 | 
            +
            KuqcVxRqQHI
         | 
| 996 | 
            +
            KxbRf-ZlSSk
         | 
| 997 | 
            +
            KxcNu6WZSCY
         | 
| 998 | 
            +
            KyBD2AeGXIE
         | 
| 999 | 
            +
            KyDTB0i_wQ0
         | 
| 1000 | 
            +
            KzVEGlNNXuI
         | 
| 1001 | 
            +
            KzVzRN5XoJs
         | 
| 1002 | 
            +
            Kz_wvavZp6c
         | 
| 1003 | 
            +
            L-bQmqP82oU
         | 
| 1004 | 
            +
            L0LZDwNDqRQ
         | 
| 1005 | 
            +
            L13WvYq8G68
         | 
| 1006 | 
            +
            L37uYJnDxVY
         | 
| 1007 | 
            +
            L5M93LmOmqw
         | 
| 1008 | 
            +
            L6SiuhBZWDk
         | 
| 1009 | 
            +
            LCsx9rVQjwE
         | 
| 1010 | 
            +
            LDXrXC0cPBo
         | 
| 1011 | 
            +
            LFBC0d4i3jE
         | 
| 1012 | 
            +
            LG8TfyiQr7w
         | 
| 1013 | 
            +
            LGumhl8-kiY
         | 
| 1014 | 
            +
            LH0IOQrB-NU
         | 
| 1015 | 
            +
            LH1WrGpM7p8
         | 
| 1016 | 
            +
            LHFY1Vg97AQ
         | 
| 1017 | 
            +
            LHNNYQ57V2c
         | 
| 1018 | 
            +
            LJJgAqdxBdA
         | 
| 1019 | 
            +
            LL-SFPRBBFw
         | 
| 1020 | 
            +
            LObC_A4G-_c
         | 
| 1021 | 
            +
            LR7ZZ5gw984
         | 
| 1022 | 
            +
            LRXrEiBeOXo
         | 
| 1023 | 
            +
            LTZPvLi3Hdc
         | 
| 1024 | 
            +
            LUhyxjNub8I
         | 
| 1025 | 
            +
            LUolzAltwKI
         | 
| 1026 | 
            +
            LVYVlHr2FKU
         | 
| 1027 | 
            +
            LXAcG9mITz0
         | 
| 1028 | 
            +
            Lawz1Mc16Vo
         | 
| 1029 | 
            +
            LbQo2tKGxV4
         | 
| 1030 | 
            +
            LbR6jjbgbis
         | 
| 1031 | 
            +
            Lbx1F4V_-8Q
         | 
| 1032 | 
            +
            LgT5uYkkPE4
         | 
| 1033 | 
            +
            Lgo_bkq9SWU
         | 
| 1034 | 
            +
            LhEzvegA-Dg
         | 
| 1035 | 
            +
            LhF_sfDfBd4
         | 
| 1036 | 
            +
            LiCmCW6EGzA
         | 
| 1037 | 
            +
            LiWszVY2lW8
         | 
| 1038 | 
            +
            Li_m7BVja44
         | 
| 1039 | 
            +
            Liv3vT9dGhU
         | 
| 1040 | 
            +
            LkCrGs-XeYI
         | 
| 1041 | 
            +
            Llq5mmhLy8s
         | 
| 1042 | 
            +
            LosFY2otV8E
         | 
| 1043 | 
            +
            Lq2icL5Y_FM
         | 
| 1044 | 
            +
            Lv3WAxgaZqU
         | 
| 1045 | 
            +
            Lx48775nwWs
         | 
| 1046 | 
            +
            LylMvKFdwJU
         | 
| 1047 | 
            +
            M5axFzT2_u0
         | 
| 1048 | 
            +
            M5zDCmXSejU
         | 
| 1049 | 
            +
            M6ZdYNFo6gM
         | 
| 1050 | 
            +
            M76UHFsQp2U
         | 
| 1051 | 
            +
            M8SkT5nE-0s
         | 
| 1052 | 
            +
            M8ayDH5DuJA
         | 
| 1053 | 
            +
            M9Xsci4JUy4
         | 
| 1054 | 
            +
            MCQ3H2jfCBs
         | 
| 1055 | 
            +
            MDyjY3uiWp0
         | 
| 1056 | 
            +
            MFcNY_CyXk4
         | 
| 1057 | 
            +
            MGGCuJdo8xs
         | 
| 1058 | 
            +
            MJnxzdG5QwM
         | 
| 1059 | 
            +
            MLUJVpk0BM8
         | 
| 1060 | 
            +
            MLay5YHp48w
         | 
| 1061 | 
            +
            MMoBEZ_d2g8
         | 
| 1062 | 
            +
            MMwKA-Ku1mM
         | 
| 1063 | 
            +
            MSr3hE3z2jw
         | 
| 1064 | 
            +
            MT6uJni993A
         | 
| 1065 | 
            +
            MTBfv2io-pQ
         | 
| 1066 | 
            +
            MVI_yEqA2RE
         | 
| 1067 | 
            +
            Makb_p6HcxE
         | 
| 1068 | 
            +
            Me95iJdHO18
         | 
| 1069 | 
            +
            MeM6r8Nj8G0
         | 
| 1070 | 
            +
            MfS4oDLBpp0
         | 
| 1071 | 
            +
            MgLHVw0tUBg
         | 
| 1072 | 
            +
            Mh3Dvs7DwdM
         | 
| 1073 | 
            +
            MimJZypAiy8
         | 
| 1074 | 
            +
            Misd5Qrx_CI
         | 
| 1075 | 
            +
            Ml1I6WEYSAY
         | 
| 1076 | 
            +
            MmfiHdQ4Wfs
         | 
| 1077 | 
            +
            MousuD_jX24
         | 
| 1078 | 
            +
            MpGxOR50sn4
         | 
| 1079 | 
            +
            Mrcn4Q50j5s
         | 
| 1080 | 
            +
            Mro6gxnOfus
         | 
| 1081 | 
            +
            Ms9K0eZLnFQ
         | 
| 1082 | 
            +
            MsA2OJiYApw
         | 
| 1083 | 
            +
            MsBU3uGpUGw
         | 
| 1084 | 
            +
            N15YpxEHjVs
         | 
| 1085 | 
            +
            N1cJakFhjNo
         | 
| 1086 | 
            +
            N4t59MjWdsg
         | 
| 1087 | 
            +
            N5esEarb5MQ
         | 
| 1088 | 
            +
            N8XGCs0js30
         | 
| 1089 | 
            +
            N9JXjNCR1EM
         | 
| 1090 | 
            +
            NDsl1_vHHTc
         | 
| 1091 | 
            +
            NISKpzp_QAM
         | 
| 1092 | 
            +
            NKJfBsc5kHk
         | 
| 1093 | 
            +
            NKKaWmoFdZA
         | 
| 1094 | 
            +
            NL6zaIPoU-Y
         | 
| 1095 | 
            +
            NMWqBL_Uhr4
         | 
| 1096 | 
            +
            NM_SJwSMRT8
         | 
| 1097 | 
            +
            NMpf6HNYIzc
         | 
| 1098 | 
            +
            NNK4pvyOhAU
         | 
| 1099 | 
            +
            NNp4yt9dHns
         | 
| 1100 | 
            +
            NNwM_OMLa10
         | 
| 1101 | 
            +
            NOYFz4DIfh8
         | 
| 1102 | 
            +
            NSZvUu8Q8ZQ
         | 
| 1103 | 
            +
            NUKIA9I6gRA
         | 
| 1104 | 
            +
            N_kIz8R84jU
         | 
| 1105 | 
            +
            Nbn1NJjbqoc
         | 
| 1106 | 
            +
            Nc-HP2vyKoE
         | 
| 1107 | 
            +
            Nchrj-dzVgs
         | 
| 1108 | 
            +
            NdKNfaWpCj0
         | 
| 1109 | 
            +
            Ndnq9Ofs2eA
         | 
| 1110 | 
            +
            NhOwdlKHcAE
         | 
| 1111 | 
            +
            NhfsI4jbWgk
         | 
| 1112 | 
            +
            NjN07qsdh0w
         | 
| 1113 | 
            +
            Nk6N7ieiphs
         | 
| 1114 | 
            +
            Nm2nt6dxVv0
         | 
| 1115 | 
            +
            NmBcsOMtKqM
         | 
| 1116 | 
            +
            NnPyqGW2w2Y
         | 
| 1117 | 
            +
            NoIHCm4wrpk
         | 
| 1118 | 
            +
            NoZ7ujJhb3k
         | 
| 1119 | 
            +
            Nom2-9WmsWU
         | 
| 1120 | 
            +
            NpskXvrCNA0
         | 
| 1121 | 
            +
            NysbSdox6zM
         | 
| 1122 | 
            +
            O0D0E42AA4I
         | 
| 1123 | 
            +
            O0hP4Hrek4s
         | 
| 1124 | 
            +
            O1UBCHWPIqE
         | 
| 1125 | 
            +
            O1d4dHwSZqs
         | 
| 1126 | 
            +
            O1j79d0IuhU
         | 
| 1127 | 
            +
            O2AnvMTbDCw
         | 
| 1128 | 
            +
            O2YHi_g2JuY
         | 
| 1129 | 
            +
            O3iPo__LYZQ
         | 
| 1130 | 
            +
            O3jxAN3j_P4
         | 
| 1131 | 
            +
            O3sFnc87STU
         | 
| 1132 | 
            +
            O42jXkaQtQU
         | 
| 1133 | 
            +
            O7dLxPQvIkI
         | 
| 1134 | 
            +
            O8G_glgmBcA
         | 
| 1135 | 
            +
            O8gZs9BCr4Y
         | 
| 1136 | 
            +
            OBlw3eBxHvA
         | 
| 1137 | 
            +
            OCQd02hORJQ
         | 
| 1138 | 
            +
            ODx9C7kHmWs
         | 
| 1139 | 
            +
            OGhvz1fwacA
         | 
| 1140 | 
            +
            OGzPe8LXHeA
         | 
| 1141 | 
            +
            OHHqegRBDWg
         | 
| 1142 | 
            +
            OI4sCSsyS4s
         | 
| 1143 | 
            +
            OLbdw1imnKY
         | 
| 1144 | 
            +
            OLe9xNH4G6s
         | 
| 1145 | 
            +
            OLfHpvJKNg0
         | 
| 1146 | 
            +
            OMeIMC_s0GQ
         | 
| 1147 | 
            +
            OMw8kl2kcZY
         | 
| 1148 | 
            +
            ON3YD52Df5s
         | 
| 1149 | 
            +
            ONvg9SbauMg
         | 
| 1150 | 
            +
            OOJ7OYp1gjg
         | 
| 1151 | 
            +
            OPzyc9rXx-I
         | 
| 1152 | 
            +
            OR6qP-X5fcs
         | 
| 1153 | 
            +
            ORObgzbi8Fc
         | 
| 1154 | 
            +
            OSrCb8eDWWk
         | 
| 1155 | 
            +
            OT_0JLIALxk
         | 
| 1156 | 
            +
            OUE8rKxYGLY
         | 
| 1157 | 
            +
            OUoQ4c1YyJM
         | 
| 1158 | 
            +
            OWdqgZQdMgw
         | 
| 1159 | 
            +
            OX0OARBqBp0
         | 
| 1160 | 
            +
            OYJh1xJbQys
         | 
| 1161 | 
            +
            OZWiY3xcr1w
         | 
| 1162 | 
            +
            OcPW_rtcbio
         | 
| 1163 | 
            +
            Odb1XiXpRTg
         | 
| 1164 | 
            +
            Odw7NOmXeaU
         | 
| 1165 | 
            +
            OgzTnofR1WY
         | 
| 1166 | 
            +
            OhHBPhb8a1I
         | 
| 1167 | 
            +
            OhsXUPDBX90
         | 
| 1168 | 
            +
            Oj22JVi762E
         | 
| 1169 | 
            +
            OmdRZ6ZM_pc
         | 
| 1170 | 
            +
            OnPdfl9qKRg
         | 
| 1171 | 
            +
            OpaFC283wJE
         | 
| 1172 | 
            +
            Opx0cWUuaBk
         | 
| 1173 | 
            +
            OqTI0KYkeJQ
         | 
| 1174 | 
            +
            OsBgWxoAOf0
         | 
| 1175 | 
            +
            OsLj4GyNvYQ
         | 
| 1176 | 
            +
            Osp20p7mHLw
         | 
| 1177 | 
            +
            OtTAH-lcO_M
         | 
| 1178 | 
            +
            OuP7vIfN3GI
         | 
| 1179 | 
            +
            OufFx-XmsLM
         | 
| 1180 | 
            +
            OyNBayVulb4
         | 
| 1181 | 
            +
            Oysv7K93B-w
         | 
| 1182 | 
            +
            OzIUFdCRm4o
         | 
| 1183 | 
            +
            Ozk5w3I6wlU
         | 
| 1184 | 
            +
            P-9Z6WeojxU
         | 
| 1185 | 
            +
            P2-SOq0SrmU
         | 
| 1186 | 
            +
            P9M__yYbsZ4
         | 
| 1187 | 
            +
            P9S15gsSywg
         | 
| 1188 | 
            +
            PAFybFU4fzI
         | 
| 1189 | 
            +
            PGQTyzsX7V8
         | 
| 1190 | 
            +
            PJXZQrwDPdQ
         | 
| 1191 | 
            +
            PJdbIALsMYQ
         | 
| 1192 | 
            +
            PNJghHAUlLg
         | 
| 1193 | 
            +
            PRgoisHRmUE
         | 
| 1194 | 
            +
            PT0KwTjsMUo
         | 
| 1195 | 
            +
            PTOZrIogdhs
         | 
| 1196 | 
            +
            PTaeZggiMrM
         | 
| 1197 | 
            +
            PUYoRT2EA5Q
         | 
| 1198 | 
            +
            PVLxoTzL31U
         | 
| 1199 | 
            +
            PXNdbOr8f9s
         | 
| 1200 | 
            +
            PXf59S2kFag
         | 
| 1201 | 
            +
            Pa-5lbobZpk
         | 
| 1202 | 
            +
            PaEO7DFyzZY
         | 
| 1203 | 
            +
            PiHMIYoV3OE
         | 
| 1204 | 
            +
            PjlEL4poXaU
         | 
| 1205 | 
            +
            Pnfh3Bxo4mE
         | 
| 1206 | 
            +
            PnxpH92CJOU
         | 
| 1207 | 
            +
            PpE-wfM5NhU
         | 
| 1208 | 
            +
            PtV9uxQHnGY
         | 
| 1209 | 
            +
            Puu_PXPw_H0
         | 
| 1210 | 
            +
            Pw_4_f6PQno
         | 
| 1211 | 
            +
            Pw_JdBkki_I
         | 
| 1212 | 
            +
            PxVZGdKMmvc
         | 
| 1213 | 
            +
            Pxg5mHeIoTA
         | 
| 1214 | 
            +
            PxiRvHqbQoo
         | 
| 1215 | 
            +
            PyNVMlDyNtg
         | 
| 1216 | 
            +
            PzzNuCk-e0Y
         | 
| 1217 | 
            +
            Q1MYDq7GgBc
         | 
| 1218 | 
            +
            Q5iKAqZ9yVU
         | 
| 1219 | 
            +
            Q71FNI--3vk
         | 
| 1220 | 
            +
            Q9W5Lxr-7v4
         | 
| 1221 | 
            +
            QEKRkIbCZEg
         | 
| 1222 | 
            +
            QEz1caz0loM
         | 
| 1223 | 
            +
            QFJZwvkJsGk
         | 
| 1224 | 
            +
            QFbp5scBzys
         | 
| 1225 | 
            +
            QGbL4LlrcIs
         | 
| 1226 | 
            +
            QHeYQalwm8Q
         | 
| 1227 | 
            +
            QIz-y9-jywM
         | 
| 1228 | 
            +
            QJj7WiwcadU
         | 
| 1229 | 
            +
            QKxRCmpAFKE
         | 
| 1230 | 
            +
            QL2Hb-v1r0A
         | 
| 1231 | 
            +
            QLunLzt4r4k
         | 
| 1232 | 
            +
            QMcdgAriqy0
         | 
| 1233 | 
            +
            QO7Jhl-r-BY
         | 
| 1234 | 
            +
            QP2zJO0AtlA
         | 
| 1235 | 
            +
            QPKKQnijnsM
         | 
| 1236 | 
            +
            QTp2snIa-cU
         | 
| 1237 | 
            +
            QWgbM9DoA7A
         | 
| 1238 | 
            +
            QX1d52gmEZ4
         | 
| 1239 | 
            +
            QZhzZtExnfc
         | 
| 1240 | 
            +
            QaqyAdedM0Q
         | 
| 1241 | 
            +
            Qd3DEZud65I
         | 
| 1242 | 
            +
            QgscBSUsuNU
         | 
| 1243 | 
            +
            Qh7rX2S4lFs
         | 
| 1244 | 
            +
            Qi4P0mLkkLQ
         | 
| 1245 | 
            +
            QkmGfY9iY9Y
         | 
| 1246 | 
            +
            QkwYl6HJHdc
         | 
| 1247 | 
            +
            Qlzca3efn6E
         | 
| 1248 | 
            +
            Qmp2Z7wPR4Y
         | 
| 1249 | 
            +
            QowV8kgwHX8
         | 
| 1250 | 
            +
            QpXUjqjewGU
         | 
| 1251 | 
            +
            QqsPM1rd688
         | 
| 1252 | 
            +
            Qru-q3ykC48
         | 
| 1253 | 
            +
            QspDZ-DYs0Y
         | 
| 1254 | 
            +
            R0XyMhCdSkY
         | 
| 1255 | 
            +
            R3QabWdSsxY
         | 
| 1256 | 
            +
            R5XePwAO4m0
         | 
| 1257 | 
            +
            R7ZX64ASSe8
         | 
| 1258 | 
            +
            R9KOp8PKhpY
         | 
| 1259 | 
            +
            R9P4_3GEjS8
         | 
| 1260 | 
            +
            RAMbIz3Y2JA
         | 
| 1261 | 
            +
            RCrTM0fHg-o
         | 
| 1262 | 
            +
            RDeLBp_-3sM
         | 
| 1263 | 
            +
            RDkMkH4drhc
         | 
| 1264 | 
            +
            REUvXBK7ypQ
         | 
| 1265 | 
            +
            REzffEzpiUM
         | 
| 1266 | 
            +
            RFM-LCECtmk
         | 
| 1267 | 
            +
            RPTk00TE3Ak
         | 
| 1268 | 
            +
            RQXCRoVV9Hc
         | 
| 1269 | 
            +
            RSJQ7iFntRA
         | 
| 1270 | 
            +
            RVG1EXFbRb0
         | 
| 1271 | 
            +
            RVQcpNgh6sI
         | 
| 1272 | 
            +
            RVluy0cjHbA
         | 
| 1273 | 
            +
            RWjDH6Od5xU
         | 
| 1274 | 
            +
            RWoOC8KvHEA
         | 
| 1275 | 
            +
            RXEUWvpmJaI
         | 
| 1276 | 
            +
            RY8e2Ivu4Ak
         | 
| 1277 | 
            +
            Raiw3nozIoc
         | 
| 1278 | 
            +
            RaqHo26ohYs
         | 
| 1279 | 
            +
            Rb2fCxGGcHE
         | 
| 1280 | 
            +
            RdGOK7ZAHMc
         | 
| 1281 | 
            +
            RdhwDd8PW0Y
         | 
| 1282 | 
            +
            Rdi5ExhmqHM
         | 
| 1283 | 
            +
            RdlMCh2idHI
         | 
| 1284 | 
            +
            RfP1AjOOtSE
         | 
| 1285 | 
            +
            RfmgkgzNhYU
         | 
| 1286 | 
            +
            Rh5qNYU-_jI
         | 
| 1287 | 
            +
            RhcnVBgKxEg
         | 
| 1288 | 
            +
            Rhn0fatp9PI
         | 
| 1289 | 
            +
            Ri-M_Vo3w5A
         | 
| 1290 | 
            +
            RjzuefWqVY8
         | 
| 1291 | 
            +
            Rm5MIya_48o
         | 
| 1292 | 
            +
            RovZoquZGn4
         | 
| 1293 | 
            +
            RsC_d7GnZtI
         | 
| 1294 | 
            +
            RsX1lwPnPPQ
         | 
| 1295 | 
            +
            RvjlBL4A_8U
         | 
| 1296 | 
            +
            RweXbb_OzBU
         | 
| 1297 | 
            +
            RyiqQnCd7qQ
         | 
| 1298 | 
            +
            RyszHongpf0
         | 
| 1299 | 
            +
            S-imxWoyMD0
         | 
| 1300 | 
            +
            S0MWAAykFuc
         | 
| 1301 | 
            +
            S1MV9j0dPAQ
         | 
| 1302 | 
            +
            S4Fje5FUgfw
         | 
| 1303 | 
            +
            S4nfcw632Oo
         | 
| 1304 | 
            +
            S5OzDdLlsUI
         | 
| 1305 | 
            +
            SBUwUUIVwHM
         | 
| 1306 | 
            +
            SCjA7BJDnEM
         | 
| 1307 | 
            +
            SD-LjOboaE0
         | 
| 1308 | 
            +
            SDCICtm9zXQ
         | 
| 1309 | 
            +
            SEDDSCUJxK8
         | 
| 1310 | 
            +
            SFE7NNxfbM4
         | 
| 1311 | 
            +
            SH80ZuySDW4
         | 
| 1312 | 
            +
            SLaZEauuEU8
         | 
| 1313 | 
            +
            SNBMdDaYhZA
         | 
| 1314 | 
            +
            SNcjWH6ZhPI
         | 
| 1315 | 
            +
            SOUME9xzIxk
         | 
| 1316 | 
            +
            SSGEoCsFoH4
         | 
| 1317 | 
            +
            SSfhcpWRUrM
         | 
| 1318 | 
            +
            SSnj8kkmNDI
         | 
| 1319 | 
            +
            STKRq8VXzjw
         | 
| 1320 | 
            +
            STKb-ai6874
         | 
| 1321 | 
            +
            STWrgFYmkL4
         | 
| 1322 | 
            +
            SVR3ZmdAV-A
         | 
| 1323 | 
            +
            SYriZ4xtdDM
         | 
| 1324 | 
            +
            SaznCPVAiJc
         | 
| 1325 | 
            +
            Sd3QWZ76IZg
         | 
| 1326 | 
            +
            SfaKxqo1NfQ
         | 
| 1327 | 
            +
            SfkSpHzhZb8
         | 
| 1328 | 
            +
            Sg-HIZ3qgtk
         | 
| 1329 | 
            +
            SjNRtrZjkfE
         | 
| 1330 | 
            +
            SjbFjIeSCf0
         | 
| 1331 | 
            +
            SlJh09MsJ7I
         | 
| 1332 | 
            +
            SnwbCVxeEVU
         | 
| 1333 | 
            +
            SoeKlf4DcSE
         | 
| 1334 | 
            +
            SqRfNG6yLEk
         | 
| 1335 | 
            +
            SrLPH5590RU
         | 
| 1336 | 
            +
            SsIDNPoW7q8
         | 
| 1337 | 
            +
            Su8Q8XMQzIM
         | 
| 1338 | 
            +
            SuYeKcei7Zo
         | 
| 1339 | 
            +
            SvWCVOGF6vs
         | 
| 1340 | 
            +
            SzjmpNTVH6U
         | 
| 1341 | 
            +
            Szx43_ah4ys
         | 
| 1342 | 
            +
            T-CAP-ULW_A
         | 
| 1343 | 
            +
            T0qjkPboQXY
         | 
| 1344 | 
            +
            T4kVhUwJZdo
         | 
| 1345 | 
            +
            T6P9TCdWE64
         | 
| 1346 | 
            +
            T9X3YhUWsDc
         | 
| 1347 | 
            +
            TAdw9R0ku2o
         | 
| 1348 | 
            +
            TFPS-iX0L4s
         | 
| 1349 | 
            +
            TGCJQR2BZhc
         | 
| 1350 | 
            +
            TIgRgGQ2azQ
         | 
| 1351 | 
            +
            TJXW9hpOlnI
         | 
| 1352 | 
            +
            TMjlO7UUubU
         | 
| 1353 | 
            +
            TNEWst_1m4s
         | 
| 1354 | 
            +
            TOT4eRF4oCU
         | 
| 1355 | 
            +
            TOzkrCUSlFg
         | 
| 1356 | 
            +
            TP2wD0LX4T8
         | 
| 1357 | 
            +
            TQ2NfO8grLs
         | 
| 1358 | 
            +
            TQ7NqpFMbFs
         | 
| 1359 | 
            +
            TQHxvPooKZc
         | 
| 1360 | 
            +
            TQzJKL_4l44
         | 
| 1361 | 
            +
            TS5BXMeG890
         | 
| 1362 | 
            +
            TUVeg-x9Za4
         | 
| 1363 | 
            +
            TX0v0pIVKUY
         | 
| 1364 | 
            +
            TXjwmCoRmhM
         | 
| 1365 | 
            +
            TckoXQoHj7c
         | 
| 1366 | 
            +
            Tg2yHK2Hnag
         | 
| 1367 | 
            +
            Tm1RbCh9YeA
         | 
| 1368 | 
            +
            Tq-AsJ8M5yw
         | 
| 1369 | 
            +
            Trq6vcUOeQE
         | 
| 1370 | 
            +
            Ts04-23URYA
         | 
| 1371 | 
            +
            Tu22Y0kIzJ0
         | 
| 1372 | 
            +
            TuoGVwBkTEA
         | 
| 1373 | 
            +
            TxC0dIBPzZg
         | 
| 1374 | 
            +
            TzzhAQLRwT8
         | 
| 1375 | 
            +
            U-kFZbOf6Nk
         | 
| 1376 | 
            +
            U1VkpKvSn5w
         | 
| 1377 | 
            +
            U2LvmqmOEZI
         | 
| 1378 | 
            +
            U2eqvs_MZGg
         | 
| 1379 | 
            +
            U4auzU8E2ms
         | 
| 1380 | 
            +
            U5Ze75nn72M
         | 
| 1381 | 
            +
            UA-U6m9O5OI
         | 
| 1382 | 
            +
            UBVzrTJEbS0
         | 
| 1383 | 
            +
            UDvCqeXCI-o
         | 
| 1384 | 
            +
            UFXt6O5cxjw
         | 
| 1385 | 
            +
            UGRFE3vTcRA
         | 
| 1386 | 
            +
            UIV2gt1Jzno
         | 
| 1387 | 
            +
            UIr0uGUWN6g
         | 
| 1388 | 
            +
            UJeKNl461d8
         | 
| 1389 | 
            +
            UJjixKei0ag
         | 
| 1390 | 
            +
            UKBlZt_JL-I
         | 
| 1391 | 
            +
            UKc54igtdXI
         | 
| 1392 | 
            +
            UL42vZliknk
         | 
| 1393 | 
            +
            UOGLLo60dzI
         | 
| 1394 | 
            +
            UPRvrLsqN8U
         | 
| 1395 | 
            +
            UPU_yi9Nv3M
         | 
| 1396 | 
            +
            UQO5Qcl8aAk
         | 
| 1397 | 
            +
            URC125wpMS4
         | 
| 1398 | 
            +
            UT7n0WY_6Ww
         | 
| 1399 | 
            +
            UTYuVdJskY0
         | 
| 1400 | 
            +
            UUT_nhIlR_U
         | 
| 1401 | 
            +
            UUoBfrbl1Cs
         | 
| 1402 | 
            +
            UV1luTyPOiY
         | 
| 1403 | 
            +
            UVTsXdLyIsk
         | 
| 1404 | 
            +
            UVaN02jNqgM
         | 
| 1405 | 
            +
            UXEr-xcC46E
         | 
| 1406 | 
            +
            UXRKQjlYUZU
         | 
| 1407 | 
            +
            UXZm1KDE_qA
         | 
| 1408 | 
            +
            UbyxFZSZZ90
         | 
| 1409 | 
            +
            UcwU4ghl9Gg
         | 
| 1410 | 
            +
            UdpTELIW7bU
         | 
| 1411 | 
            +
            UeMQ_al9lDQ
         | 
| 1412 | 
            +
            UeO44STvnJw
         | 
| 1413 | 
            +
            UjAxgnvxIJE
         | 
| 1414 | 
            +
            UlKZ83REIkA
         | 
| 1415 | 
            +
            Ul_ZfzfHRek
         | 
| 1416 | 
            +
            UlsgLGCVKks
         | 
| 1417 | 
            +
            UmA3FpFowh4
         | 
| 1418 | 
            +
            UoVJllDh6rg
         | 
| 1419 | 
            +
            UpScMViXT1s
         | 
| 1420 | 
            +
            Ux-ExovbpsE
         | 
| 1421 | 
            +
            V1frWTXGVN8
         | 
| 1422 | 
            +
            V2DvDDzrFqI
         | 
| 1423 | 
            +
            V2XB2l3aFvc
         | 
| 1424 | 
            +
            V2x33UdHq4w
         | 
| 1425 | 
            +
            V3nPA6doMBM
         | 
| 1426 | 
            +
            V5FsNyk9rDo
         | 
| 1427 | 
            +
            V5blsv5pn60
         | 
| 1428 | 
            +
            V5uV1vR2M6g
         | 
| 1429 | 
            +
            V6egGoCrbIo
         | 
| 1430 | 
            +
            V7uG1tWVqHM
         | 
| 1431 | 
            +
            VC7lRZTxDng
         | 
| 1432 | 
            +
            VDLUQlOR_nI
         | 
| 1433 | 
            +
            VF0hNn-Yfn0
         | 
| 1434 | 
            +
            VFJsMQnqZZ4
         | 
| 1435 | 
            +
            VFeOyT16oEI
         | 
| 1436 | 
            +
            VFf_xowsMcQ
         | 
| 1437 | 
            +
            VGOslZT-f-I
         | 
| 1438 | 
            +
            VJjiUcZCkzw
         | 
| 1439 | 
            +
            VKfVhH35RL4
         | 
| 1440 | 
            +
            VKnNVP23toY
         | 
| 1441 | 
            +
            VNtYIBI3BFc
         | 
| 1442 | 
            +
            VOFQb8sVnxs
         | 
| 1443 | 
            +
            VOomWcgrHis
         | 
| 1444 | 
            +
            VRu86oG1hVY
         | 
| 1445 | 
            +
            VSRuncwwJyQ
         | 
| 1446 | 
            +
            VTsKS3ccd5M
         | 
| 1447 | 
            +
            VVV3XeAevc8
         | 
| 1448 | 
            +
            VWc3ezusNTg
         | 
| 1449 | 
            +
            VWrYbF797LI
         | 
| 1450 | 
            +
            VYE91m6Rli4
         | 
| 1451 | 
            +
            VYKXayozHFU
         | 
| 1452 | 
            +
            VZ0-gccLaNU
         | 
| 1453 | 
            +
            VZki-LyHI0E
         | 
| 1454 | 
            +
            V_lZ61OB0EI
         | 
| 1455 | 
            +
            VcLWubfmJcM
         | 
| 1456 | 
            +
            VcYUWSBo4i4
         | 
| 1457 | 
            +
            Vcvl5piGlYg
         | 
| 1458 | 
            +
            VePpQBCbKBw
         | 
| 1459 | 
            +
            VfLSoyinXmo
         | 
| 1460 | 
            +
            VfmcO0gQ8B4
         | 
| 1461 | 
            +
            VfxI-6_LL54
         | 
| 1462 | 
            +
            VgrW-fB3EXI
         | 
| 1463 | 
            +
            Vm2mKdh_VUc
         | 
| 1464 | 
            +
            VmPl5QClxYk
         | 
| 1465 | 
            +
            VpKnSOS6NGo
         | 
| 1466 | 
            +
            Vpw09qKQal0
         | 
| 1467 | 
            +
            VsOismDNYjE
         | 
| 1468 | 
            +
            VvXMMtldJU0
         | 
| 1469 | 
            +
            Vw7hC4jpglg
         | 
| 1470 | 
            +
            Vwxft_tqrcg
         | 
| 1471 | 
            +
            Vy6PKQy2OI0
         | 
| 1472 | 
            +
            VyJCLVAj-vE
         | 
| 1473 | 
            +
            VzHAbg24fRs
         | 
| 1474 | 
            +
            W-7t8Zho4AI
         | 
| 1475 | 
            +
            W-_X1HZM7ys
         | 
| 1476 | 
            +
            W0Mw5dfZoyg
         | 
| 1477 | 
            +
            W0caVAMB7LQ
         | 
| 1478 | 
            +
            W1tOTi9L7Hs
         | 
| 1479 | 
            +
            W354uz6KPJE
         | 
| 1480 | 
            +
            W3H5b9yZcOs
         | 
| 1481 | 
            +
            W3XADagE6P8
         | 
| 1482 | 
            +
            W42cARRDRe4
         | 
| 1483 | 
            +
            W4PKfrQ2J5Q
         | 
| 1484 | 
            +
            W8mQ41XaZvo
         | 
| 1485 | 
            +
            W9okU7bAE-U
         | 
| 1486 | 
            +
            WA1L8vXkSKQ
         | 
| 1487 | 
            +
            WA9sMdQzdiA
         | 
| 1488 | 
            +
            WAl7wIw5ReQ
         | 
| 1489 | 
            +
            WBZ3das2pd0
         | 
| 1490 | 
            +
            WDialA8RHEg
         | 
| 1491 | 
            +
            WIiuU7Fd-KA
         | 
| 1492 | 
            +
            WJBgKbe1ZyU
         | 
| 1493 | 
            +
            WJFdyqLo-pM
         | 
| 1494 | 
            +
            WJaW32ZTyKE
         | 
| 1495 | 
            +
            WJlK8D9Vy1k
         | 
| 1496 | 
            +
            WL5IJ4JVjrg
         | 
| 1497 | 
            +
            WLVKRBitiY4
         | 
| 1498 | 
            +
            WMl7MSsJMGI
         | 
| 1499 | 
            +
            WP4jOqfpJx8
         | 
| 1500 | 
            +
            WPIIgluc2vA
         | 
| 1501 | 
            +
            WQ2QwrfZHTk
         | 
| 1502 | 
            +
            WQ4W-UqaaMo
         | 
| 1503 | 
            +
            WQXM3hU-7vk
         | 
| 1504 | 
            +
            WQiGCGxYMm4
         | 
| 1505 | 
            +
            WR4vkITJckY
         | 
| 1506 | 
            +
            WT2aDvMsZF8
         | 
| 1507 | 
            +
            WTxTntSi6Jw
         | 
| 1508 | 
            +
            WUx-OqSLBak
         | 
| 1509 | 
            +
            WUzV_mDcBmk
         | 
| 1510 | 
            +
            WXKNBguF0a0
         | 
| 1511 | 
            +
            WZQi3LOqiNc
         | 
| 1512 | 
            +
            WZw5Vz_imPM
         | 
| 1513 | 
            +
            WcLq2oABDhA
         | 
| 1514 | 
            +
            WeHTlU8efMA
         | 
| 1515 | 
            +
            WgWkOiDD4n4
         | 
| 1516 | 
            +
            WiILKjGKveI
         | 
| 1517 | 
            +
            WiNgIQ1pOlE
         | 
| 1518 | 
            +
            Wj6MkLWm8dQ
         | 
| 1519 | 
            +
            Wmt5FzPTuXE
         | 
| 1520 | 
            +
            WnQCWE22AYs
         | 
| 1521 | 
            +
            Wq5ZIu0UZmE
         | 
| 1522 | 
            +
            Wqb2ZPi6KyI
         | 
| 1523 | 
            +
            Wrb8tfqYPzw
         | 
| 1524 | 
            +
            WsQ7ysVt-0A
         | 
| 1525 | 
            +
            WssviVcyncg
         | 
| 1526 | 
            +
            Wx9v_J34Fyo
         | 
| 1527 | 
            +
            Wxp1QG7GIBs
         | 
| 1528 | 
            +
            WysUzNnT4i0
         | 
| 1529 | 
            +
            Wz6DxjLZSbc
         | 
| 1530 | 
            +
            WzyI1gx_PHI
         | 
| 1531 | 
            +
            X-fZ5fMfAv4
         | 
| 1532 | 
            +
            X-irPLY6oLk
         | 
| 1533 | 
            +
            X2ac5fHYZ3I
         | 
| 1534 | 
            +
            X3bcvqrTTJI
         | 
| 1535 | 
            +
            X3tI7SRuvhw
         | 
| 1536 | 
            +
            X3ztiC2hUXM
         | 
| 1537 | 
            +
            X7Jd6mI9iHM
         | 
| 1538 | 
            +
            X7WI5_UUpys
         | 
| 1539 | 
            +
            XAJMmm6sLQs
         | 
| 1540 | 
            +
            XAhljQgieEs
         | 
| 1541 | 
            +
            XAlAgC7rYug
         | 
| 1542 | 
            +
            XBF-Pd_asag
         | 
| 1543 | 
            +
            XEHxXWpF6qI
         | 
| 1544 | 
            +
            XIXA-Kqb_Os
         | 
| 1545 | 
            +
            XKCWJuWup08
         | 
| 1546 | 
            +
            XL6m6Zl2ejc
         | 
| 1547 | 
            +
            XLSJ7NIldNo
         | 
| 1548 | 
            +
            XPgdPEYr648
         | 
| 1549 | 
            +
            XPwYTyTbCag
         | 
| 1550 | 
            +
            XQy5b5mlVZ4
         | 
| 1551 | 
            +
            XUxgC9KYoPE
         | 
| 1552 | 
            +
            XVtVVuER3W4
         | 
| 1553 | 
            +
            XXKVwqZS1R8
         | 
| 1554 | 
            +
            XXgJZXUPZXM
         | 
| 1555 | 
            +
            XZ70Li8v68o
         | 
| 1556 | 
            +
            XZxl6h-TxQ4
         | 
| 1557 | 
            +
            XaGss5gNQEM
         | 
| 1558 | 
            +
            XabAlfY1TyQ
         | 
| 1559 | 
            +
            XaxSxkApUQc
         | 
| 1560 | 
            +
            Xb32P_VWh7w
         | 
| 1561 | 
            +
            XbDyn-2_xIc
         | 
| 1562 | 
            +
            XbNcsgEX2jc
         | 
| 1563 | 
            +
            XbtdjM8wGv4
         | 
| 1564 | 
            +
            XcZaQG7wUpA
         | 
| 1565 | 
            +
            Xdlo2HW5jwk
         | 
| 1566 | 
            +
            Xf6xJiXV3AM
         | 
| 1567 | 
            +
            XfMoY5WSlvc
         | 
| 1568 | 
            +
            XkNofrvAt2s
         | 
| 1569 | 
            +
            XkX-zJa_9Wo
         | 
| 1570 | 
            +
            XlQzQ55BA0c
         | 
| 1571 | 
            +
            XlYXYqwEeJw
         | 
| 1572 | 
            +
            XoVZxH4CwMQ
         | 
| 1573 | 
            +
            Xq-YIJA61W4
         | 
| 1574 | 
            +
            XrGuIdJ0Ckg
         | 
| 1575 | 
            +
            XvfpyrdeZ0s
         | 
| 1576 | 
            +
            Xw2PEuhphPk
         | 
| 1577 | 
            +
            Xwu5PSZfocc
         | 
| 1578 | 
            +
            XxqpGCkrF8g
         | 
| 1579 | 
            +
            XyvlWUQAkxM
         | 
| 1580 | 
            +
            Y05wSSdslyI
         | 
| 1581 | 
            +
            Y1QnypwCPZo
         | 
| 1582 | 
            +
            Y2zmCgmDVqk
         | 
| 1583 | 
            +
            Y3sbt-6ndq0
         | 
| 1584 | 
            +
            Y65tbaBs88M
         | 
| 1585 | 
            +
            Y6Mn-d9QMxY
         | 
| 1586 | 
            +
            Y9anPwwkuU4
         | 
| 1587 | 
            +
            Y9rkKtK1b44
         | 
| 1588 | 
            +
            YC3Hhxqbof0
         | 
| 1589 | 
            +
            YECIYrmXH0o
         | 
| 1590 | 
            +
            YEgE-m8kzpM
         | 
| 1591 | 
            +
            YGdNSqa_clI
         | 
| 1592 | 
            +
            YGwLb86Uso8
         | 
| 1593 | 
            +
            YIDhGzp8Z2s
         | 
| 1594 | 
            +
            YJkS7QqeYPw
         | 
| 1595 | 
            +
            YMoa5JpjEtM
         | 
| 1596 | 
            +
            YMqKHYZHQD0
         | 
| 1597 | 
            +
            YO-oamNqsA4
         | 
| 1598 | 
            +
            YOD6jIFD5aw
         | 
| 1599 | 
            +
            YP_35HEWcfc
         | 
| 1600 | 
            +
            YUJa7_i3Cn8
         | 
| 1601 | 
            +
            YUxb5mw96eQ
         | 
| 1602 | 
            +
            YWpX7tlXLB0
         | 
| 1603 | 
            +
            YXPEXwjYpGA
         | 
| 1604 | 
            +
            YXfpaJVsVa4
         | 
| 1605 | 
            +
            YYTcoNCWy8c
         | 
| 1606 | 
            +
            YZBLFRe-G0A
         | 
| 1607 | 
            +
            YZLGkfy0_oM
         | 
| 1608 | 
            +
            YZME4lTWBHY
         | 
| 1609 | 
            +
            YZp4fNMECVg
         | 
| 1610 | 
            +
            YcGOV1iUBlE
         | 
| 1611 | 
            +
            YeIn1rFbTuw
         | 
| 1612 | 
            +
            Yex9CPZzezk
         | 
| 1613 | 
            +
            Yf_jdF01azE
         | 
| 1614 | 
            +
            YgCBzXR63l8
         | 
| 1615 | 
            +
            YhoYie6_la0
         | 
| 1616 | 
            +
            YiPEZWaxSXs
         | 
| 1617 | 
            +
            YjTCns1fFmM
         | 
| 1618 | 
            +
            YjwTPflZm70
         | 
| 1619 | 
            +
            YlIl427ZdHc
         | 
| 1620 | 
            +
            YnRgf2UNBXA
         | 
| 1621 | 
            +
            Yo-CEXgHwkk
         | 
| 1622 | 
            +
            YpmKbkU-X_U
         | 
| 1623 | 
            +
            YtiVmh7UKOw
         | 
| 1624 | 
            +
            YuLSfLZ9apM
         | 
| 1625 | 
            +
            Yui2Msy8X1E
         | 
| 1626 | 
            +
            YvRRXziXpMY
         | 
| 1627 | 
            +
            YwqTTdUEJGc
         | 
| 1628 | 
            +
            Z12xymgfH9k
         | 
| 1629 | 
            +
            Z3r9tnbK_iU
         | 
| 1630 | 
            +
            Z5SpCVtoOdw
         | 
| 1631 | 
            +
            Z75PmkL_UaQ
         | 
| 1632 | 
            +
            Z8iLMnTX6OQ
         | 
| 1633 | 
            +
            ZAX4LKUeAVE
         | 
| 1634 | 
            +
            ZAYK9cMiSbE
         | 
| 1635 | 
            +
            ZBcOyv8LZ8s
         | 
| 1636 | 
            +
            ZDfRJiIODMs
         | 
| 1637 | 
            +
            ZDv9njERj0s
         | 
| 1638 | 
            +
            ZEHCzjk0Hrk
         | 
| 1639 | 
            +
            ZFnr_mTTL0E
         | 
| 1640 | 
            +
            ZGzQUBDGd-g
         | 
| 1641 | 
            +
            ZH6357PHRCc
         | 
| 1642 | 
            +
            ZHLsDRxEMGs
         | 
| 1643 | 
            +
            ZPHfpA_4uhY
         | 
| 1644 | 
            +
            ZQPrD6cbqHQ
         | 
| 1645 | 
            +
            ZQQwgYaQh1w
         | 
| 1646 | 
            +
            ZSEV1ivNUWY
         | 
| 1647 | 
            +
            ZSTo8stxfG0
         | 
| 1648 | 
            +
            ZUlkRGgSLfI
         | 
| 1649 | 
            +
            ZXMx5C9oFk8
         | 
| 1650 | 
            +
            ZYSjPZUqLdk
         | 
| 1651 | 
            +
            ZZIjgZYnP6Q
         | 
| 1652 | 
            +
            Z_TNQsWm8SM
         | 
| 1653 | 
            +
            ZcO5PLLXLy0
         | 
| 1654 | 
            +
            Zg4zFxyeLMQ
         | 
| 1655 | 
            +
            Zi2RoikofDs
         | 
| 1656 | 
            +
            Zj7U7R-2fcs
         | 
| 1657 | 
            +
            ZjmynEwugnk
         | 
| 1658 | 
            +
            Zn8iU3-RNL0
         | 
| 1659 | 
            +
            ZnpqfpPzQAE
         | 
| 1660 | 
            +
            Zot-rd9KoYE
         | 
| 1661 | 
            +
            ZoyUo4ZY-70
         | 
| 1662 | 
            +
            ZpCK7G0LQAc
         | 
| 1663 | 
            +
            ZpNQS6CX7FA
         | 
| 1664 | 
            +
            ZpbEtTNDQBM
         | 
| 1665 | 
            +
            ZptziXSxpx0
         | 
| 1666 | 
            +
            ZsMJ8wO1YKs
         | 
| 1667 | 
            +
            ZsY6kAHzdwM
         | 
| 1668 | 
            +
            ZtXr7bckLyc
         | 
| 1669 | 
            +
            ZvAaTKbPzH8
         | 
| 1670 | 
            +
            ZyOqaUFxojc
         | 
| 1671 | 
            +
            ZyUCcfMcmyE
         | 
| 1672 | 
            +
            ZzVhwsetzDk
         | 
| 1673 | 
            +
            _1B60L4m60M
         | 
| 1674 | 
            +
            _4bzRoRn260
         | 
| 1675 | 
            +
            _4r4LIX84TM
         | 
| 1676 | 
            +
            _5O0_4kkKSg
         | 
| 1677 | 
            +
            _5r3yqpaNuM
         | 
| 1678 | 
            +
            _6AK5vp6nDE
         | 
| 1679 | 
            +
            _6ck3EDlssw
         | 
| 1680 | 
            +
            _7RMd0g9FtQ
         | 
| 1681 | 
            +
            _A-pZH-S4jk
         | 
| 1682 | 
            +
            _AvNT3vyzr0
         | 
| 1683 | 
            +
            _BxhdmIGNys
         | 
| 1684 | 
            +
            _CKFycGHzLo
         | 
| 1685 | 
            +
            _F6bq0l18Ng
         | 
| 1686 | 
            +
            _FcVS3nf3Qs
         | 
| 1687 | 
            +
            _H71S7ar21o
         | 
| 1688 | 
            +
            _ITluulB74Q
         | 
| 1689 | 
            +
            _K-JEM9RNeA
         | 
| 1690 | 
            +
            _KIjLRuf4NQ
         | 
| 1691 | 
            +
            _LR1NtZOISg
         | 
| 1692 | 
            +
            _OhqC6w4C28
         | 
| 1693 | 
            +
            _QRahNSxQfc
         | 
| 1694 | 
            +
            _SYvYBxt_Dg
         | 
| 1695 | 
            +
            _UVuXcclWM8
         | 
| 1696 | 
            +
            _WN-6t58HdM
         | 
| 1697 | 
            +
            _Xo-Cy_okCE
         | 
| 1698 | 
            +
            _ZZVgjbePRI
         | 
| 1699 | 
            +
            _ZdfwflsC3U
         | 
| 1700 | 
            +
            _aOcddJCrSQ
         | 
| 1701 | 
            +
            _ak7BooJlnk
         | 
| 1702 | 
            +
            _bBrj6QBPW0
         | 
| 1703 | 
            +
            _cg2nSAfeUY
         | 
| 1704 | 
            +
            _czQyx6JYgc
         | 
| 1705 | 
            +
            _f2hDpHsQlg
         | 
| 1706 | 
            +
            _gJN7I0a9XU
         | 
| 1707 | 
            +
            _gR3p72XEMg
         | 
| 1708 | 
            +
            _gm8Jp_4a5E
         | 
| 1709 | 
            +
            _hE7CQmHPNI
         | 
| 1710 | 
            +
            _hYhPQTHOMg
         | 
| 1711 | 
            +
            _kUyGB9O_Hs
         | 
| 1712 | 
            +
            _nwF3zYpfQ4
         | 
| 1713 | 
            +
            _piu_0WXnOA
         | 
| 1714 | 
            +
            _rWxLXmPdc0
         | 
| 1715 | 
            +
            _sWO1yvsmmo
         | 
| 1716 | 
            +
            _t61OZ5dN9Q
         | 
| 1717 | 
            +
            _uV1LuL6yDQ
         | 
| 1718 | 
            +
            _y9aHEd08LM
         | 
| 1719 | 
            +
            _yKGZu_8gyI
         | 
| 1720 | 
            +
            _zYWKwpARf0
         | 
| 1721 | 
            +
            a3Ah-REb5vc
         | 
| 1722 | 
            +
            a3mNe6zQS7Y
         | 
| 1723 | 
            +
            a5CAVvzL2GA
         | 
| 1724 | 
            +
            a5lUNW9wlpY
         | 
| 1725 | 
            +
            a8-ySFmij_I
         | 
| 1726 | 
            +
            aA1H4iLap44
         | 
| 1727 | 
            +
            aB0Ku9J6jHg
         | 
| 1728 | 
            +
            aDURTM8MwIE
         | 
| 1729 | 
            +
            aGPO0OB2_Ak
         | 
| 1730 | 
            +
            aJAQVletzdY
         | 
| 1731 | 
            +
            aLPYGw9HubM
         | 
| 1732 | 
            +
            aN5gtrkwgb4
         | 
| 1733 | 
            +
            aQM3Hbvospw
         | 
| 1734 | 
            +
            aSDRWUh7nqQ
         | 
| 1735 | 
            +
            aSF8LfYNlSM
         | 
| 1736 | 
            +
            aSp8Pf6zXvg
         | 
| 1737 | 
            +
            aSuaW_0lLYY
         | 
| 1738 | 
            +
            aTigt0mmyiM
         | 
| 1739 | 
            +
            aValNp9ADko
         | 
| 1740 | 
            +
            aVstEGR5jt0
         | 
| 1741 | 
            +
            aVtOmrULE2w
         | 
| 1742 | 
            +
            aZn-H9uoYk8
         | 
| 1743 | 
            +
            abAitsu2-iA
         | 
| 1744 | 
            +
            acWlXpQu83s
         | 
| 1745 | 
            +
            ad7p5nSZbBg
         | 
| 1746 | 
            +
            adXUEwBrrl0
         | 
| 1747 | 
            +
            ae527aiePIg
         | 
| 1748 | 
            +
            afqjRWOtCzM
         | 
| 1749 | 
            +
            ajI8zq2SedY
         | 
| 1750 | 
            +
            aluYFRd96Kk
         | 
| 1751 | 
            +
            aqz-KE-bpKQ
         | 
| 1752 | 
            +
            asFNxO3cXMY
         | 
| 1753 | 
            +
            asyKEIv1pZw
         | 
| 1754 | 
            +
            atd0dgRkl2k
         | 
| 1755 | 
            +
            au5oFT_zkYU
         | 
| 1756 | 
            +
            avITb-TZWOQ
         | 
| 1757 | 
            +
            ays4JisCVAw
         | 
| 1758 | 
            +
            azPa3uccg2I
         | 
| 1759 | 
            +
            b-lZA6gHWg8
         | 
| 1760 | 
            +
            b0dX-hS1mUY
         | 
| 1761 | 
            +
            b3wy7s_QvOY
         | 
| 1762 | 
            +
            b44IhiCuNw4
         | 
| 1763 | 
            +
            b4jlwhPxTpo
         | 
| 1764 | 
            +
            b552H9Gclo0
         | 
| 1765 | 
            +
            b6DszEFrkSQ
         | 
| 1766 | 
            +
            bBpQgQ416dY
         | 
| 1767 | 
            +
            bCbKYU8D2QA
         | 
| 1768 | 
            +
            bCqq2y9Ge-A
         | 
| 1769 | 
            +
            bDjCnFvz11A
         | 
| 1770 | 
            +
            bHeksIj7dpM
         | 
| 1771 | 
            +
            bI0kawdOOXs
         | 
| 1772 | 
            +
            bKqwRavOIVY
         | 
| 1773 | 
            +
            bL2qA6Gt6Ko
         | 
| 1774 | 
            +
            bMtTAQHLc6A
         | 
| 1775 | 
            +
            bPnX7JwHQEg
         | 
| 1776 | 
            +
            bQ5gacQY7y8
         | 
| 1777 | 
            +
            bRh_KJ6yyGU
         | 
| 1778 | 
            +
            bSySiLIcnzs
         | 
| 1779 | 
            +
            bUAg8d3aQZU
         | 
| 1780 | 
            +
            bWh4bNRqaK0
         | 
| 1781 | 
            +
            b_PbouAwYIU
         | 
| 1782 | 
            +
            babTVMWIosM
         | 
| 1783 | 
            +
            bc15oBT5Nec
         | 
| 1784 | 
            +
            be0sJh-pxOg
         | 
| 1785 | 
            +
            bebrJ-o4d2E
         | 
| 1786 | 
            +
            bg6f32E9vN0
         | 
| 1787 | 
            +
            bhMSZQLSp2M
         | 
| 1788 | 
            +
            bi3iqJykwEo
         | 
| 1789 | 
            +
            bj77Ljq7kbA
         | 
| 1790 | 
            +
            bjNvrJwE9Dc
         | 
| 1791 | 
            +
            bk4b1P_IHZ8
         | 
| 1792 | 
            +
            bkUDUnE6aP8
         | 
| 1793 | 
            +
            bkZBYQ7mnrQ
         | 
| 1794 | 
            +
            blCUScrxzdo
         | 
| 1795 | 
            +
            bn5OSGM8oKc
         | 
| 1796 | 
            +
            bqfA6lRrlaU
         | 
| 1797 | 
            +
            bqfAc6X_uUY
         | 
| 1798 | 
            +
            bsNztQbe4Ic
         | 
| 1799 | 
            +
            bugT5lGfl9M
         | 
| 1800 | 
            +
            bvCbqmHHQD8
         | 
| 1801 | 
            +
            bzDZY35Vacw
         | 
| 1802 | 
            +
            c0IrO0Rnlls
         | 
| 1803 | 
            +
            c0XSC8b_9hU
         | 
| 1804 | 
            +
            c1Fjrbt7peU
         | 
| 1805 | 
            +
            c1H__IGGs8E
         | 
| 1806 | 
            +
            c30s6OnCApw
         | 
| 1807 | 
            +
            c41Mm_I_pBc
         | 
| 1808 | 
            +
            c62KFa9jY8E
         | 
| 1809 | 
            +
            c6gVQ2e1zEs
         | 
| 1810 | 
            +
            c7baTdyHv8g
         | 
| 1811 | 
            +
            cBXqfQzrsEY
         | 
| 1812 | 
            +
            cCLOtOW3mIk
         | 
| 1813 | 
            +
            cDJ_DVILBuk
         | 
| 1814 | 
            +
            cFhONVldyE0
         | 
| 1815 | 
            +
            cG_MFoGh_EM
         | 
| 1816 | 
            +
            cH3DOOXFE24
         | 
| 1817 | 
            +
            cIpXNRmZtVc
         | 
| 1818 | 
            +
            cLMUQZr0TOg
         | 
| 1819 | 
            +
            cLVQSb0l2Pw
         | 
| 1820 | 
            +
            cLcmBWC4FBI
         | 
| 1821 | 
            +
            cLofgTNATIQ
         | 
| 1822 | 
            +
            cOtoozzRy8g
         | 
| 1823 | 
            +
            cRiOZTv0dzs
         | 
| 1824 | 
            +
            cSEqa8cLqss
         | 
| 1825 | 
            +
            cSp0k6jEvY4
         | 
| 1826 | 
            +
            cTFi0WEdtvo
         | 
| 1827 | 
            +
            cUkZLttONGM
         | 
| 1828 | 
            +
            cVezZhj7sC0
         | 
| 1829 | 
            +
            cWZD_1CxIJw
         | 
| 1830 | 
            +
            cWdvVQ7hIa8
         | 
| 1831 | 
            +
            cXpb2qzMlJ8
         | 
| 1832 | 
            +
            c_Ok8VutSbw
         | 
| 1833 | 
            +
            caSPzISFhiM
         | 
| 1834 | 
            +
            ca_kO_J5rWg
         | 
| 1835 | 
            +
            cafMvJshI1c
         | 
| 1836 | 
            +
            cbqshch5yAA
         | 
| 1837 | 
            +
            ciV5Vi-3Adw
         | 
| 1838 | 
            +
            cmA7Ze4KPd8
         | 
| 1839 | 
            +
            cngWph0hiVo
         | 
| 1840 | 
            +
            co-tsFhaeRQ
         | 
| 1841 | 
            +
            coswCgQ_Zwg
         | 
| 1842 | 
            +
            cpAUXdNPnQs
         | 
| 1843 | 
            +
            crJ3KpoMxdk
         | 
| 1844 | 
            +
            cvlLKmzsEBc
         | 
| 1845 | 
            +
            cy9rx19dujU
         | 
| 1846 | 
            +
            d0am7-lXaus
         | 
| 1847 | 
            +
            d0npGPi3UPw
         | 
| 1848 | 
            +
            d2b921R6Q7U
         | 
| 1849 | 
            +
            d4gLpU_fqmE
         | 
| 1850 | 
            +
            d9ShdxJRArw
         | 
| 1851 | 
            +
            dBHgd6MNyyE
         | 
| 1852 | 
            +
            dCmfHeROKIE
         | 
| 1853 | 
            +
            dFxMzUUWLeM
         | 
| 1854 | 
            +
            dGwu92AU4TU
         | 
| 1855 | 
            +
            dHx4lFPqPiI
         | 
| 1856 | 
            +
            dIFsZ9uTrpE
         | 
| 1857 | 
            +
            dKfNJ2umK4o
         | 
| 1858 | 
            +
            dMN2CeulM6o
         | 
| 1859 | 
            +
            dMjan7yZ4gU
         | 
| 1860 | 
            +
            dMxd2IrTF7w
         | 
| 1861 | 
            +
            dMxrAgNbTRk
         | 
| 1862 | 
            +
            dMyTRV4x50w
         | 
| 1863 | 
            +
            dP4U1yI1WZ0
         | 
| 1864 | 
            +
            dR4CGlYvT7g
         | 
| 1865 | 
            +
            dSfIxFW_X1c
         | 
| 1866 | 
            +
            dUKtnNKWV44
         | 
| 1867 | 
            +
            dVeMgCpj-4c
         | 
| 1868 | 
            +
            dZCCdLDE8gI
         | 
| 1869 | 
            +
            d_CTrbVqWW0
         | 
| 1870 | 
            +
            d_oCEre1NJ0
         | 
| 1871 | 
            +
            daIt5KbxFNY
         | 
| 1872 | 
            +
            daTulcsI2RU
         | 
| 1873 | 
            +
            dbkgiCgapGc
         | 
| 1874 | 
            +
            dd03Lj8KOjA
         | 
| 1875 | 
            +
            dd9EimkKEZw
         | 
| 1876 | 
            +
            dk2FVz_B5ls
         | 
| 1877 | 
            +
            dnQnF9apUF8
         | 
| 1878 | 
            +
            dnYUpixA8m0
         | 
| 1879 | 
            +
            do2lClbRBmA
         | 
| 1880 | 
            +
            dpHBJkblp2Y
         | 
| 1881 | 
            +
            dt1MS1YmxyY
         | 
| 1882 | 
            +
            dt1XiYVENuk
         | 
| 1883 | 
            +
            dt9To7mMjl0
         | 
| 1884 | 
            +
            dt9tqCG8neM
         | 
| 1885 | 
            +
            dw6X5-D3tmY
         | 
| 1886 | 
            +
            dwd_Z917XGI
         | 
| 1887 | 
            +
            dxWIZ0ODlZE
         | 
| 1888 | 
            +
            e0Q9GzQzBhE
         | 
| 1889 | 
            +
            e1kPOlccTbM
         | 
| 1890 | 
            +
            e3rjGvtVXeo
         | 
| 1891 | 
            +
            e6MyukRaKOc
         | 
| 1892 | 
            +
            e7jMlBiYy98
         | 
| 1893 | 
            +
            e7z4uzyeRzA
         | 
| 1894 | 
            +
            e82tT1ge9Ak
         | 
| 1895 | 
            +
            e89XopekEJI
         | 
| 1896 | 
            +
            eAQBVytibCc
         | 
| 1897 | 
            +
            eCKD8fP2aao
         | 
| 1898 | 
            +
            eDGFEV4CtB0
         | 
| 1899 | 
            +
            eF7TdzaX_Jc
         | 
| 1900 | 
            +
            eFUL4yP0vqo
         | 
| 1901 | 
            +
            eFdjgis1E5I
         | 
| 1902 | 
            +
            eGYkD0e411I
         | 
| 1903 | 
            +
            eILksASDf9w
         | 
| 1904 | 
            +
            eIXNlBbw54g
         | 
| 1905 | 
            +
            eKl16S8gUXk
         | 
| 1906 | 
            +
            eLX1KG3FnBg
         | 
| 1907 | 
            +
            eNtpsXBrhk4
         | 
| 1908 | 
            +
            eO8hhdMv7P4
         | 
| 1909 | 
            +
            eOJ7XVQlnB8
         | 
| 1910 | 
            +
            eObAEb5SBmg
         | 
| 1911 | 
            +
            eQY39NuSXHU
         | 
| 1912 | 
            +
            eQcmzGIKrzg
         | 
| 1913 | 
            +
            eQjsCvqh1_Y
         | 
| 1914 | 
            +
            eRU1XIwXCAE
         | 
| 1915 | 
            +
            eRvOQ8MsyV0
         | 
| 1916 | 
            +
            eSR9swuM61I
         | 
| 1917 | 
            +
            eT5IGtWmQ-M
         | 
| 1918 | 
            +
            eVXJaSgEf74
         | 
| 1919 | 
            +
            eVz41Qm-5aU
         | 
| 1920 | 
            +
            eX3PtJN52g8
         | 
| 1921 | 
            +
            eXeWNtyjgPk
         | 
| 1922 | 
            +
            eY5c3ce48Rs
         | 
| 1923 | 
            +
            e_7T20B65hQ
         | 
| 1924 | 
            +
            edRk4JmnLkM
         | 
| 1925 | 
            +
            efIVRw-eVzU
         | 
| 1926 | 
            +
            efooj84xalQ
         | 
| 1927 | 
            +
            eg0bYuuHzkI
         | 
| 1928 | 
            +
            ehMbGtUiYh4
         | 
| 1929 | 
            +
            ehoNb1i6vY0
         | 
| 1930 | 
            +
            ejrSSx2FMhQ
         | 
| 1931 | 
            +
            eke0xp4rprM
         | 
| 1932 | 
            +
            ekxjCWMq8Z0
         | 
| 1933 | 
            +
            emqCYr2xVGw
         | 
| 1934 | 
            +
            eoHw0W_CzX8
         | 
| 1935 | 
            +
            eoN2Xrs6cxc
         | 
| 1936 | 
            +
            eoWIjARiH6Y
         | 
| 1937 | 
            +
            eowka-cMoxM
         | 
| 1938 | 
            +
            epfVelQrqX8
         | 
| 1939 | 
            +
            eppNMltmm-o
         | 
| 1940 | 
            +
            err7vaMQ4z4
         | 
| 1941 | 
            +
            esVois0s3qg
         | 
| 1942 | 
            +
            esnMNkFAG1U
         | 
| 1943 | 
            +
            estUu_XdB7k
         | 
| 1944 | 
            +
            etnFlNJ-uys
         | 
| 1945 | 
            +
            eub0JuAMSiI
         | 
| 1946 | 
            +
            evORVtwC0zk
         | 
| 1947 | 
            +
            evnEcyr9dIw
         | 
| 1948 | 
            +
            ewQ3FI_u5nY
         | 
| 1949 | 
            +
            exsaT4HrbhA
         | 
| 1950 | 
            +
            exvJz3JPHuI
         | 
| 1951 | 
            +
            eyBEIx7fCfY
         | 
| 1952 | 
            +
            ezQjNJUSraY
         | 
| 1953 | 
            +
            ezxm9w77JKI
         | 
| 1954 | 
            +
            f5kTVt7QnK4
         | 
| 1955 | 
            +
            f5mk7tpuEs4
         | 
| 1956 | 
            +
            f5ud_4pbXPk
         | 
| 1957 | 
            +
            f7HNmm8MHMI
         | 
| 1958 | 
            +
            f9oet4cvYf4
         | 
| 1959 | 
            +
            fAa51WqtOT0
         | 
| 1960 | 
            +
            fAtWwadP6CY
         | 
| 1961 | 
            +
            fDZ8fFOesDQ
         | 
| 1962 | 
            +
            fJrNkspUMno
         | 
| 1963 | 
            +
            fKHcxXH3f6k
         | 
| 1964 | 
            +
            fLQ-pj8lteY
         | 
| 1965 | 
            +
            fLc6CPIre_4
         | 
| 1966 | 
            +
            fO1dl3Kzz40
         | 
| 1967 | 
            +
            fREa-rfs8aU
         | 
| 1968 | 
            +
            fSSzNXPVvYc
         | 
| 1969 | 
            +
            fUQ-OTqjp9c
         | 
| 1970 | 
            +
            fUzh2Hu4JoY
         | 
| 1971 | 
            +
            fV1xRX3XGKk
         | 
| 1972 | 
            +
            fWnDlFMfOA0
         | 
| 1973 | 
            +
            fX_sxgqAKkg
         | 
| 1974 | 
            +
            fXuqsnqsfGE
         | 
| 1975 | 
            +
            fYHqUK0tqH8
         | 
| 1976 | 
            +
            fZ8S5N2akUE
         | 
| 1977 | 
            +
            f_LHuvCZLf0
         | 
| 1978 | 
            +
            fb8d5RZqzA0
         | 
| 1979 | 
            +
            fceagC5I1Yk
         | 
| 1980 | 
            +
            fdANKfoxm6s
         | 
| 1981 | 
            +
            ferxnIAT2Go
         | 
| 1982 | 
            +
            ffVL9wvWfgs
         | 
| 1983 | 
            +
            fgIfH_85nBw
         | 
| 1984 | 
            +
            fgzKbL4HjCs
         | 
| 1985 | 
            +
            fhXPsdrWJiA
         | 
| 1986 | 
            +
            fhrwGiZrvio
         | 
| 1987 | 
            +
            fjW_WL3KLUg
         | 
| 1988 | 
            +
            fk3Cq0mR6_4
         | 
| 1989 | 
            +
            fkJt1i4aO_8
         | 
| 1990 | 
            +
            fkYqJFYFYXI
         | 
| 1991 | 
            +
            fk_RkZortw8
         | 
| 1992 | 
            +
            fnArfARx9wI
         | 
| 1993 | 
            +
            fnW2Qy7uY9Y
         | 
| 1994 | 
            +
            fo65xXZqfoA
         | 
| 1995 | 
            +
            fsUkET-XhzM
         | 
| 1996 | 
            +
            fu1ZVnk2Gqk
         | 
| 1997 | 
            +
            fuRU10ocuds
         | 
| 1998 | 
            +
            fuZ88PJ7Lsg
         | 
| 1999 | 
            +
            fvtbdq3WiyU
         | 
| 2000 | 
            +
            fxIAaegID9M
         | 
| 2001 | 
            +
            fyFOwJRr3I0
         | 
| 2002 | 
            +
            g0UDwv1vPgw
         | 
| 2003 | 
            +
            g0cy2szFR4Y
         | 
| 2004 | 
            +
            g3pERE3VsX8
         | 
| 2005 | 
            +
            g4zf6FeVoxM
         | 
| 2006 | 
            +
            g8DbS9Ochow
         | 
| 2007 | 
            +
            gAjMBetApiA
         | 
| 2008 | 
            +
            gB-ZlM-aUTE
         | 
| 2009 | 
            +
            gB6vLAjfMdc
         | 
| 2010 | 
            +
            gE9soy7r-Ms
         | 
| 2011 | 
            +
            gFZ8NPmkPpg
         | 
| 2012 | 
            +
            gFZj_2voVyA
         | 
| 2013 | 
            +
            gGZq_aR_jyg
         | 
| 2014 | 
            +
            gMZp4NeJq5w
         | 
| 2015 | 
            +
            gOprZJ2CbR0
         | 
| 2016 | 
            +
            gRO6JH35Cdc
         | 
| 2017 | 
            +
            gROnZPk4dnk
         | 
| 2018 | 
            +
            gTDprJn164c
         | 
| 2019 | 
            +
            gTPaMD7qhek
         | 
| 2020 | 
            +
            gTmG636eAYY
         | 
| 2021 | 
            +
            gTzhAelL1go
         | 
| 2022 | 
            +
            gV7XWdt72Vo
         | 
| 2023 | 
            +
            gV8icTgcuyU
         | 
| 2024 | 
            +
            gX0AEmOrKsY
         | 
| 2025 | 
            +
            gX6r9BWwCOI
         | 
| 2026 | 
            +
            gZyG2_WKQvc
         | 
| 2027 | 
            +
            gaUt3gTwwzU
         | 
| 2028 | 
            +
            gb13T2EYzvM
         | 
| 2029 | 
            +
            gcsL5WUXoYU
         | 
| 2030 | 
            +
            gdb3IbS2SGQ
         | 
| 2031 | 
            +
            gksr08xM7dc
         | 
| 2032 | 
            +
            gmKD-PSkATI
         | 
| 2033 | 
            +
            gn_UhhjygOk
         | 
| 2034 | 
            +
            gqxjTyxDC-Q
         | 
| 2035 | 
            +
            gs2r0YmX7rk
         | 
| 2036 | 
            +
            gvYPX1ja9gU
         | 
| 2037 | 
            +
            gwysz5CtZLg
         | 
| 2038 | 
            +
            gxYTI3KmFk0
         | 
| 2039 | 
            +
            gzfKeagBy1k
         | 
| 2040 | 
            +
            h-h1ceF9ToI
         | 
| 2041 | 
            +
            h0Jgoc3tosQ
         | 
| 2042 | 
            +
            h16CeeTSV2Y
         | 
| 2043 | 
            +
            h3sdAzf02O8
         | 
| 2044 | 
            +
            h5ZU5xukqyE
         | 
| 2045 | 
            +
            h7HDtT_cOs4
         | 
| 2046 | 
            +
            hB5cFvlTYWk
         | 
| 2047 | 
            +
            hCc4qd-6h_Y
         | 
| 2048 | 
            +
            hFj2tLk_poo
         | 
| 2049 | 
            +
            hHHYqKqySy8
         | 
| 2050 | 
            +
            hIkJ1Q69eJI
         | 
| 2051 | 
            +
            hK4VPzJYU94
         | 
| 2052 | 
            +
            hMmYNZgItKc
         | 
| 2053 | 
            +
            hN4A9M4qXy8
         | 
| 2054 | 
            +
            hNhlfyoVlLQ
         | 
| 2055 | 
            +
            hO4aTFDeokA
         | 
| 2056 | 
            +
            hOloWe3oYR4
         | 
| 2057 | 
            +
            hPUs3kB39sA
         | 
| 2058 | 
            +
            hPhJlvpNz2Y
         | 
| 2059 | 
            +
            hPt5JG9kGUc
         | 
| 2060 | 
            +
            hQyEUb5DS2o
         | 
| 2061 | 
            +
            hQzC6_3S6xg
         | 
| 2062 | 
            +
            hS-re7JJ8ts
         | 
| 2063 | 
            +
            hS2fdP1bNV0
         | 
| 2064 | 
            +
            hSUDE3-e5_0
         | 
| 2065 | 
            +
            hUKXRN4RzpA
         | 
| 2066 | 
            +
            hXtL9Oe2OTI
         | 
| 2067 | 
            +
            halJEOj2RP4
         | 
| 2068 | 
            +
            hasaLmOLJ8k
         | 
| 2069 | 
            +
            hcl4vYMfvYQ
         | 
| 2070 | 
            +
            hfMHcdPo7fk
         | 
| 2071 | 
            +
            hihIrNRfnpQ
         | 
| 2072 | 
            +
            hnAqGpkvYIM
         | 
| 2073 | 
            +
            hoAGRdA2Zpo
         | 
| 2074 | 
            +
            hpK6FZbxjgs
         | 
| 2075 | 
            +
            hq-1BIaFjGc
         | 
| 2076 | 
            +
            hqbW-EaOcUY
         | 
| 2077 | 
            +
            hr5Px8dD_iw
         | 
| 2078 | 
            +
            hrb-HL0UUpM
         | 
| 2079 | 
            +
            hrhBvOz8ius
         | 
| 2080 | 
            +
            hsfgj1OWX0Q
         | 
| 2081 | 
            +
            htCPtKDBmKw
         | 
| 2082 | 
            +
            htZAga_nSW8
         | 
| 2083 | 
            +
            hv4NNsPaL44
         | 
| 2084 | 
            +
            hw0VaaAhfjM
         | 
| 2085 | 
            +
            hx0rraflBpg
         | 
| 2086 | 
            +
            hxHjQZSANwI
         | 
| 2087 | 
            +
            hxa7Kd8P-oM
         | 
| 2088 | 
            +
            hykLNP-Cpsc
         | 
| 2089 | 
            +
            i-vmCEgFW5g
         | 
| 2090 | 
            +
            i0CP1dmr4ng
         | 
| 2091 | 
            +
            i1-9WDuXJGY
         | 
| 2092 | 
            +
            i17JKd_eCAU
         | 
| 2093 | 
            +
            i1srQA7ocZs
         | 
| 2094 | 
            +
            i2l72jO-otU
         | 
| 2095 | 
            +
            i3DQ9UOs8nY
         | 
| 2096 | 
            +
            i4jX18-l9pI
         | 
| 2097 | 
            +
            i4oLqHRxoZ8
         | 
| 2098 | 
            +
            i5HYNnHtcdY
         | 
| 2099 | 
            +
            i5z06C9Mi00
         | 
| 2100 | 
            +
            i9WbGqPeY8k
         | 
| 2101 | 
            +
            iAWKPOyYdXo
         | 
| 2102 | 
            +
            iCPxwkaCXLk
         | 
| 2103 | 
            +
            iCd5W4gwJsI
         | 
| 2104 | 
            +
            iDJVid5u0Mo
         | 
| 2105 | 
            +
            iDWMIMCMNiQ
         | 
| 2106 | 
            +
            iFJ2pJph-Do
         | 
| 2107 | 
            +
            iIw0Hfm9h7E
         | 
| 2108 | 
            +
            iJJxd-XGQMo
         | 
| 2109 | 
            +
            iKAYJ-makHU
         | 
| 2110 | 
            +
            iN0gsOIWQgw
         | 
| 2111 | 
            +
            iNTSOGM5rCY
         | 
| 2112 | 
            +
            iNhHBJkMz58
         | 
| 2113 | 
            +
            iPDuJS2QUrc
         | 
| 2114 | 
            +
            iSYvDl5iBFQ
         | 
| 2115 | 
            +
            iT5-jVpP_TQ
         | 
| 2116 | 
            +
            iTk4dutvfsE
         | 
| 2117 | 
            +
            iVBD4cmI3_E
         | 
| 2118 | 
            +
            iVbefrog1uI
         | 
| 2119 | 
            +
            iVu7DNjFgWk
         | 
| 2120 | 
            +
            iWRrLD7H98s
         | 
| 2121 | 
            +
            iX1P6XAvtlM
         | 
| 2122 | 
            +
            iXUwLs4kNvc
         | 
| 2123 | 
            +
            iY2XmAG6Rl0
         | 
| 2124 | 
            +
            i_QZJaPorpU
         | 
| 2125 | 
            +
            ib2KHcsUS18
         | 
| 2126 | 
            +
            id1m2sLzwrE
         | 
| 2127 | 
            +
            id8Uq_339xM
         | 
| 2128 | 
            +
            idAzpl13_sc
         | 
| 2129 | 
            +
            ihpS0LTtWjw
         | 
| 2130 | 
            +
            ijPyu-jUJ5Y
         | 
| 2131 | 
            +
            ijlyytCZ_RI
         | 
| 2132 | 
            +
            ikDYpq4uESA
         | 
| 2133 | 
            +
            io3xwOBD4f0
         | 
| 2134 | 
            +
            ioFH4kyF0kY
         | 
| 2135 | 
            +
            ip0yFdCqbkY
         | 
| 2136 | 
            +
            iqm-XEqpayc
         | 
| 2137 | 
            +
            iqmkldsIxkI
         | 
| 2138 | 
            +
            irKLUxa7jkA
         | 
| 2139 | 
            +
            it0EYBBl5LI
         | 
| 2140 | 
            +
            iuqe74uT7fw
         | 
| 2141 | 
            +
            iy-uKpGZmrQ
         | 
| 2142 | 
            +
            j-0L20FH2Zc
         | 
| 2143 | 
            +
            j-nCvuPZoWo
         | 
| 2144 | 
            +
            j2WVRXdVu_4
         | 
| 2145 | 
            +
            j2k6EQOoRzU
         | 
| 2146 | 
            +
            j3BVnXHPjyw
         | 
| 2147 | 
            +
            j6FjjenQyko
         | 
| 2148 | 
            +
            j7LhySzyh7k
         | 
| 2149 | 
            +
            j7XDYxypFb0
         | 
| 2150 | 
            +
            j921XOqiQ7o
         | 
| 2151 | 
            +
            j9Q2J2MDctA
         | 
| 2152 | 
            +
            jA4WY877mTk
         | 
| 2153 | 
            +
            jBox8_bAoTM
         | 
| 2154 | 
            +
            jHVnt6VROM8
         | 
| 2155 | 
            +
            jLLVBH5ZZG0
         | 
| 2156 | 
            +
            jLRyB9Hz7U4
         | 
| 2157 | 
            +
            jNyPJ1LQmiA
         | 
| 2158 | 
            +
            jOj_NSDXMz0
         | 
| 2159 | 
            +
            jPxamG3f5TE
         | 
| 2160 | 
            +
            jTaFavHwbiI
         | 
| 2161 | 
            +
            jXqb7dbUBHs
         | 
| 2162 | 
            +
            jYEIkpTjpwI
         | 
| 2163 | 
            +
            jZa3FK_T_Z4
         | 
| 2164 | 
            +
            j_k1TZLK2mQ
         | 
| 2165 | 
            +
            jbzpyRmU3YA
         | 
| 2166 | 
            +
            jcFgCdlsPjI
         | 
| 2167 | 
            +
            jec9rBFqcwc
         | 
| 2168 | 
            +
            jfcrY85C_-k
         | 
| 2169 | 
            +
            jgT5X37XW3w
         | 
| 2170 | 
            +
            jhUnM7jekNo
         | 
| 2171 | 
            +
            jhaa9bIPuOY
         | 
| 2172 | 
            +
            jpAig_5u60Y
         | 
| 2173 | 
            +
            jv-dZw3ITJs
         | 
| 2174 | 
            +
            jvRleA3lWBw
         | 
| 2175 | 
            +
            jvr7UJI47UM
         | 
| 2176 | 
            +
            jwBi_Q9ffys
         | 
| 2177 | 
            +
            jwS75RtJJBc
         | 
| 2178 | 
            +
            jzbqbu-0bxc
         | 
| 2179 | 
            +
            k-pmfynqbko
         | 
| 2180 | 
            +
            k5QJ8s3qUyA
         | 
| 2181 | 
            +
            k6Hf0WGquNM
         | 
| 2182 | 
            +
            k9Kb4Pwu3ok
         | 
| 2183 | 
            +
            k9zYM3XqNps
         | 
| 2184 | 
            +
            kBLs0CsEWEg
         | 
| 2185 | 
            +
            kEQyvL6El-M
         | 
| 2186 | 
            +
            kHBSmEfwZZs
         | 
| 2187 | 
            +
            kLdPQfLv1g0
         | 
| 2188 | 
            +
            kM8iZqP4GDk
         | 
| 2189 | 
            +
            kPUqlB13Kn4
         | 
| 2190 | 
            +
            kQLhEtSx0NA
         | 
| 2191 | 
            +
            kYVd_HIkGw4
         | 
| 2192 | 
            +
            kYXiegTXsEs
         | 
| 2193 | 
            +
            kaBI3TvA7vA
         | 
| 2194 | 
            +
            kdIG_ZsrdUs
         | 
| 2195 | 
            +
            kdQPXCcV2K0
         | 
| 2196 | 
            +
            kdo0b2eiXVI
         | 
| 2197 | 
            +
            kfssQHnlHjM
         | 
| 2198 | 
            +
            khm7702744s
         | 
| 2199 | 
            +
            kl5eVK9kY_c
         | 
| 2200 | 
            +
            klh8JFoo4Og
         | 
| 2201 | 
            +
            kmTRmjeoKYA
         | 
| 2202 | 
            +
            kp33ZprO0Ck
         | 
| 2203 | 
            +
            kqFzRSwX3Fs
         | 
| 2204 | 
            +
            kqsmCUo3xEQ
         | 
| 2205 | 
            +
            kr5Ot5x8mmc
         | 
| 2206 | 
            +
            kvOzjIRylsM
         | 
| 2207 | 
            +
            kzgohxtf3hg
         | 
| 2208 | 
            +
            l1wHRYkFhZg
         | 
| 2209 | 
            +
            l29q7OxKMmM
         | 
| 2210 | 
            +
            l5bkGI-CGFI
         | 
| 2211 | 
            +
            l5hgKlBq2aE
         | 
| 2212 | 
            +
            l5tn1sJ0fKg
         | 
| 2213 | 
            +
            l6iQSCD9UeI
         | 
| 2214 | 
            +
            l7OIqpr56NY
         | 
| 2215 | 
            +
            l82uiWKCgF0
         | 
| 2216 | 
            +
            lAzL_47Wkbc
         | 
| 2217 | 
            +
            lB98olcaEm0
         | 
| 2218 | 
            +
            lClz0KqwrFU
         | 
| 2219 | 
            +
            lDJEC7OX6AE
         | 
| 2220 | 
            +
            lHakoK0j9qA
         | 
| 2221 | 
            +
            lIRpgkLK7r0
         | 
| 2222 | 
            +
            lJYwN2X7IbI
         | 
| 2223 | 
            +
            lK44daVVh2w
         | 
| 2224 | 
            +
            lM1Zmq0Lcd4
         | 
| 2225 | 
            +
            lOwZ3mwlenw
         | 
| 2226 | 
            +
            lSGfxPD4nR0
         | 
| 2227 | 
            +
            lZZgjJz-SEw
         | 
| 2228 | 
            +
            ldiJbsXZgvg
         | 
| 2229 | 
            +
            le3cBRlWSE8
         | 
| 2230 | 
            +
            lfrBVdmeUE0
         | 
| 2231 | 
            +
            lgWY-gjEYW0
         | 
| 2232 | 
            +
            lh_ZUt-O34Y
         | 
| 2233 | 
            +
            li7HdK2vIlw
         | 
| 2234 | 
            +
            liKbDWr0RzI
         | 
| 2235 | 
            +
            liVQZnSAv28
         | 
| 2236 | 
            +
            llj7LzTULog
         | 
| 2237 | 
            +
            losLXh9sDc8
         | 
| 2238 | 
            +
            lpShGGv6iJI
         | 
| 2239 | 
            +
            lqbSxAvUNpc
         | 
| 2240 | 
            +
            ltPAsp71rmI
         | 
| 2241 | 
            +
            lxBYJOEbU_g
         | 
| 2242 | 
            +
            lxE9lqRrcuo
         | 
| 2243 | 
            +
            lxQjwbUiM9w
         | 
| 2244 | 
            +
            lz1RY_CNWeU
         | 
| 2245 | 
            +
            lza-61vEfcw
         | 
| 2246 | 
            +
            lzniYTLmFkc
         | 
| 2247 | 
            +
            m03Bn3jgP48
         | 
| 2248 | 
            +
            m0EwquC6wBU
         | 
| 2249 | 
            +
            m0svbKxpLhI
         | 
| 2250 | 
            +
            m0ttpozYW14
         | 
| 2251 | 
            +
            m1lhGqNCZlA
         | 
| 2252 | 
            +
            m3ZogsjvmLA
         | 
| 2253 | 
            +
            m3q4bKFCkio
         | 
| 2254 | 
            +
            m3q7itlxq14
         | 
| 2255 | 
            +
            m4yEAVUxsFM
         | 
| 2256 | 
            +
            m5_41I_BLc8
         | 
| 2257 | 
            +
            m9qPsbp-l00
         | 
| 2258 | 
            +
            m9y0Kt9UFYc
         | 
| 2259 | 
            +
            mAUNqn8QAFU
         | 
| 2260 | 
            +
            mCghaYzVDxw
         | 
| 2261 | 
            +
            mD24h-bbdMU
         | 
| 2262 | 
            +
            mEP7QCH2oYc
         | 
| 2263 | 
            +
            mETDq4gwIkU
         | 
| 2264 | 
            +
            mFRkTyvuamE
         | 
| 2265 | 
            +
            mFu85lirRfw
         | 
| 2266 | 
            +
            mLTM_vEz1jU
         | 
| 2267 | 
            +
            mMiiyP2W-qQ
         | 
| 2268 | 
            +
            mQu-g8K7qtc
         | 
| 2269 | 
            +
            mQyL3LgJwXA
         | 
| 2270 | 
            +
            mRzqtElhGsY
         | 
| 2271 | 
            +
            mXBHUYIXQAU
         | 
| 2272 | 
            +
            mXNd6zUVwP0
         | 
| 2273 | 
            +
            m_D83abmA4Q
         | 
| 2274 | 
            +
            mbKfbtQvUgQ
         | 
| 2275 | 
            +
            mcZfJHqf4KY
         | 
| 2276 | 
            +
            meka3_pUVqc
         | 
| 2277 | 
            +
            mexPA0ocnnQ
         | 
| 2278 | 
            +
            mf8vuUJoNaI
         | 
| 2279 | 
            +
            mfuwTh61hMA
         | 
| 2280 | 
            +
            mfzWMIEVrFk
         | 
| 2281 | 
            +
            mg7CQGLjRzE
         | 
| 2282 | 
            +
            mhZJxmbSSt4
         | 
| 2283 | 
            +
            mhxEcl-85pM
         | 
| 2284 | 
            +
            miGwjQa0txo
         | 
| 2285 | 
            +
            mjI_IyzUye0
         | 
| 2286 | 
            +
            mp_aq18zg38
         | 
| 2287 | 
            +
            mqSucLmIFeg
         | 
| 2288 | 
            +
            mtXfzd53wRQ
         | 
| 2289 | 
            +
            mu1XN7ABANM
         | 
| 2290 | 
            +
            mw4GQ5jhL6g
         | 
| 2291 | 
            +
            myDLLgryIs8
         | 
| 2292 | 
            +
            myGaZRw-0oU
         | 
| 2293 | 
            +
            myaOG-5N12M
         | 
| 2294 | 
            +
            n-EpKQ6xIJs
         | 
| 2295 | 
            +
            n-Ptyqo4lE0
         | 
| 2296 | 
            +
            n-mmxFdva4w
         | 
| 2297 | 
            +
            n1WR4pPT1Jo
         | 
| 2298 | 
            +
            n7YJE14tLLQ
         | 
| 2299 | 
            +
            n7Z6KyTeouY
         | 
| 2300 | 
            +
            n9Gl1hBgjIU
         | 
| 2301 | 
            +
            nAyLvwIcnRc
         | 
| 2302 | 
            +
            nHEr8-LtfUo
         | 
| 2303 | 
            +
            nHU621TjCi0
         | 
| 2304 | 
            +
            nISa7ahsQVY
         | 
| 2305 | 
            +
            nMIE9IKTV6Y
         | 
| 2306 | 
            +
            nN4fDhAcGTM
         | 
| 2307 | 
            +
            nNgIi4eJduY
         | 
| 2308 | 
            +
            nNuk96Rw2Ks
         | 
| 2309 | 
            +
            nQeMM3bqM1M
         | 
| 2310 | 
            +
            nQgkkH-o-aE
         | 
| 2311 | 
            +
            nQmB8u7aBZs
         | 
| 2312 | 
            +
            nQpuGwWyFQ0
         | 
| 2313 | 
            +
            nSsQFG8QzcE
         | 
| 2314 | 
            +
            nWo--dSu9bs
         | 
| 2315 | 
            +
            nXcU8x_xK18
         | 
| 2316 | 
            +
            nZQ_jnOVFeU
         | 
| 2317 | 
            +
            n__HtO28X8M
         | 
| 2318 | 
            +
            naFR4znnS_0
         | 
| 2319 | 
            +
            ngdwHwnLCt8
         | 
| 2320 | 
            +
            niKRw8zeYa8
         | 
| 2321 | 
            +
            nihu7deKG9E
         | 
| 2322 | 
            +
            nj-YK3JJCIU
         | 
| 2323 | 
            +
            nkCgvEXj7FQ
         | 
| 2324 | 
            +
            nky_VSE43Hs
         | 
| 2325 | 
            +
            noYQhtNG-RA
         | 
| 2326 | 
            +
            nor0P6jwoeg
         | 
| 2327 | 
            +
            nsqOggafySQ
         | 
| 2328 | 
            +
            nsrEmJ_19v4
         | 
| 2329 | 
            +
            nu3p9JQ4ykM
         | 
| 2330 | 
            +
            nujU66hnemE
         | 
| 2331 | 
            +
            nvGGjCIIrm0
         | 
| 2332 | 
            +
            nwyoo3oYYpE
         | 
| 2333 | 
            +
            nxk8alj07sY
         | 
| 2334 | 
            +
            nyes4M2CbtI
         | 
| 2335 | 
            +
            nyxYzQVqo20
         | 
| 2336 | 
            +
            nyyS0FSztKc
         | 
| 2337 | 
            +
            o0lvhDX6DXc
         | 
| 2338 | 
            +
            o1zo4BYFdtU
         | 
| 2339 | 
            +
            o3z2CwnY_5M
         | 
| 2340 | 
            +
            o4R1-TLkxBs
         | 
| 2341 | 
            +
            o5q1ne_uNE0
         | 
| 2342 | 
            +
            o5ufkJMr24c
         | 
| 2343 | 
            +
            oBRZ8sD-OjE
         | 
| 2344 | 
            +
            oCM304tbwcM
         | 
| 2345 | 
            +
            oKC8ikzEFIA
         | 
| 2346 | 
            +
            oMbvC_siQyc
         | 
| 2347 | 
            +
            oNGKZrLIO0U
         | 
| 2348 | 
            +
            oOdNHtF_s5o
         | 
| 2349 | 
            +
            oRvkMz0FXtw
         | 
| 2350 | 
            +
            oSBD9lej7oA
         | 
| 2351 | 
            +
            oWVfSS5m5LY
         | 
| 2352 | 
            +
            oWqLRywhozk
         | 
| 2353 | 
            +
            oYKlQPSZr9A
         | 
| 2354 | 
            +
            o_EvSqIz1EE
         | 
| 2355 | 
            +
            oarLQY6VJzs
         | 
| 2356 | 
            +
            oe45d8WFc20
         | 
| 2357 | 
            +
            oe4VZ1YDL9Y
         | 
| 2358 | 
            +
            oeFSoHWiLBI
         | 
| 2359 | 
            +
            ofWA7ERRwzs
         | 
| 2360 | 
            +
            ogOqpmvv6eU
         | 
| 2361 | 
            +
            ol3tAxnNccY
         | 
| 2362 | 
            +
            om1FNUWg4yo
         | 
| 2363 | 
            +
            oo5gIrWn9tI
         | 
| 2364 | 
            +
            oonc4u-Adbc
         | 
| 2365 | 
            +
            oun9ZWMYYVQ
         | 
| 2366 | 
            +
            owZYdzNJSUo
         | 
| 2367 | 
            +
            owqMWjBPCW4
         | 
| 2368 | 
            +
            oxQHiGgFQ2A
         | 
| 2369 | 
            +
            oxsRS9fialY
         | 
| 2370 | 
            +
            p-xcYP1ef6M
         | 
| 2371 | 
            +
            p1lHlsF1LeM
         | 
| 2372 | 
            +
            p2tdlkmZ8D4
         | 
| 2373 | 
            +
            p4Q2mwsvlpQ
         | 
| 2374 | 
            +
            p9ijo4bNOJI
         | 
| 2375 | 
            +
            pBoDJqyONC4
         | 
| 2376 | 
            +
            pD8z8Dior4A
         | 
| 2377 | 
            +
            pD9cAOBZDj4
         | 
| 2378 | 
            +
            pDySXCjwXJg
         | 
| 2379 | 
            +
            pFXjD9J-JE0
         | 
| 2380 | 
            +
            pHgSyR3qUas
         | 
| 2381 | 
            +
            pI1feWHeUq4
         | 
| 2382 | 
            +
            pIeCH_unCd4
         | 
| 2383 | 
            +
            pJznoC1fZ_U
         | 
| 2384 | 
            +
            pKu6GJdrKOM
         | 
| 2385 | 
            +
            pL3u5ztU9kA
         | 
| 2386 | 
            +
            pOBuggPY9_c
         | 
| 2387 | 
            +
            pQ4C6LaLV48
         | 
| 2388 | 
            +
            pQMiwYP8mq0
         | 
| 2389 | 
            +
            pQcXM9HJXjs
         | 
| 2390 | 
            +
            pRm187D8-MQ
         | 
| 2391 | 
            +
            pSeYDrDjV48
         | 
| 2392 | 
            +
            pUayltZ4PRk
         | 
| 2393 | 
            +
            pXg1P_wX79Q
         | 
| 2394 | 
            +
            pZ3OMf01xJs
         | 
| 2395 | 
            +
            pb85Bw9sHY0
         | 
| 2396 | 
            +
            pcOdWPkjUzY
         | 
| 2397 | 
            +
            peYcx-xDiwg
         | 
| 2398 | 
            +
            pfC0yuJtMc0
         | 
| 2399 | 
            +
            phnXyHYku8k
         | 
| 2400 | 
            +
            pidRKmq2iGI
         | 
| 2401 | 
            +
            pk5WuA39qzc
         | 
| 2402 | 
            +
            pkSnKgRHjU8
         | 
| 2403 | 
            +
            pnmOhTbhKhc
         | 
| 2404 | 
            +
            po-Dx2CgFGs
         | 
| 2405 | 
            +
            pp71BH0UlvE
         | 
| 2406 | 
            +
            ppPbjVv2XeQ
         | 
| 2407 | 
            +
            pru-95YczT4
         | 
| 2408 | 
            +
            psfAc33Ok94
         | 
| 2409 | 
            +
            puDuigN0_I8
         | 
| 2410 | 
            +
            puZZoKkv2Nk
         | 
| 2411 | 
            +
            pujqknUWycM
         | 
| 2412 | 
            +
            px-H1yOAQUo
         | 
| 2413 | 
            +
            pzIQGk5nWDw
         | 
| 2414 | 
            +
            pzev9CB3vuM
         | 
| 2415 | 
            +
            q-abd-Tjf_g
         | 
| 2416 | 
            +
            q0whherUIeo
         | 
| 2417 | 
            +
            q1NTjsXYpK0
         | 
| 2418 | 
            +
            q1SYOXJWXNg
         | 
| 2419 | 
            +
            q2S5mFVGVec
         | 
| 2420 | 
            +
            q3kU8MyAHhE
         | 
| 2421 | 
            +
            q3zhx8M7mgI
         | 
| 2422 | 
            +
            q5uELNh_Fro
         | 
| 2423 | 
            +
            q6irtmJxniE
         | 
| 2424 | 
            +
            q7Pfap5IRMc
         | 
| 2425 | 
            +
            q7qZd-5PQec
         | 
| 2426 | 
            +
            q8G-VO3gy5o
         | 
| 2427 | 
            +
            q8PoT8bhElc
         | 
| 2428 | 
            +
            qDzY7_qAP9E
         | 
| 2429 | 
            +
            qEHexC4KaLA
         | 
| 2430 | 
            +
            qGl8JMXmwL0
         | 
| 2431 | 
            +
            qH8uMr3qb_M
         | 
| 2432 | 
            +
            qKMd70Jr-ws
         | 
| 2433 | 
            +
            qKnrUrYLlj0
         | 
| 2434 | 
            +
            qLciglFWSBY
         | 
| 2435 | 
            +
            qLxgp5VIx4A
         | 
| 2436 | 
            +
            qLyCi_ARgfM
         | 
| 2437 | 
            +
            qMoypa93-_M
         | 
| 2438 | 
            +
            qMroyKN05zQ
         | 
| 2439 | 
            +
            qOxbcVscVuQ
         | 
| 2440 | 
            +
            qRiBE2DuGA4
         | 
| 2441 | 
            +
            qTPgNaT-IyY
         | 
| 2442 | 
            +
            qUbu1hTOKQQ
         | 
| 2443 | 
            +
            qWd6VN9sseU
         | 
| 2444 | 
            +
            qXBgNj7d2aI
         | 
| 2445 | 
            +
            qYW_VBZoTsM
         | 
| 2446 | 
            +
            qZdAl2dAL7k
         | 
| 2447 | 
            +
            q_EJdzfnPSg
         | 
| 2448 | 
            +
            qatNSkb_O3Y
         | 
| 2449 | 
            +
            qav1y7G15JQ
         | 
| 2450 | 
            +
            qb4Kx1MoxGQ
         | 
| 2451 | 
            +
            qbaocv8MUJI
         | 
| 2452 | 
            +
            qckQShckJI0
         | 
| 2453 | 
            +
            qfKmOf3d0fc
         | 
| 2454 | 
            +
            qj63Fyah8Jw
         | 
| 2455 | 
            +
            qmwgjonregk
         | 
| 2456 | 
            +
            qnQhGZNOIzE
         | 
| 2457 | 
            +
            qnRbz82xzWk
         | 
| 2458 | 
            +
            qnboyP15mi8
         | 
| 2459 | 
            +
            qo_ZzjhbWLk
         | 
| 2460 | 
            +
            qrmmPQC6o4I
         | 
| 2461 | 
            +
            qsOjHdZtUM4
         | 
| 2462 | 
            +
            qwMVYILJ7bc
         | 
| 2463 | 
            +
            qxabzkWQ744
         | 
| 2464 | 
            +
            r0i10UvjWBY
         | 
| 2465 | 
            +
            r28QlaYxRDY
         | 
| 2466 | 
            +
            r2REC5k-2AE
         | 
| 2467 | 
            +
            r2vFxIWtQ-E
         | 
| 2468 | 
            +
            r341ehyHft4
         | 
| 2469 | 
            +
            r40wnEAEozQ
         | 
| 2470 | 
            +
            r4yqeuWlJqM
         | 
| 2471 | 
            +
            r59GRI81jQU
         | 
| 2472 | 
            +
            r6xt8HZy1-k
         | 
| 2473 | 
            +
            r7vzgexzXOk
         | 
| 2474 | 
            +
            rA2g4mWai58
         | 
| 2475 | 
            +
            rA4jmcefefQ
         | 
| 2476 | 
            +
            rAnvXFlvV3M
         | 
| 2477 | 
            +
            rEJBmcJlEy0
         | 
| 2478 | 
            +
            rFEg1iwdHBM
         | 
| 2479 | 
            +
            rFOs4b_WTYY
         | 
| 2480 | 
            +
            rGBU08IrdrI
         | 
| 2481 | 
            +
            rGqAwF16IOk
         | 
| 2482 | 
            +
            rHZlSM-m_Xo
         | 
| 2483 | 
            +
            rHgcNbOwnas
         | 
| 2484 | 
            +
            rI8ccs3k0kE
         | 
| 2485 | 
            +
            rJXB9VhK1eM
         | 
| 2486 | 
            +
            rJc0Pf2B7Mg
         | 
| 2487 | 
            +
            rKCT1mmxfb0
         | 
| 2488 | 
            +
            rKvnvavLhKg
         | 
| 2489 | 
            +
            rLUoN3LY6Fk
         | 
| 2490 | 
            +
            rLnNaewOAbY
         | 
| 2491 | 
            +
            rNOyRIU9WUk
         | 
| 2492 | 
            +
            rNqiDGKZiZE
         | 
| 2493 | 
            +
            rPa_Q-v7iPU
         | 
| 2494 | 
            +
            rRexKBeW-LY
         | 
| 2495 | 
            +
            rRsjDRqRvgA
         | 
| 2496 | 
            +
            rS8oFARouuA
         | 
| 2497 | 
            +
            rTgVxBHEKJY
         | 
| 2498 | 
            +
            rWMEyWjaDug
         | 
| 2499 | 
            +
            rZ5iulZ3rvk
         | 
| 2500 | 
            +
            rc744Z9IjhY
         | 
| 2501 | 
            +
            rcdFlgadpYQ
         | 
| 2502 | 
            +
            rfzHohoFoZc
         | 
| 2503 | 
            +
            rgj6AQ0KiXI
         | 
| 2504 | 
            +
            rhFDM4YtAjM
         | 
| 2505 | 
            +
            rizm_pzU7xo
         | 
| 2506 | 
            +
            rjjFQ6onAJM
         | 
| 2507 | 
            +
            rjlNd5leBDY
         | 
| 2508 | 
            +
            rl4qZtDSLCs
         | 
| 2509 | 
            +
            rl6K4-2q4JI
         | 
| 2510 | 
            +
            rnzWJv_L13Y
         | 
| 2511 | 
            +
            rpC49dRxPkM
         | 
| 2512 | 
            +
            rqqgH8fMsOs
         | 
| 2513 | 
            +
            rrzJQMo6QQ4
         | 
| 2514 | 
            +
            ruAnF4N_8y4
         | 
| 2515 | 
            +
            rw0AUfItOss
         | 
| 2516 | 
            +
            ryJxN-ZRAGk
         | 
| 2517 | 
            +
            rztwo4iUnqo
         | 
| 2518 | 
            +
            s1QCigF6JOg
         | 
| 2519 | 
            +
            s2Ya_pPoKQw
         | 
| 2520 | 
            +
            s322l02OzWM
         | 
| 2521 | 
            +
            s4b9dN-X32Q
         | 
| 2522 | 
            +
            s5eZtpsX2Uw
         | 
| 2523 | 
            +
            s6LlkCsQSq0
         | 
| 2524 | 
            +
            s8i4K8MvQjg
         | 
| 2525 | 
            +
            s9aNVQP9Bi8
         | 
| 2526 | 
            +
            s9zkSyuL8eQ
         | 
| 2527 | 
            +
            sCk_3RNWdZI
         | 
| 2528 | 
            +
            sEnf_XAMuso
         | 
| 2529 | 
            +
            sGvmS07G46I
         | 
| 2530 | 
            +
            sIesHZHrHck
         | 
| 2531 | 
            +
            sJIvQ5imN20
         | 
| 2532 | 
            +
            sK-QPNTRj24
         | 
| 2533 | 
            +
            sKFiaAcqTMY
         | 
| 2534 | 
            +
            sKRcy61BFfM
         | 
| 2535 | 
            +
            sNHDCXNLLlw
         | 
| 2536 | 
            +
            sS7O_qMN_pM
         | 
| 2537 | 
            +
            sSrSorPjUvU
         | 
| 2538 | 
            +
            sTKAL3OfgSQ
         | 
| 2539 | 
            +
            s_A2wZB7ZfA
         | 
| 2540 | 
            +
            s_gSNpE1Z5Y
         | 
| 2541 | 
            +
            sb7TL-252e0
         | 
| 2542 | 
            +
            sboMcBqlShY
         | 
| 2543 | 
            +
            sdeLg0on1Go
         | 
| 2544 | 
            +
            sdnbXzi5yDQ
         | 
| 2545 | 
            +
            sebF4SCrhgY
         | 
| 2546 | 
            +
            sgGPHfZ6O00
         | 
| 2547 | 
            +
            sgRTFPJ1MdE
         | 
| 2548 | 
            +
            shkbyqqkkTA
         | 
| 2549 | 
            +
            si4zS_Jx_uY
         | 
| 2550 | 
            +
            skyd1JiJiYs
         | 
| 2551 | 
            +
            slAdtDXiNgI
         | 
| 2552 | 
            +
            sp4yAT08rqw
         | 
| 2553 | 
            +
            sphx939ru4U
         | 
| 2554 | 
            +
            spi7TCSQqns
         | 
| 2555 | 
            +
            sqseuym5HKI
         | 
| 2556 | 
            +
            ssHyZRRz6ek
         | 
| 2557 | 
            +
            stqdcOSqbnI
         | 
| 2558 | 
            +
            suK34prc56o
         | 
| 2559 | 
            +
            swP3fNDUD0M
         | 
| 2560 | 
            +
            sy-JNEKRe6w
         | 
| 2561 | 
            +
            t-N3In2rLI4
         | 
| 2562 | 
            +
            t1hyNFQq1Qc
         | 
| 2563 | 
            +
            t1ok0e9gTRo
         | 
| 2564 | 
            +
            t3SPY13b64M
         | 
| 2565 | 
            +
            t43zNbKooJs
         | 
| 2566 | 
            +
            t4xtn8b1Nk0
         | 
| 2567 | 
            +
            t7caALtdVBM
         | 
| 2568 | 
            +
            t7f-iQf3PRA
         | 
| 2569 | 
            +
            t9nyOewqrU0
         | 
| 2570 | 
            +
            tAbhaguKARw
         | 
| 2571 | 
            +
            tBvd7OSDGgQ
         | 
| 2572 | 
            +
            tC0vzGbKXWs
         | 
| 2573 | 
            +
            tCskNV4zvIA
         | 
| 2574 | 
            +
            tDNEWvgVQU8
         | 
| 2575 | 
            +
            tE9_u7slTrc
         | 
| 2576 | 
            +
            tFHxf3tCRr4
         | 
| 2577 | 
            +
            tGQgcHMIq1g
         | 
| 2578 | 
            +
            tHGLoklGaE0
         | 
| 2579 | 
            +
            tIjr1ZMPEkc
         | 
| 2580 | 
            +
            tMTZDgGaWqE
         | 
| 2581 | 
            +
            tPX6j_22umA
         | 
| 2582 | 
            +
            tQRaArBTpu0
         | 
| 2583 | 
            +
            tRBf2g6XqCU
         | 
| 2584 | 
            +
            tSUX6HReL6o
         | 
| 2585 | 
            +
            tSf72G2vTU8
         | 
| 2586 | 
            +
            tTyFNcuR8dw
         | 
| 2587 | 
            +
            tUPzZFsH9NM
         | 
| 2588 | 
            +
            tXwwOXxj3Wk
         | 
| 2589 | 
            +
            tYS3l-lh39Q
         | 
| 2590 | 
            +
            tZMO74qrrJk
         | 
| 2591 | 
            +
            tZZyNqO9bQ0
         | 
| 2592 | 
            +
            tZzyiJC7pqs
         | 
| 2593 | 
            +
            teIlbfF2SE0
         | 
| 2594 | 
            +
            tgKPxj4-0QE
         | 
| 2595 | 
            +
            thhRZXvb0fE
         | 
| 2596 | 
            +
            tj46eMPD8jw
         | 
| 2597 | 
            +
            tj79bCk8Y7E
         | 
| 2598 | 
            +
            tlPIi5sLOoI
         | 
| 2599 | 
            +
            tlSl7JSQ35w
         | 
| 2600 | 
            +
            tm50929wbaA
         | 
| 2601 | 
            +
            tmAx6umELmU
         | 
| 2602 | 
            +
            tnX_ibkICWk
         | 
| 2603 | 
            +
            tng9I_Yfhg8
         | 
| 2604 | 
            +
            trGNjNAxMMA
         | 
| 2605 | 
            +
            tssS0XyUIi0
         | 
| 2606 | 
            +
            tsxCu5Fom2A
         | 
| 2607 | 
            +
            tu3g6qTyWiU
         | 
| 2608 | 
            +
            tvsBIX44mQM
         | 
| 2609 | 
            +
            tygH_zAKRvc
         | 
| 2610 | 
            +
            u2gB0EGQxxA
         | 
| 2611 | 
            +
            u5TYUHIGqzA
         | 
| 2612 | 
            +
            u5eti_-WK9g
         | 
| 2613 | 
            +
            u61kdTMLJTQ
         | 
| 2614 | 
            +
            u7bLXr675gw
         | 
| 2615 | 
            +
            u8B3lvaw9tw
         | 
| 2616 | 
            +
            u9QPtZEhH3o
         | 
| 2617 | 
            +
            uAWBQI7PVKA
         | 
| 2618 | 
            +
            uAkCPrihEzQ
         | 
| 2619 | 
            +
            uAsqM8rL8GA
         | 
| 2620 | 
            +
            uB9UEkO77MU
         | 
| 2621 | 
            +
            uCQMZfnM-a4
         | 
| 2622 | 
            +
            uGUee74VHAc
         | 
| 2623 | 
            +
            uHmQzfPWBG0
         | 
| 2624 | 
            +
            uK0u0BHCF3s
         | 
| 2625 | 
            +
            uKbvq15Pjw8
         | 
| 2626 | 
            +
            uLycRSuHSAs
         | 
| 2627 | 
            +
            uM9zA0QAvhA
         | 
| 2628 | 
            +
            uOWT7-wqKS4
         | 
| 2629 | 
            +
            uQ2I4dZh9O4
         | 
| 2630 | 
            +
            uQEUqgEVQvU
         | 
| 2631 | 
            +
            uQz8Y_jYzy0
         | 
| 2632 | 
            +
            uSs1HeOShlY
         | 
| 2633 | 
            +
            uTUY9W-eDZk
         | 
| 2634 | 
            +
            uW6e50NYlWE
         | 
| 2635 | 
            +
            uZEfW4QJot0
         | 
| 2636 | 
            +
            ufnnbfJSZ3M
         | 
| 2637 | 
            +
            ulMrIHCeLQU
         | 
| 2638 | 
            +
            un5l34RRYR4
         | 
| 2639 | 
            +
            uomUPcl17N8
         | 
| 2640 | 
            +
            upw774ewNjg
         | 
| 2641 | 
            +
            uqCecnqjL1g
         | 
| 2642 | 
            +
            uqav8KWIBPM
         | 
| 2643 | 
            +
            uvNun-YAzwk
         | 
| 2644 | 
            +
            uwJtuNmBb90
         | 
| 2645 | 
            +
            uxBzmTylbwg
         | 
| 2646 | 
            +
            uxQbWbWVWug
         | 
| 2647 | 
            +
            uxy82zQnQpo
         | 
| 2648 | 
            +
            v-2yFMzxqwU
         | 
| 2649 | 
            +
            v1DXBLkiqFM
         | 
| 2650 | 
            +
            v1RFw8FpEJQ
         | 
| 2651 | 
            +
            v1wFRiV9_v4
         | 
| 2652 | 
            +
            v2DjHVhnjQI
         | 
| 2653 | 
            +
            v2_u0yV5ua0
         | 
| 2654 | 
            +
            v5vIyfkumj0
         | 
| 2655 | 
            +
            v62wDFbK7iM
         | 
| 2656 | 
            +
            v7-eoymQp3o
         | 
| 2657 | 
            +
            v79U6LcewMc
         | 
| 2658 | 
            +
            v7iWP-4rYg4
         | 
| 2659 | 
            +
            v8R4spPNofA
         | 
| 2660 | 
            +
            vC-uE8RAzbo
         | 
| 2661 | 
            +
            vC9i_jB5h1k
         | 
| 2662 | 
            +
            vKHi1XtBPQE
         | 
| 2663 | 
            +
            vLb2GXb-bsE
         | 
| 2664 | 
            +
            vM39qhXle4g
         | 
| 2665 | 
            +
            vO87PpdQKV4
         | 
| 2666 | 
            +
            vOFoltimf5o
         | 
| 2667 | 
            +
            vQtLms02PFM
         | 
| 2668 | 
            +
            vT4z4TCf4uk
         | 
| 2669 | 
            +
            vTKx76zG23U
         | 
| 2670 | 
            +
            vXPaPV2Ii-Y
         | 
| 2671 | 
            +
            v_bumG-g0Dc
         | 
| 2672 | 
            +
            vblot9RiULI
         | 
| 2673 | 
            +
            vcL75ICzL0w
         | 
| 2674 | 
            +
            vf4CrrsnVWs
         | 
| 2675 | 
            +
            vhZqXOG9Sfo
         | 
| 2676 | 
            +
            vi9kXfl4Nzo
         | 
| 2677 | 
            +
            vjjNnix_rGQ
         | 
| 2678 | 
            +
            vlddfDNoCS8
         | 
| 2679 | 
            +
            vmGW-kulgy8
         | 
| 2680 | 
            +
            vmhYHtGvqCI
         | 
| 2681 | 
            +
            vmtEmebxSwo
         | 
| 2682 | 
            +
            vpAyvSQdqvU
         | 
| 2683 | 
            +
            vqqv18miTHs
         | 
| 2684 | 
            +
            vsrK3zDsT4c
         | 
| 2685 | 
            +
            vt6evh25rpY
         | 
| 2686 | 
            +
            vtBXhiKZjWk
         | 
| 2687 | 
            +
            vuHbp02YfKA
         | 
| 2688 | 
            +
            vuThpe-Rgxs
         | 
| 2689 | 
            +
            vueMpDhosM8
         | 
| 2690 | 
            +
            vviufcserks
         | 
| 2691 | 
            +
            vwuBZEo9eAE
         | 
| 2692 | 
            +
            vyUiZfxuXXk
         | 
| 2693 | 
            +
            vyWMhZ-NiHg
         | 
| 2694 | 
            +
            vyrHk4_-epU
         | 
| 2695 | 
            +
            w09mGrJy_h8
         | 
| 2696 | 
            +
            w0ztlIAYTCU
         | 
| 2697 | 
            +
            w4ZSe355UKY
         | 
| 2698 | 
            +
            w4fzfZkZ2Ng
         | 
| 2699 | 
            +
            w7zqBnrLxiw
         | 
| 2700 | 
            +
            w9V5LKdTPRY
         | 
| 2701 | 
            +
            w9rXlL5iJNk
         | 
| 2702 | 
            +
            wAaHY_SXdgY
         | 
| 2703 | 
            +
            wB1IOUjeiXU
         | 
| 2704 | 
            +
            wB5lKhN4uoY
         | 
| 2705 | 
            +
            wD-jLNmRVfw
         | 
| 2706 | 
            +
            wDT446J2XME
         | 
| 2707 | 
            +
            wF17z_DX7DA
         | 
| 2708 | 
            +
            wFS3088FEUk
         | 
| 2709 | 
            +
            wFkig7Vh8YU
         | 
| 2710 | 
            +
            wHJB9u61btI
         | 
| 2711 | 
            +
            wJKn7xElol8
         | 
| 2712 | 
            +
            wKnbAj-2Hnw
         | 
| 2713 | 
            +
            wLvCU_o362k
         | 
| 2714 | 
            +
            wN-xfvQKBgc
         | 
| 2715 | 
            +
            wNcTvkR4u8s
         | 
| 2716 | 
            +
            wRQGTMig_P8
         | 
| 2717 | 
            +
            wSDR6ymotHk
         | 
| 2718 | 
            +
            wSO5y2Vq8Ss
         | 
| 2719 | 
            +
            wTHo7j8Ruww
         | 
| 2720 | 
            +
            wTYpjp9Bzrs
         | 
| 2721 | 
            +
            wUnPxBv2h1E
         | 
| 2722 | 
            +
            wV7TB-8PyhU
         | 
| 2723 | 
            +
            wVnhS8BuE4U
         | 
| 2724 | 
            +
            w_Ms7re3lYU
         | 
| 2725 | 
            +
            waHHFLAet8A
         | 
| 2726 | 
            +
            wbokl5PhXEg
         | 
| 2727 | 
            +
            wfCZYvqVFKM
         | 
| 2728 | 
            +
            whbyuy2nHBg
         | 
| 2729 | 
            +
            wkYeYfLt8P4
         | 
| 2730 | 
            +
            wm9QvbgryRg
         | 
| 2731 | 
            +
            wmKPIm2HuXM
         | 
| 2732 | 
            +
            wnH9X7Y8-fw
         | 
| 2733 | 
            +
            wonfEPTNA0w
         | 
| 2734 | 
            +
            wrtkQSU_Ekc
         | 
| 2735 | 
            +
            wrtrwY2caSI
         | 
| 2736 | 
            +
            wwBfqXf-1Xg
         | 
| 2737 | 
            +
            wxNELCR-TMk
         | 
| 2738 | 
            +
            wyM-7ra8uY4
         | 
| 2739 | 
            +
            wz3TSWrZVjM
         | 
| 2740 | 
            +
            x-YG6j9ZYsY
         | 
| 2741 | 
            +
            x-ty9x6-P1o
         | 
| 2742 | 
            +
            x1HMmnAI5sc
         | 
| 2743 | 
            +
            x2Sh6TOWjkM
         | 
| 2744 | 
            +
            x47V2e-4NmY
         | 
| 2745 | 
            +
            x7jZG8cbqBI
         | 
| 2746 | 
            +
            x8LIzP4vBrQ
         | 
| 2747 | 
            +
            x8jdx-lf2Dw
         | 
| 2748 | 
            +
            x99gUDpak34
         | 
| 2749 | 
            +
            xCDQAlQfzNs
         | 
| 2750 | 
            +
            xD1mRhx68eE
         | 
| 2751 | 
            +
            xFFs9UgOAlE
         | 
| 2752 | 
            +
            xGoCF5bk56A
         | 
| 2753 | 
            +
            xITRYnvl0oc
         | 
| 2754 | 
            +
            xIyfkI0jJMs
         | 
| 2755 | 
            +
            xJUlD1q4bRw
         | 
| 2756 | 
            +
            xL32w7DMwHM
         | 
| 2757 | 
            +
            xLSzvPQpo5A
         | 
| 2758 | 
            +
            xMhd22uQusw
         | 
| 2759 | 
            +
            xSaGl8fiiYk
         | 
| 2760 | 
            +
            xVuZZS93qtc
         | 
| 2761 | 
            +
            xWrJD9-1o44
         | 
| 2762 | 
            +
            xZ0Xdew--H4
         | 
| 2763 | 
            +
            x_0F7lFtPRY
         | 
| 2764 | 
            +
            xe21-4hVA20
         | 
| 2765 | 
            +
            xfXkzZ62y8g
         | 
| 2766 | 
            +
            xgpgHZ9iTMo
         | 
| 2767 | 
            +
            xjwSr2qv1cY
         | 
| 2768 | 
            +
            xkf9Gk1QuYo
         | 
| 2769 | 
            +
            xmXiws6G8Mc
         | 
| 2770 | 
            +
            xnLoToJVQH4
         | 
| 2771 | 
            +
            xog_GEISGDE
         | 
| 2772 | 
            +
            xokbf-np33Q
         | 
| 2773 | 
            +
            xt7bRz9dX4A
         | 
| 2774 | 
            +
            xuVTCXSW6WM
         | 
| 2775 | 
            +
            xz7Ilex4McU
         | 
| 2776 | 
            +
            y0jwPOra9Jg
         | 
| 2777 | 
            +
            y2tCX54cDx4
         | 
| 2778 | 
            +
            y5yxjABbdVQ
         | 
| 2779 | 
            +
            y6Dh74INR_I
         | 
| 2780 | 
            +
            y6Ge4RZsq4I
         | 
| 2781 | 
            +
            y6zsW14YDBY
         | 
| 2782 | 
            +
            y7bKFMO0d-w
         | 
| 2783 | 
            +
            y9L5dA7pQxk
         | 
| 2784 | 
            +
            yAe2kgW47G0
         | 
| 2785 | 
            +
            yBEfb0XnMec
         | 
| 2786 | 
            +
            yF8dBlsLn6k
         | 
| 2787 | 
            +
            yHaY_d3QQR8
         | 
| 2788 | 
            +
            yLkqI2UiZJU
         | 
| 2789 | 
            +
            yMSj47Xs2_g
         | 
| 2790 | 
            +
            yPqieOw41gc
         | 
| 2791 | 
            +
            yRV2bb-tRMk
         | 
| 2792 | 
            +
            yV6ZXGQDFfo
         | 
| 2793 | 
            +
            yWJDUISGUp4
         | 
| 2794 | 
            +
            yX5g1OHKE-E
         | 
| 2795 | 
            +
            yXRXk5ubwW8
         | 
| 2796 | 
            +
            yXhj9XnXpbI
         | 
| 2797 | 
            +
            yXrJCyJBugg
         | 
| 2798 | 
            +
            yY9QkbpDLaE
         | 
| 2799 | 
            +
            yZ6vSn7PaPI
         | 
| 2800 | 
            +
            y_-a5D-1_mE
         | 
| 2801 | 
            +
            ya8cSGAiEyw
         | 
| 2802 | 
            +
            yc0wPSjL8rc
         | 
| 2803 | 
            +
            yc3l8Xsk4k4
         | 
| 2804 | 
            +
            yeVl67bOTD4
         | 
| 2805 | 
            +
            yew316-hSiM
         | 
| 2806 | 
            +
            yg49p-i94rM
         | 
| 2807 | 
            +
            yjD-_z6P75s
         | 
| 2808 | 
            +
            yn_0j3hDnPI
         | 
| 2809 | 
            +
            yqCnnSfXrRg
         | 
| 2810 | 
            +
            yrqpVREbHfs
         | 
| 2811 | 
            +
            ysCHqf1HfEQ
         | 
| 2812 | 
            +
            ysogiWIjy10
         | 
| 2813 | 
            +
            yu2iuSrpjHo
         | 
| 2814 | 
            +
            yu6gBfUQFNI
         | 
| 2815 | 
            +
            yuGOVGNkjAA
         | 
| 2816 | 
            +
            yuNg5JugqrE
         | 
| 2817 | 
            +
            yumyfeToWyg
         | 
| 2818 | 
            +
            yvGUNb80FTI
         | 
| 2819 | 
            +
            yvWV56LXTh8
         | 
| 2820 | 
            +
            yvcUoZqSvbk
         | 
| 2821 | 
            +
            yw--rqjGfI8
         | 
| 2822 | 
            +
            ywljr9RKExQ
         | 
| 2823 | 
            +
            yxPk1s6kjls
         | 
| 2824 | 
            +
            yxuTqbqzzpM
         | 
| 2825 | 
            +
            yz4H6fx15Uk
         | 
| 2826 | 
            +
            z-KziTO_5so
         | 
| 2827 | 
            +
            z2-YMvHXvkk
         | 
| 2828 | 
            +
            z6kC2r9UrF8
         | 
| 2829 | 
            +
            z83CZnYt72o
         | 
| 2830 | 
            +
            z8X4DB-ecWM
         | 
| 2831 | 
            +
            z8gNQpsYIco
         | 
| 2832 | 
            +
            z93Kr9LmMCo
         | 
| 2833 | 
            +
            zArkP0YCXw0
         | 
| 2834 | 
            +
            zESeeaFDVSw
         | 
| 2835 | 
            +
            zF-pekRLJ3M
         | 
| 2836 | 
            +
            zF9VM-voMFQ
         | 
| 2837 | 
            +
            zJIKjeOLOFw
         | 
| 2838 | 
            +
            zJahR4BmskA
         | 
| 2839 | 
            +
            zJsr4Tie-tk
         | 
| 2840 | 
            +
            zJuuBn8mTP8
         | 
| 2841 | 
            +
            zKkJB8Etq54
         | 
| 2842 | 
            +
            zKwgR9IBovs
         | 
| 2843 | 
            +
            zL_d7b1bsUE
         | 
| 2844 | 
            +
            zLaE0SmZdMo
         | 
| 2845 | 
            +
            zQpGf1gPY7M
         | 
| 2846 | 
            +
            zUDEten_j9o
         | 
| 2847 | 
            +
            zUkN2ILNflA
         | 
| 2848 | 
            +
            zYYWeXjQn8M
         | 
| 2849 | 
            +
            zZb8HVaO4Nc
         | 
| 2850 | 
            +
            z_cAYz0Q5DI
         | 
| 2851 | 
            +
            zb8B-vxmjTg
         | 
| 2852 | 
            +
            zdIcTkGHFac
         | 
| 2853 | 
            +
            zeO8n9byqg0
         | 
| 2854 | 
            +
            zesVY6sbjoM
         | 
| 2855 | 
            +
            zgs82z9t7Mw
         | 
| 2856 | 
            +
            zhESYHHbzsc
         | 
| 2857 | 
            +
            zhI__xPhoW4
         | 
| 2858 | 
            +
            zhzlGFKXV2g
         | 
| 2859 | 
            +
            zjnOeTL7Bz8
         | 
| 2860 | 
            +
            zlHe6erNcQA
         | 
| 2861 | 
            +
            zmn50KVgQak
         | 
| 2862 | 
            +
            zotrHY6f1-4
         | 
| 2863 | 
            +
            zpRuDsk_0vk
         | 
| 2864 | 
            +
            zqFEtAUGItg
         | 
| 2865 | 
            +
            zqVaXf-E8us
         | 
| 2866 | 
            +
            zucFlVCiV-g
         | 
| 2867 | 
            +
            zuk7TtRuR-U
         | 
| 2868 | 
            +
            zwGcVuZCM4Y
         | 
| 2869 | 
            +
            zxN1HYq4iEg
         | 
| 2870 | 
            +
            zygTUJZ93dE
         | 
| 2871 | 
            +
            zzQoGtjkKuU
         | 
| 2872 | 
            +
            zzpYxy7lveg
         | 
    	
        TalkingHead-1KH/data_list/train_video_tubes.txt
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:86b9a6514dc4abdc9484c5fa93a3ad5db3c5ecb965181e92d16b9fd95ff8222a
         | 
| 3 | 
            +
            size 29153463
         | 
    	
        TalkingHead-1KH/data_list/val_video_ids.txt
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            1lSejjfNHpw
         | 
| 2 | 
            +
            2Xu56MEC91w
         | 
| 3 | 
            +
            3y6Vjr45I34
         | 
| 4 | 
            +
            4hQi42Q9mcY
         | 
| 5 | 
            +
            5crEV5DbRyc
         | 
| 6 | 
            +
            85UEFVcmIjI
         | 
| 7 | 
            +
            A2800grpOzU
         | 
| 8 | 
            +
            c1DRo3tPDG4
         | 
| 9 | 
            +
            d_7s4huYOD4
         | 
| 10 | 
            +
            EGGsK7po68c
         | 
| 11 | 
            +
            eKFlMKp9Gs0
         | 
| 12 | 
            +
            EWKJprUrnPE
         | 
| 13 | 
            +
            gp4fg9PWuhM
         | 
| 14 | 
            +
            HBlkinewdHM
         | 
| 15 | 
            +
            jpCrKYWjYD8
         | 
| 16 | 
            +
            jxi_Cjc8T1w
         | 
| 17 | 
            +
            kMXhWN71Ar0
         | 
| 18 | 
            +
            m2ZmZflLryo
         | 
| 19 | 
            +
            npEcenV-Y08
         | 
| 20 | 
            +
            nUe3F8jYoZo
         | 
| 21 | 
            +
            NXpWIephX1o
         | 
| 22 | 
            +
            PAaWZTFRP9Q
         | 
| 23 | 
            +
            SmtJ5Cy4jCM
         | 
| 24 | 
            +
            SU8NSkuBkb0
         | 
| 25 | 
            +
            VkKnOEQlwl4
         | 
| 26 | 
            +
            WigprYZPaLc
         | 
| 27 | 
            +
            YsrzvkG5_KI
         | 
| 28 | 
            +
            Zel-zag38mQ
         | 
    	
        TalkingHead-1KH/data_list/val_video_tubes.txt
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            1lSejjfNHpw_0075, 1080, 1920, 0, 728, 671, 47, 1471, 847
         | 
| 2 | 
            +
            1lSejjfNHpw_0075, 1080, 1920, 728, 1456, 671, 47, 1471, 847
         | 
| 3 | 
            +
            2Xu56MEC91w_0046, 1080, 1920, 80, 1105, 586, 86, 1314, 814
         | 
| 4 | 
            +
            3y6Vjr45I34_0004, 1080, 1920, 287, 1254, 568, 0, 1464, 896
         | 
| 5 | 
            +
            4hQi42Q9mcY_0002, 1080, 1920, 0, 605, 443, 0, 1515, 992
         | 
| 6 | 
            +
            4hQi42Q9mcY_0002, 1080, 1920, 605, 1209, 443, 0, 1515, 992
         | 
| 7 | 
            +
            5crEV5DbRyc_0009, 1080, 1920, 208, 1152, 1058, 102, 1712, 756
         | 
| 8 | 
            +
            85UEFVcmIjI_0014, 1080, 1920, 92, 627, 558, 134, 1294, 870
         | 
| 9 | 
            +
            85UEFVcmIjI_0014, 1080, 1920, 627, 1162, 558, 134, 1294, 870
         | 
| 10 | 
            +
            A2800grpOzU_0002, 1080, 1920, 812, 1407, 227, 7, 1139, 919
         | 
| 11 | 
            +
            EGGsK7po68c_0007, 1080, 1920, 0, 1024, 786, 50, 1598, 862
         | 
| 12 | 
            +
            EWKJprUrnPE_0005, 1080, 1920, 0, 1024, 84, 168, 702, 786
         | 
| 13 | 
            +
            HBlkinewdHM_0000, 1080, 1920, 319, 1344, 807, 149, 1347, 689
         | 
| 14 | 
            +
            NXpWIephX1o_0031, 1080, 1920, 0, 632, 357, 0, 1493, 1072
         | 
| 15 | 
            +
            NXpWIephX1o_0031, 1080, 1920, 632, 1264, 357, 0, 1493, 1072
         | 
| 16 | 
            +
            PAaWZTFRP9Q_0001, 1080, 1920, 0, 672, 624, 42, 1376, 794
         | 
| 17 | 
            +
            PAaWZTFRP9Q_0001, 1080, 1920, 926, 1425, 696, 101, 1464, 869
         | 
| 18 | 
            +
            SU8NSkuBkb0_0015, 1080, 1920, 826, 1397, 347, 69, 1099, 821
         | 
| 19 | 
            +
            SmtJ5Cy4jCM_0006, 1080, 1920, 0, 523, 524, 50, 1388, 914
         | 
| 20 | 
            +
            SmtJ5Cy4jCM_0006, 1080, 1920, 546, 1134, 477, 42, 1357, 922
         | 
| 21 | 
            +
            VkKnOEQlwl4_0010, 1080, 1920, 98, 818, 821, 22, 1733, 934
         | 
| 22 | 
            +
            VkKnOEQlwl4_0010, 1080, 1920, 818, 1537, 821, 22, 1733, 934
         | 
| 23 | 
            +
            WigprYZPaLc_0002, 1080, 1920, 234, 877, 802, 25, 1490, 713
         | 
| 24 | 
            +
            WigprYZPaLc_0002, 1080, 1920, 877, 1519, 802, 25, 1490, 713
         | 
| 25 | 
            +
            YsrzvkG5_KI_0018, 1080, 1920, 36, 1061, 591, 100, 1055, 564
         | 
| 26 | 
            +
            Zel-zag38mQ_0001, 1080, 1920, 0, 733, 591, 12, 1439, 860
         | 
| 27 | 
            +
            Zel-zag38mQ_0001, 1080, 1920, 733, 1466, 591, 12, 1439, 860
         | 
| 28 | 
            +
            c1DRo3tPDG4_0010, 1080, 1920, 0, 865, 432, 33, 1264, 865
         | 
| 29 | 
            +
            c1DRo3tPDG4_0010, 1080, 1920, 865, 1730, 432, 33, 1264, 865
         | 
| 30 | 
            +
            eKFlMKp9Gs0_0005, 1080, 1920, 0, 1024, 705, 118, 1249, 662
         | 
| 31 | 
            +
            gp4fg9PWuhM_0003, 1080, 1920, 0, 858, 526, 0, 1310, 768
         | 
| 32 | 
            +
            jpCrKYWjYD8_0002, 1080, 1920, 0, 768, 527, 68, 1215, 756
         | 
| 33 | 
            +
            jpCrKYWjYD8_0002, 1080, 1920, 768, 1535, 527, 68, 1215, 756
         | 
| 34 | 
            +
            jxi_Cjc8T1w_0061, 1080, 1920, 0, 1024, 660, 102, 1286, 728
         | 
| 35 | 
            +
            kMXhWN71Ar0_0001, 1080, 1920, 0, 656, 60, 0, 940, 832
         | 
| 36 | 
            +
            kMXhWN71Ar0_0001, 1080, 1920, 656, 1311, 60, 0, 940, 832
         | 
| 37 | 
            +
            m2ZmZflLryo_0009, 1080, 1920, 0, 1024, 678, 51, 1390, 763
         | 
| 38 | 
            +
            npEcenV-Y08_0011, 1080, 1920, 99, 1087, 625, 69, 1425, 869
         | 
    	
        TalkingHead-1KH/requirements.txt
    ADDED
    
    | @@ -0,0 +1,4 @@ | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            ffmpeg-python
         | 
| 2 | 
            +
            imageio
         | 
| 3 | 
            +
            git+https://github.com/nficano/pytube
         | 
| 4 | 
            +
            tqdm
         | 
    	
        TalkingHead-1KH/teaser.gif
    ADDED
    
    |   | 
| Git LFS Details
 | 
    	
        TalkingHead-1KH/videos_crop.py
    ADDED
    
    | @@ -0,0 +1,79 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # This script is licensed under the MIT License.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            import argparse
         | 
| 6 | 
            +
            import multiprocessing as mp
         | 
| 7 | 
            +
            import os
         | 
| 8 | 
            +
            from functools import partial
         | 
| 9 | 
            +
            from time import time as timer
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            import ffmpeg
         | 
| 12 | 
            +
            from tqdm import tqdm
         | 
| 13 | 
            +
             | 
| 14 | 
            +
             | 
| 15 | 
            +
            parser = argparse.ArgumentParser()
         | 
| 16 | 
            +
            parser.add_argument('--input_dir', type=str, required=True,
         | 
| 17 | 
            +
                                help='Dir containing youtube clips.')
         | 
| 18 | 
            +
            parser.add_argument('--clip_info_file', type=str, required=True,
         | 
| 19 | 
            +
                                help='File containing clip information.')
         | 
| 20 | 
            +
            parser.add_argument('--output_dir', type=str, required=True,
         | 
| 21 | 
            +
                                help='Location to dump outputs.')
         | 
| 22 | 
            +
            parser.add_argument('--num_workers', type=int, default=8,
         | 
| 23 | 
            +
                                help='How many multiprocessing workers?')
         | 
| 24 | 
            +
            args = parser.parse_args()
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            def get_h_w(filepath):
         | 
| 28 | 
            +
                probe = ffmpeg.probe(filepath)
         | 
| 29 | 
            +
                video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
         | 
| 30 | 
            +
                height = int(video_stream['height'])
         | 
| 31 | 
            +
                width = int(video_stream['width'])
         | 
| 32 | 
            +
                return height, width
         | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
            def trim_and_crop(input_dir, output_dir, clip_params):
         | 
| 36 | 
            +
                video_name, H, W, S, E, L, T, R, B = clip_params.strip().split(',')
         | 
| 37 | 
            +
                H, W, S, E, L, T, R, B = int(H), int(W), int(S), int(E), int(L), int(T), int(R), int(B)
         | 
| 38 | 
            +
                output_filename = '{}_S{}_E{}_L{}_T{}_R{}_B{}.mp4'.format(video_name, S, E, L, T, R, B)
         | 
| 39 | 
            +
                output_filepath = os.path.join(output_dir, output_filename)
         | 
| 40 | 
            +
                if os.path.exists(output_filepath):
         | 
| 41 | 
            +
                    print('Output file %s exists, skipping' % (output_filepath))
         | 
| 42 | 
            +
                    return
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                input_filepath = os.path.join(input_dir, video_name + '.mp4')
         | 
| 45 | 
            +
                if not os.path.exists(input_filepath):
         | 
| 46 | 
            +
                    print('Input file %s does not exist, skipping' % (input_filepath))
         | 
| 47 | 
            +
                    return
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                h, w = get_h_w(input_filepath)
         | 
| 50 | 
            +
                t = int(T / H * h)
         | 
| 51 | 
            +
                b = int(B / H * h)
         | 
| 52 | 
            +
                l = int(L / W * w)
         | 
| 53 | 
            +
                r = int(R / W * w)
         | 
| 54 | 
            +
                stream = ffmpeg.input(input_filepath)
         | 
| 55 | 
            +
                stream = ffmpeg.trim(stream, start_frame=S, end_frame=E+1)
         | 
| 56 | 
            +
                stream = ffmpeg.crop(stream, l, t, r-l, b-t)
         | 
| 57 | 
            +
                stream = ffmpeg.output(stream, output_filepath)
         | 
| 58 | 
            +
                ffmpeg.run(stream)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
             | 
| 61 | 
            +
            if __name__ == '__main__':
         | 
| 62 | 
            +
                # Read list of videos.
         | 
| 63 | 
            +
                clip_info = []
         | 
| 64 | 
            +
                with open(args.clip_info_file) as fin:
         | 
| 65 | 
            +
                    for line in fin:
         | 
| 66 | 
            +
                        clip_info.append(line.strip())
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                # Create output folder.
         | 
| 69 | 
            +
                os.makedirs(args.output_dir, exist_ok=True)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                # Download videos.
         | 
| 72 | 
            +
                downloader = partial(trim_and_crop, args.input_dir, args.output_dir)
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                start = timer()
         | 
| 75 | 
            +
                pool_size = args.num_workers
         | 
| 76 | 
            +
                print('Using pool size of %d' % (pool_size))
         | 
| 77 | 
            +
                with mp.Pool(processes=pool_size) as p:
         | 
| 78 | 
            +
                    _ = list(tqdm(p.imap_unordered(downloader, clip_info), total=len(clip_info)))
         | 
| 79 | 
            +
                print('Elapsed time: %.2f' % (timer() - start))
         | 
    	
        TalkingHead-1KH/videos_download.py
    ADDED
    
    | @@ -0,0 +1,56 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import argparse
         | 
| 2 | 
            +
            import multiprocessing as mp
         | 
| 3 | 
            +
            import os
         | 
| 4 | 
            +
            from functools import partial
         | 
| 5 | 
            +
            from time import time as timer
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from pytube import YouTube
         | 
| 8 | 
            +
            from tqdm import tqdm
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            parser = argparse.ArgumentParser()
         | 
| 11 | 
            +
            parser.add_argument('--input_list', type=str, required=True,
         | 
| 12 | 
            +
                                help='List of youtube video ids')
         | 
| 13 | 
            +
            parser.add_argument('--output_dir', type=str, default='data/youtube_videos',
         | 
| 14 | 
            +
                                help='Location to download videos')
         | 
| 15 | 
            +
            parser.add_argument('--num_workers', type=int, default=8,
         | 
| 16 | 
            +
                                help='How many multiprocessing workers?')
         | 
| 17 | 
            +
            args = parser.parse_args()
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 | 
            +
            def download_video(output_dir, video_id):
         | 
| 21 | 
            +
                r"""Download video."""
         | 
| 22 | 
            +
                video_path = '%s/%s.mp4' % (output_dir, video_id)
         | 
| 23 | 
            +
                if not os.path.isfile(video_path):
         | 
| 24 | 
            +
                    try:
         | 
| 25 | 
            +
                        # Download the highest quality mp4 stream.
         | 
| 26 | 
            +
                        yt = YouTube('https://www.youtube.com/watch?v=%s' % (video_id))
         | 
| 27 | 
            +
                        stream = yt.streams.filter(subtype='mp4', only_video=True, adaptive=True).first()
         | 
| 28 | 
            +
                        if stream is None:
         | 
| 29 | 
            +
                            stream = yt.streams.filter(subtype='mp4').first()
         | 
| 30 | 
            +
                        stream.download(output_path=output_dir, filename=video_id + '.mp4')
         | 
| 31 | 
            +
                    except Exception as e:
         | 
| 32 | 
            +
                        print(e)
         | 
| 33 | 
            +
                        print('Failed to download %s' % (video_id))
         | 
| 34 | 
            +
                else:
         | 
| 35 | 
            +
                    print('File exists: %s' % (video_id))
         | 
| 36 | 
            +
             | 
| 37 | 
            +
             | 
| 38 | 
            +
            if __name__ == '__main__':
         | 
| 39 | 
            +
                # Read list of videos.
         | 
| 40 | 
            +
                video_ids = []
         | 
| 41 | 
            +
                with open(args.input_list) as fin:
         | 
| 42 | 
            +
                    for line in fin:
         | 
| 43 | 
            +
                        video_ids.append(line.strip())
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                # Create output folder.
         | 
| 46 | 
            +
                os.makedirs(args.output_dir, exist_ok=True)
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                # Download videos.
         | 
| 49 | 
            +
                downloader = partial(download_video, args.output_dir)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                start = timer()
         | 
| 52 | 
            +
                pool_size = args.num_workers
         | 
| 53 | 
            +
                print('Using pool size of %d' % (pool_size))
         | 
| 54 | 
            +
                with mp.Pool(processes=pool_size) as p:
         | 
| 55 | 
            +
                    _ = list(tqdm(p.imap_unordered(downloader, video_ids), total=len(video_ids)))
         | 
| 56 | 
            +
                print('Elapsed time: %.2f' % (timer() - start))
         | 
    	
        TalkingHead-1KH/videos_download_and_crop.sh
    ADDED
    
    | @@ -0,0 +1,10 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            dataset=$1
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Download the videos.
         | 
| 4 | 
            +
            python videos_download.py --input_list data_list/${dataset}_video_ids.txt --output_dir ${dataset}/raw_videos
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Split the videos into 1-min chunks.
         | 
| 7 | 
            +
            ./videos_split.sh ${dataset}/raw_videos ${dataset}/1min_clips
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # Extract the talking head clips.
         | 
| 10 | 
            +
            python videos_crop.py --input_dir ${dataset}/1min_clips/ --output_dir ${dataset}/cropped_clips --clip_info_file data_list/${dataset}_video_tubes.txt
         | 
    	
        TalkingHead-1KH/videos_split.sh
    ADDED
    
    | @@ -0,0 +1,11 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            #!/bin/bash
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            in_dir=$1
         | 
| 4 | 
            +
            out_dir=$2
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            mkdir $out_dir;
         | 
| 7 | 
            +
            for f in $in_dir/*.mp4
         | 
| 8 | 
            +
            do
         | 
| 9 | 
            +
              y=${f##*/};
         | 
| 10 | 
            +
              ffmpeg -i $f -c copy -map 0 -segment_time 00:01:00 -f segment $out_dir/${y/.mp4}_%04d.mp4;
         | 
| 11 | 
            +
            done
         | 
    	
        checkpoints/.gitkeep
    ADDED
    
    | 
            File without changes
         | 
    	
        data_gen/eg3d/convert_to_eg3d_convention.py
    ADDED
    
    | @@ -0,0 +1,146 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import numpy as np
         | 
| 2 | 
            +
            import torch
         | 
| 3 | 
            +
            import copy
         | 
| 4 | 
            +
            from utils.commons.tensor_utils import convert_to_tensor, convert_to_np
         | 
| 5 | 
            +
            from deep_3drecon.deep_3drecon_models.bfm import ParametricFaceModel
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            def _fix_intrinsics(intrinsics):
         | 
| 9 | 
            +
                """
         | 
| 10 | 
            +
                intrinsics: [3,3], not batch-wise
         | 
| 11 | 
            +
                """
         | 
| 12 | 
            +
                # unnormalized                                normalized
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # [[ f_x, s=0,    x_0]             [[ f_x/size_x,   s=0,            x_0/size_x=0.5]
         | 
| 15 | 
            +
                #  [ 0,   f_y,  y_0]      ->      [ 0,            f_y/size_y,   y_0/size_y=0.5]
         | 
| 16 | 
            +
                #  [ 0,   0,    1  ]]             [ 0,            0,            1         ]]
         | 
| 17 | 
            +
                intrinsics = np.array(intrinsics).copy()
         | 
| 18 | 
            +
                assert intrinsics.shape == (3, 3), intrinsics
         | 
| 19 | 
            +
                intrinsics[0,0] = 2985.29/700
         | 
| 20 | 
            +
                intrinsics[1,1] = 2985.29/700
         | 
| 21 | 
            +
                intrinsics[0,2] = 1/2
         | 
| 22 | 
            +
                intrinsics[1,2] = 1/2
         | 
| 23 | 
            +
                assert intrinsics[0,1] == 0
         | 
| 24 | 
            +
                assert intrinsics[2,2] == 1
         | 
| 25 | 
            +
                assert intrinsics[1,0] == 0
         | 
| 26 | 
            +
                assert intrinsics[2,0] == 0
         | 
| 27 | 
            +
                assert intrinsics[2,1] == 0
         | 
| 28 | 
            +
                return intrinsics
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            # Used in original submission
         | 
| 31 | 
            +
            def _fix_pose_orig(pose):
         | 
| 32 | 
            +
                """
         | 
| 33 | 
            +
                pose: [4,4], not batch-wise
         | 
| 34 | 
            +
                """
         | 
| 35 | 
            +
                pose = np.array(pose).copy()
         | 
| 36 | 
            +
                location = pose[:3, 3]
         | 
| 37 | 
            +
                radius = np.linalg.norm(location)
         | 
| 38 | 
            +
                pose[:3, 3] = pose[:3, 3]/radius * 2.7
         | 
| 39 | 
            +
                return pose
         | 
| 40 | 
            +
             | 
| 41 | 
            +
             | 
| 42 | 
            +
            def get_eg3d_convention_camera_pose_intrinsic(item):
         | 
| 43 | 
            +
                """
         | 
| 44 | 
            +
                item: a dict during binarize
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                """
         | 
| 47 | 
            +
                if item['euler'].ndim == 1:
         | 
| 48 | 
            +
                    angle = convert_to_tensor(copy.copy(item['euler']))
         | 
| 49 | 
            +
                    trans = copy.deepcopy(item['trans'])
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    # handle the difference of euler axis between eg3d and ours
         | 
| 52 | 
            +
                    # see data_gen/process_ffhq_for_eg3d/transplant_eg3d_ckpt_into_our_convention.ipynb
         | 
| 53 | 
            +
                    # angle += torch.tensor([0, 3.1415926535, 3.1415926535], device=angle.device)
         | 
| 54 | 
            +
                    R = ParametricFaceModel.compute_rotation(angle.unsqueeze(0))[0].cpu().numpy()
         | 
| 55 | 
            +
                    trans[2] += -10
         | 
| 56 | 
            +
                    c = -np.dot(R, trans)
         | 
| 57 | 
            +
                    pose = np.eye(4)
         | 
| 58 | 
            +
                    pose[:3,:3] = R
         | 
| 59 | 
            +
                    c *= 0.27 # normalize camera radius
         | 
| 60 | 
            +
                    c[1] += 0.006 # additional offset used in submission
         | 
| 61 | 
            +
                    c[2] += 0.161 # additional offset used in submission
         | 
| 62 | 
            +
                    pose[0,3] = c[0]
         | 
| 63 | 
            +
                    pose[1,3] = c[1]
         | 
| 64 | 
            +
                    pose[2,3] = c[2]
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    focal = 2985.29 # = 1015*1024/224*(300/466.285),
         | 
| 67 | 
            +
                    # todo: 如果修改了fit 3dmm阶段的camera intrinsic,这里也要跟着改
         | 
| 68 | 
            +
                    pp = 512#112
         | 
| 69 | 
            +
                    w = 1024#224
         | 
| 70 | 
            +
                    h = 1024#224
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    K = np.eye(3)
         | 
| 73 | 
            +
                    K[0][0] = focal
         | 
| 74 | 
            +
                    K[1][1] = focal
         | 
| 75 | 
            +
                    K[0][2] = w/2.0
         | 
| 76 | 
            +
                    K[1][2] = h/2.0
         | 
| 77 | 
            +
                    convention_K = _fix_intrinsics(K)
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    Rot = np.eye(3)
         | 
| 80 | 
            +
                    Rot[0, 0] = 1
         | 
| 81 | 
            +
                    Rot[1, 1] = -1
         | 
| 82 | 
            +
                    Rot[2, 2] = -1        
         | 
| 83 | 
            +
                    pose[:3, :3] = np.dot(pose[:3, :3], Rot) # permute axes
         | 
| 84 | 
            +
                    convention_pose = _fix_pose_orig(pose)
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    item['c2w'] = pose
         | 
| 87 | 
            +
                    item['convention_c2w'] = convention_pose
         | 
| 88 | 
            +
                    item['intrinsics'] = convention_K
         | 
| 89 | 
            +
                    return item
         | 
| 90 | 
            +
                else:
         | 
| 91 | 
            +
                    num_samples = len(item['euler'])
         | 
| 92 | 
            +
                    eulers_all = convert_to_tensor(copy.deepcopy(item['euler'])) # [B, 3]
         | 
| 93 | 
            +
                    trans_all = copy.deepcopy(item['trans']) # [B, 3]
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    # handle the difference of euler axis between eg3d and ours
         | 
| 96 | 
            +
                    # see data_gen/process_ffhq_for_eg3d/transplant_eg3d_ckpt_into_our_convention.ipynb
         | 
| 97 | 
            +
                    # eulers_all += torch.tensor([0, 3.1415926535, 3.1415926535], device=eulers_all.device).unsqueeze(0).repeat([eulers_all.shape[0],1])
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    intrinsics = []
         | 
| 100 | 
            +
                    poses = []
         | 
| 101 | 
            +
                    convention_poses = []
         | 
| 102 | 
            +
                    for i in range(num_samples):
         | 
| 103 | 
            +
                        angle = eulers_all[i]
         | 
| 104 | 
            +
                        trans = trans_all[i]
         | 
| 105 | 
            +
                        R = ParametricFaceModel.compute_rotation(angle.unsqueeze(0))[0].cpu().numpy()
         | 
| 106 | 
            +
                        trans[2] += -10
         | 
| 107 | 
            +
                        c = -np.dot(R, trans)
         | 
| 108 | 
            +
                        pose = np.eye(4)
         | 
| 109 | 
            +
                        pose[:3,:3] = R
         | 
| 110 | 
            +
                        c *= 0.27 # normalize camera radius
         | 
| 111 | 
            +
                        c[1] += 0.006 # additional offset used in submission
         | 
| 112 | 
            +
                        c[2] += 0.161 # additional offset used in submission
         | 
| 113 | 
            +
                        pose[0,3] = c[0]
         | 
| 114 | 
            +
                        pose[1,3] = c[1]
         | 
| 115 | 
            +
                        pose[2,3] = c[2]
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                        focal = 2985.29 # = 1015*1024/224*(300/466.285),
         | 
| 118 | 
            +
                        # todo: 如果修改了fit 3dmm阶段的camera intrinsic,这里也要跟着改
         | 
| 119 | 
            +
                        pp = 512#112
         | 
| 120 | 
            +
                        w = 1024#224
         | 
| 121 | 
            +
                        h = 1024#224
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                        K = np.eye(3)
         | 
| 124 | 
            +
                        K[0][0] = focal
         | 
| 125 | 
            +
                        K[1][1] = focal
         | 
| 126 | 
            +
                        K[0][2] = w/2.0
         | 
| 127 | 
            +
                        K[1][2] = h/2.0
         | 
| 128 | 
            +
                        convention_K = _fix_intrinsics(K)
         | 
| 129 | 
            +
                        intrinsics.append(convention_K)
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                        Rot = np.eye(3)
         | 
| 132 | 
            +
                        Rot[0, 0] = 1
         | 
| 133 | 
            +
                        Rot[1, 1] = -1
         | 
| 134 | 
            +
                        Rot[2, 2] = -1        
         | 
| 135 | 
            +
                        pose[:3, :3] = np.dot(pose[:3, :3], Rot)
         | 
| 136 | 
            +
                        convention_pose = _fix_pose_orig(pose)
         | 
| 137 | 
            +
                        convention_poses.append(convention_pose)
         | 
| 138 | 
            +
                        poses.append(pose)
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                    intrinsics = np.stack(intrinsics) # [B, 3, 3]
         | 
| 141 | 
            +
                    poses = np.stack(poses) # [B, 4, 4]
         | 
| 142 | 
            +
                    convention_poses = np.stack(convention_poses) # [B, 4, 4]
         | 
| 143 | 
            +
                    item['intrinsics'] = intrinsics
         | 
| 144 | 
            +
                    item['c2w'] = poses
         | 
| 145 | 
            +
                    item['convention_c2w'] = convention_poses
         | 
| 146 | 
            +
                    return item
         | 
    	
        data_gen/runs/binarizer_nerf.py
    ADDED
    
    | @@ -0,0 +1,335 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            import numpy as np
         | 
| 3 | 
            +
            import math
         | 
| 4 | 
            +
            import json
         | 
| 5 | 
            +
            import imageio
         | 
| 6 | 
            +
            import torch
         | 
| 7 | 
            +
            import tqdm
         | 
| 8 | 
            +
            import cv2
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            from data_util.face3d_helper import Face3DHelper
         | 
| 11 | 
            +
            from utils.commons.euler2rot import euler_trans_2_c2w, c2w_to_euler_trans
         | 
| 12 | 
            +
            from data_gen.utils.process_video.euler2quaterion import euler2quaterion, quaterion2euler
         | 
| 13 | 
            +
            from deep_3drecon.deep_3drecon_models.bfm import ParametricFaceModel
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             | 
| 16 | 
            +
            def euler2rot(euler_angle):
         | 
| 17 | 
            +
                batch_size = euler_angle.shape[0]
         | 
| 18 | 
            +
                theta = euler_angle[:, 0].reshape(-1, 1, 1)
         | 
| 19 | 
            +
                phi = euler_angle[:, 1].reshape(-1, 1, 1)
         | 
| 20 | 
            +
                psi = euler_angle[:, 2].reshape(-1, 1, 1)
         | 
| 21 | 
            +
                one = torch.ones(batch_size, 1, 1).to(euler_angle.device)
         | 
| 22 | 
            +
                zero = torch.zeros(batch_size, 1, 1).to(euler_angle.device)
         | 
| 23 | 
            +
                rot_x = torch.cat((
         | 
| 24 | 
            +
                    torch.cat((one, zero, zero), 1),
         | 
| 25 | 
            +
                    torch.cat((zero, theta.cos(), theta.sin()), 1),
         | 
| 26 | 
            +
                    torch.cat((zero, -theta.sin(), theta.cos()), 1),
         | 
| 27 | 
            +
                ), 2)
         | 
| 28 | 
            +
                rot_y = torch.cat((
         | 
| 29 | 
            +
                    torch.cat((phi.cos(), zero, -phi.sin()), 1),
         | 
| 30 | 
            +
                    torch.cat((zero, one, zero), 1),
         | 
| 31 | 
            +
                    torch.cat((phi.sin(), zero, phi.cos()), 1),
         | 
| 32 | 
            +
                ), 2)
         | 
| 33 | 
            +
                rot_z = torch.cat((
         | 
| 34 | 
            +
                    torch.cat((psi.cos(), -psi.sin(), zero), 1),
         | 
| 35 | 
            +
                    torch.cat((psi.sin(), psi.cos(), zero), 1),
         | 
| 36 | 
            +
                    torch.cat((zero, zero, one), 1)
         | 
| 37 | 
            +
                ), 2)
         | 
| 38 | 
            +
                return torch.bmm(rot_x, torch.bmm(rot_y, rot_z))
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
            def rot2euler(rot_mat):
         | 
| 42 | 
            +
                batch_size = len(rot_mat)
         | 
| 43 | 
            +
                # we assert that y in in [-0.5pi, 0.5pi]
         | 
| 44 | 
            +
                cos_y = torch.sqrt(rot_mat[:, 1, 2] * rot_mat[:, 1, 2] + rot_mat[:, 2, 2] * rot_mat[:, 2, 2])
         | 
| 45 | 
            +
                theta_x = torch.atan2(-rot_mat[:, 1, 2], rot_mat[:, 2, 2])
         | 
| 46 | 
            +
                theta_y = torch.atan2(rot_mat[:, 2, 0], cos_y)
         | 
| 47 | 
            +
                theta_z = torch.atan2(rot_mat[:, 0, 1], rot_mat[:, 0, 0])
         | 
| 48 | 
            +
                euler_angles = torch.zeros([batch_size, 3])
         | 
| 49 | 
            +
                euler_angles[:, 0] = theta_x
         | 
| 50 | 
            +
                euler_angles[:, 1] = theta_y
         | 
| 51 | 
            +
                euler_angles[:, 2] = theta_z
         | 
| 52 | 
            +
                return euler_angles
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            index_lm68_from_lm468 = [127,234,93,132,58,136,150,176,152,400,379,365,288,361,323,454,356,70,63,105,66,107,336,296,334,293,300,168,197,5,4,75,97,2,326,305,
         | 
| 55 | 
            +
                                     33,160,158,133,153,144,362,385,387,263,373,380,61,40,37,0,267,270,291,321,314,17,84,91,78,81,13,311,308,402,14,178]
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            def plot_lm2d(lm2d):
         | 
| 58 | 
            +
                WH = 512
         | 
| 59 | 
            +
                img = np.ones([WH, WH, 3], dtype=np.uint8) * 255
         | 
| 60 | 
            +
                
         | 
| 61 | 
            +
                for i in range(len(lm2d)):
         | 
| 62 | 
            +
                    x, y = lm2d[i]
         | 
| 63 | 
            +
                    color = (255,0,0)
         | 
| 64 | 
            +
                    img = cv2.circle(img, center=(int(x),int(y)), radius=3, color=color, thickness=-1)
         | 
| 65 | 
            +
                    font = cv2.FONT_HERSHEY_SIMPLEX
         | 
| 66 | 
            +
                for i in range(len(lm2d)):
         | 
| 67 | 
            +
                    x, y = lm2d[i]
         | 
| 68 | 
            +
                    img = cv2.putText(img, f"{i}", org=(int(x),int(y)), fontFace=font, fontScale=0.3, color=(255,0,0))
         | 
| 69 | 
            +
                return img
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            def get_face_rect(lms, h, w):
         | 
| 72 | 
            +
                """
         | 
| 73 | 
            +
                lms: [68, 2]
         | 
| 74 | 
            +
                h, w: int
         | 
| 75 | 
            +
                return: [4,]
         | 
| 76 | 
            +
                """
         | 
| 77 | 
            +
                assert len(lms) == 68
         | 
| 78 | 
            +
                # min_x, max_x = np.min(lms, 0)[0], np.max(lms, 0)[0]
         | 
| 79 | 
            +
                min_x, max_x = np.min(lms[:, 0]), np.max(lms[:, 0])
         | 
| 80 | 
            +
                cx = int((min_x+max_x)/2.0)
         | 
| 81 | 
            +
                cy = int(lms[27, 1])
         | 
| 82 | 
            +
                h_w = int((max_x-cx)*1.5)
         | 
| 83 | 
            +
                h_h = int((lms[8, 1]-cy)*1.15)
         | 
| 84 | 
            +
                rect_x = cx - h_w
         | 
| 85 | 
            +
                rect_y = cy - h_h
         | 
| 86 | 
            +
                if rect_x < 0:
         | 
| 87 | 
            +
                    rect_x = 0
         | 
| 88 | 
            +
                if rect_y < 0:
         | 
| 89 | 
            +
                    rect_y = 0
         | 
| 90 | 
            +
                rect_w = min(w-1-rect_x, 2*h_w)
         | 
| 91 | 
            +
                rect_h = min(h-1-rect_y, 2*h_h)
         | 
| 92 | 
            +
                # rect = np.array((rect_x, rect_y, rect_w, rect_h), dtype=np.int32)
         | 
| 93 | 
            +
                # rect = [rect_x, rect_y, rect_w, rect_h]
         | 
| 94 | 
            +
                rect = [rect_x, rect_x + rect_w, rect_y, rect_y + rect_h] # min_j,  max_j, min_i, max_i
         | 
| 95 | 
            +
                return rect # this x is width, y is height
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            def get_lip_rect(lms, h, w):
         | 
| 98 | 
            +
                """
         | 
| 99 | 
            +
                lms: [68, 2]
         | 
| 100 | 
            +
                h, w: int
         | 
| 101 | 
            +
                return: [4,]
         | 
| 102 | 
            +
                """
         | 
| 103 | 
            +
                # this x is width, y is height
         | 
| 104 | 
            +
                # for lms, lms[:, 0] is width, lms[:, 1] is height
         | 
| 105 | 
            +
                assert len(lms) == 68
         | 
| 106 | 
            +
                lips = slice(48, 60)
         | 
| 107 | 
            +
                lms = lms[lips]
         | 
| 108 | 
            +
                min_x, max_x = np.min(lms[:, 0]), np.max(lms[:, 0])
         | 
| 109 | 
            +
                min_y, max_y = np.min(lms[:, 1]), np.max(lms[:, 1])
         | 
| 110 | 
            +
                cx = int((min_x+max_x)/2.0)
         | 
| 111 | 
            +
                cy = int((min_y+max_y)/2.0)
         | 
| 112 | 
            +
                h_w = int((max_x-cx)*1.2)
         | 
| 113 | 
            +
                h_h = int((max_y-cy)*1.2)
         | 
| 114 | 
            +
                
         | 
| 115 | 
            +
                h_w = max(h_w, h_h)
         | 
| 116 | 
            +
                h_h = h_w
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                rect_x = cx - h_w
         | 
| 119 | 
            +
                rect_y = cy - h_h
         | 
| 120 | 
            +
                rect_w = 2*h_w
         | 
| 121 | 
            +
                rect_h = 2*h_h
         | 
| 122 | 
            +
                if rect_x < 0:
         | 
| 123 | 
            +
                    rect_x = 0
         | 
| 124 | 
            +
                if rect_y < 0:
         | 
| 125 | 
            +
                    rect_y = 0
         | 
| 126 | 
            +
                
         | 
| 127 | 
            +
                if rect_x + rect_w > w:
         | 
| 128 | 
            +
                    rect_x = w - rect_w
         | 
| 129 | 
            +
                if rect_y + rect_h > h:
         | 
| 130 | 
            +
                    rect_y = h - rect_h
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                rect = [rect_x, rect_x + rect_w, rect_y, rect_y + rect_h] # min_j,  max_j, min_i, max_i
         | 
| 133 | 
            +
                return rect # this x is width, y is height
         | 
| 134 | 
            +
             | 
| 135 | 
            +
             | 
| 136 | 
            +
            # def get_lip_rect(lms, h, w):
         | 
| 137 | 
            +
            #     """
         | 
| 138 | 
            +
            #     lms: [68, 2]
         | 
| 139 | 
            +
            #     h, w: int
         | 
| 140 | 
            +
            #     return: [4,]
         | 
| 141 | 
            +
            #     """
         | 
| 142 | 
            +
            #     assert len(lms) == 68
         | 
| 143 | 
            +
            #     lips = slice(48, 60)
         | 
| 144 | 
            +
            #     # this x is width, y is height
         | 
| 145 | 
            +
            #     xmin, xmax = int(lms[lips, 1].min()), int(lms[lips, 1].max())
         | 
| 146 | 
            +
            #     ymin, ymax = int(lms[lips, 0].min()), int(lms[lips, 0].max())
         | 
| 147 | 
            +
            #     # padding to H == W
         | 
| 148 | 
            +
            #     cx = (xmin + xmax) // 2
         | 
| 149 | 
            +
            #     cy = (ymin + ymax) // 2
         | 
| 150 | 
            +
            #     l = max(xmax - xmin, ymax - ymin) // 2
         | 
| 151 | 
            +
            #     xmin = max(0, cx - l)
         | 
| 152 | 
            +
            #     xmax = min(h, cx + l)
         | 
| 153 | 
            +
            #     ymin = max(0, cy - l)
         | 
| 154 | 
            +
            #     ymax = min(w, cy + l)
         | 
| 155 | 
            +
            #     lip_rect = [xmin, xmax, ymin, ymax]
         | 
| 156 | 
            +
            #     return lip_rect
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            def get_win_conds(conds, idx, smo_win_size=8, pad_option='zero'):
         | 
| 159 | 
            +
                """
         | 
| 160 | 
            +
                conds: [b, t=16, h=29]
         | 
| 161 | 
            +
                idx: long, time index of the selected frame
         | 
| 162 | 
            +
                """
         | 
| 163 | 
            +
                idx = max(0, idx)
         | 
| 164 | 
            +
                idx = min(idx, conds.shape[0]-1)
         | 
| 165 | 
            +
                smo_half_win_size = smo_win_size//2
         | 
| 166 | 
            +
                left_i = idx - smo_half_win_size
         | 
| 167 | 
            +
                right_i = idx + (smo_win_size - smo_half_win_size)
         | 
| 168 | 
            +
                pad_left, pad_right = 0, 0
         | 
| 169 | 
            +
                if left_i < 0:
         | 
| 170 | 
            +
                    pad_left = -left_i
         | 
| 171 | 
            +
                    left_i = 0
         | 
| 172 | 
            +
                if right_i > conds.shape[0]:
         | 
| 173 | 
            +
                    pad_right = right_i - conds.shape[0]
         | 
| 174 | 
            +
                    right_i = conds.shape[0]
         | 
| 175 | 
            +
                conds_win = conds[left_i:right_i]
         | 
| 176 | 
            +
                if pad_left > 0:
         | 
| 177 | 
            +
                    if pad_option == 'zero':
         | 
| 178 | 
            +
                        conds_win = np.concatenate([np.zeros_like(conds_win)[:pad_left], conds_win], axis=0)
         | 
| 179 | 
            +
                    elif pad_option == 'edge':
         | 
| 180 | 
            +
                        edge_value = conds[0][np.newaxis, ...]
         | 
| 181 | 
            +
                        conds_win = np.concatenate([edge_value] * pad_left + [conds_win], axis=0)
         | 
| 182 | 
            +
                    else: 
         | 
| 183 | 
            +
                        raise NotImplementedError
         | 
| 184 | 
            +
                if pad_right > 0:
         | 
| 185 | 
            +
                    if pad_option == 'zero':
         | 
| 186 | 
            +
                        conds_win = np.concatenate([conds_win, np.zeros_like(conds_win)[:pad_right]], axis=0)
         | 
| 187 | 
            +
                    elif pad_option == 'edge':
         | 
| 188 | 
            +
                        edge_value = conds[-1][np.newaxis, ...]
         | 
| 189 | 
            +
                        conds_win = np.concatenate([conds_win] + [edge_value] * pad_right , axis=0)
         | 
| 190 | 
            +
                    else: 
         | 
| 191 | 
            +
                        raise NotImplementedError
         | 
| 192 | 
            +
                assert conds_win.shape[0] == smo_win_size
         | 
| 193 | 
            +
                return conds_win
         | 
| 194 | 
            +
             | 
| 195 | 
            +
             | 
| 196 | 
            +
            def load_processed_data(processed_dir):
         | 
| 197 | 
            +
                # load necessary files
         | 
| 198 | 
            +
                background_img_name = os.path.join(processed_dir, "bg.jpg")
         | 
| 199 | 
            +
                assert os.path.exists(background_img_name)
         | 
| 200 | 
            +
                head_img_dir = os.path.join(processed_dir, "head_imgs")
         | 
| 201 | 
            +
                torso_img_dir = os.path.join(processed_dir, "inpaint_torso_imgs")
         | 
| 202 | 
            +
                gt_img_dir = os.path.join(processed_dir, "gt_imgs")
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                hubert_npy_name = os.path.join(processed_dir, "aud_hubert.npy")
         | 
| 205 | 
            +
                mel_f0_npy_name = os.path.join(processed_dir, "aud_mel_f0.npy")
         | 
| 206 | 
            +
                coeff_npy_name = os.path.join(processed_dir, "coeff_fit_mp.npy")
         | 
| 207 | 
            +
                lm2d_npy_name = os.path.join(processed_dir, "lms_2d.npy")
         | 
| 208 | 
            +
                
         | 
| 209 | 
            +
                ret_dict = {}
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                ret_dict['bg_img'] = imageio.imread(background_img_name)
         | 
| 212 | 
            +
                ret_dict['H'], ret_dict['W'] = ret_dict['bg_img'].shape[:2]
         | 
| 213 | 
            +
                ret_dict['focal'], ret_dict['cx'], ret_dict['cy'] = face_model.focal, face_model.center, face_model.center
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                print("loading lm2d coeff ...")
         | 
| 216 | 
            +
                lm2d_arr = np.load(lm2d_npy_name)
         | 
| 217 | 
            +
                face_rect_lst = []
         | 
| 218 | 
            +
                lip_rect_lst = []
         | 
| 219 | 
            +
                for lm2d in lm2d_arr:
         | 
| 220 | 
            +
                    if len(lm2d) in [468, 478]:
         | 
| 221 | 
            +
                        lm2d = lm2d[index_lm68_from_lm468]
         | 
| 222 | 
            +
                    face_rect = get_face_rect(lm2d, ret_dict['H'], ret_dict['W'])
         | 
| 223 | 
            +
                    lip_rect = get_lip_rect(lm2d, ret_dict['H'], ret_dict['W'])
         | 
| 224 | 
            +
                    face_rect_lst.append(face_rect)
         | 
| 225 | 
            +
                    lip_rect_lst.append(lip_rect)
         | 
| 226 | 
            +
                face_rects = np.stack(face_rect_lst, axis=0) # [T, 4]
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                print("loading fitted 3dmm coeff ...")
         | 
| 229 | 
            +
                coeff_dict = np.load(coeff_npy_name, allow_pickle=True).tolist()
         | 
| 230 | 
            +
                identity_arr = coeff_dict['id']
         | 
| 231 | 
            +
                exp_arr = coeff_dict['exp']
         | 
| 232 | 
            +
                ret_dict['id'] = identity_arr
         | 
| 233 | 
            +
                ret_dict['exp'] = exp_arr
         | 
| 234 | 
            +
                euler_arr = ret_dict['euler'] = coeff_dict['euler']
         | 
| 235 | 
            +
                trans_arr = ret_dict['trans'] = coeff_dict['trans']
         | 
| 236 | 
            +
                print("calculating lm3d ...")
         | 
| 237 | 
            +
                idexp_lm3d_arr = face3d_helper.reconstruct_idexp_lm3d(torch.from_numpy(identity_arr), torch.from_numpy(exp_arr)).cpu().numpy().reshape([-1, 68*3])
         | 
| 238 | 
            +
                len_motion = len(idexp_lm3d_arr)
         | 
| 239 | 
            +
                video_idexp_lm3d_mean = idexp_lm3d_arr.mean(axis=0)
         | 
| 240 | 
            +
                video_idexp_lm3d_std = idexp_lm3d_arr.std(axis=0)
         | 
| 241 | 
            +
                ret_dict['idexp_lm3d'] = idexp_lm3d_arr
         | 
| 242 | 
            +
                ret_dict['idexp_lm3d_mean'] = video_idexp_lm3d_mean
         | 
| 243 | 
            +
                ret_dict['idexp_lm3d_std'] = video_idexp_lm3d_std
         | 
| 244 | 
            +
                
         | 
| 245 | 
            +
                # now we convert the euler_trans from deep3d convention to adnerf convention
         | 
| 246 | 
            +
                eulers = torch.FloatTensor(euler_arr)
         | 
| 247 | 
            +
                trans = torch.FloatTensor(trans_arr)
         | 
| 248 | 
            +
                rots = face_model.compute_rotation(eulers) # rotation matrix is a better intermediate for convention-transplan than euler
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                # handle the camera pose to geneface's convention
         | 
| 251 | 
            +
                trans[:, 2] = 10 - trans[:, 2] # 抵消fit阶段的to_camera操作,即trans[...,2] = 10 - trans[...,2]
         | 
| 252 | 
            +
                rots = rots.permute(0, 2, 1)
         | 
| 253 | 
            +
                trans[:, 2] = - trans[:,2] # 因为intrinsic proj不同
         | 
| 254 | 
            +
                # below is the NeRF camera preprocessing strategy, see `save_transforms` in data_util/process.py 
         | 
| 255 | 
            +
                trans = trans / 10.0
         | 
| 256 | 
            +
                rots_inv = rots.permute(0, 2, 1)
         | 
| 257 | 
            +
                trans_inv = - torch.bmm(rots_inv, trans.unsqueeze(2))
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                pose = torch.eye(4, dtype=torch.float32).unsqueeze(0).repeat([len_motion, 1, 1]) # [T, 4, 4]
         | 
| 260 | 
            +
                pose[:, :3, :3] = rots_inv
         | 
| 261 | 
            +
                pose[:, :3, 3] = trans_inv[:, :, 0]
         | 
| 262 | 
            +
                c2w_transform_matrices = pose.numpy()
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                # process the audio features used for postnet training
         | 
| 265 | 
            +
                print("loading hubert ...")
         | 
| 266 | 
            +
                hubert_features = np.load(hubert_npy_name)
         | 
| 267 | 
            +
                print("loading Mel and F0 ...")
         | 
| 268 | 
            +
                mel_f0_features = np.load(mel_f0_npy_name, allow_pickle=True).tolist()
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                ret_dict['hubert'] = hubert_features
         | 
| 271 | 
            +
                ret_dict['mel'] = mel_f0_features['mel']
         | 
| 272 | 
            +
                ret_dict['f0'] = mel_f0_features['f0']
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                # obtaining train samples
         | 
| 275 | 
            +
                frame_indices = list(range(len_motion))
         | 
| 276 | 
            +
                num_train = len_motion // 11 * 10
         | 
| 277 | 
            +
                train_indices = frame_indices[:num_train]
         | 
| 278 | 
            +
                val_indices = frame_indices[num_train:]
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                for split in ['train', 'val']:
         | 
| 281 | 
            +
                    if split == 'train':
         | 
| 282 | 
            +
                        indices = train_indices
         | 
| 283 | 
            +
                        samples = []
         | 
| 284 | 
            +
                        ret_dict['train_samples'] = samples
         | 
| 285 | 
            +
                    elif split == 'val':
         | 
| 286 | 
            +
                        indices = val_indices
         | 
| 287 | 
            +
                        samples = []
         | 
| 288 | 
            +
                        ret_dict['val_samples'] = samples
         | 
| 289 | 
            +
                    
         | 
| 290 | 
            +
                    for idx in indices:
         | 
| 291 | 
            +
                        sample = {}
         | 
| 292 | 
            +
                        sample['idx'] = idx
         | 
| 293 | 
            +
                        sample['head_img_fname'] = os.path.join(head_img_dir,f"{idx:08d}.png")
         | 
| 294 | 
            +
                        sample['torso_img_fname'] = os.path.join(torso_img_dir,f"{idx:08d}.png")
         | 
| 295 | 
            +
                        sample['gt_img_fname'] = os.path.join(gt_img_dir,f"{idx:08d}.jpg")
         | 
| 296 | 
            +
                        # assert os.path.exists(sample['head_img_fname']) and os.path.exists(sample['torso_img_fname']) and os.path.exists(sample['gt_img_fname'])
         | 
| 297 | 
            +
                        sample['face_rect'] = face_rects[idx]
         | 
| 298 | 
            +
                        sample['lip_rect'] = lip_rect_lst[idx]
         | 
| 299 | 
            +
                        sample['c2w'] = c2w_transform_matrices[idx]
         | 
| 300 | 
            +
                        samples.append(sample)
         | 
| 301 | 
            +
                return ret_dict
         | 
| 302 | 
            +
             | 
| 303 | 
            +
             | 
| 304 | 
            +
            class Binarizer:
         | 
| 305 | 
            +
                def __init__(self):
         | 
| 306 | 
            +
                    self.data_dir = 'data/'
         | 
| 307 | 
            +
                    
         | 
| 308 | 
            +
                def parse(self, video_id):
         | 
| 309 | 
            +
                    processed_dir = os.path.join(self.data_dir, 'processed/videos', video_id)
         | 
| 310 | 
            +
                    binary_dir = os.path.join(self.data_dir, 'binary/videos', video_id)
         | 
| 311 | 
            +
                    out_fname = os.path.join(binary_dir, "trainval_dataset.npy")
         | 
| 312 | 
            +
                    os.makedirs(binary_dir, exist_ok=True)
         | 
| 313 | 
            +
                    ret = load_processed_data(processed_dir)
         | 
| 314 | 
            +
                    mel_name = os.path.join(processed_dir, 'aud_mel_f0.npy')
         | 
| 315 | 
            +
                    mel_f0_dict = np.load(mel_name, allow_pickle=True).tolist()
         | 
| 316 | 
            +
                    ret.update(mel_f0_dict)
         | 
| 317 | 
            +
                    np.save(out_fname, ret, allow_pickle=True)
         | 
| 318 | 
            +
             | 
| 319 | 
            +
             | 
| 320 | 
            +
             | 
| 321 | 
            +
            if __name__ == '__main__':
         | 
| 322 | 
            +
                from argparse import ArgumentParser
         | 
| 323 | 
            +
                parser = ArgumentParser()
         | 
| 324 | 
            +
                parser.add_argument('--video_id', type=str, default='May', help='')
         | 
| 325 | 
            +
                args = parser.parse_args()
         | 
| 326 | 
            +
                ### Process Single Long Audio for NeRF dataset
         | 
| 327 | 
            +
                video_id = args.video_id
         | 
| 328 | 
            +
                face_model = ParametricFaceModel(bfm_folder='deep_3drecon/BFM', 
         | 
| 329 | 
            +
                            camera_distance=10, focal=1015)
         | 
| 330 | 
            +
                face_model.to("cpu")
         | 
| 331 | 
            +
                face3d_helper = Face3DHelper()
         | 
| 332 | 
            +
             | 
| 333 | 
            +
                binarizer = Binarizer()
         | 
| 334 | 
            +
                binarizer.parse(video_id)
         | 
| 335 | 
            +
                print(f"Binarization for {video_id} Done!")
         | 
    	
        data_gen/runs/binarizer_th1kh.py
    ADDED
    
    | @@ -0,0 +1,100 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            import numpy as np
         | 
| 3 | 
            +
            from scipy.misc import face
         | 
| 4 | 
            +
            import torch
         | 
| 5 | 
            +
            from tqdm import trange
         | 
| 6 | 
            +
            import pickle
         | 
| 7 | 
            +
            from copy import deepcopy
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            from data_util.face3d_helper import Face3DHelper
         | 
| 10 | 
            +
            from utils.commons.indexed_datasets import IndexedDataset, IndexedDatasetBuilder
         | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
            def load_video_npy(fn):
         | 
| 14 | 
            +
                assert fn.endswith("_coeff_fit_mp.npy")
         | 
| 15 | 
            +
                ret_dict = np.load(fn,allow_pickle=True).item()
         | 
| 16 | 
            +
                video_dict = {
         | 
| 17 | 
            +
                    'euler': ret_dict['euler'], # [T, 3]
         | 
| 18 | 
            +
                    'trans': ret_dict['trans'], # [T, 3]
         | 
| 19 | 
            +
                    'id': ret_dict['id'], # [T, 80]
         | 
| 20 | 
            +
                    'exp': ret_dict['exp'], # [T, 64]
         | 
| 21 | 
            +
                }
         | 
| 22 | 
            +
                return video_dict
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            def cal_lm3d_in_video_dict(video_dict, face3d_helper):
         | 
| 25 | 
            +
                identity = video_dict['id']
         | 
| 26 | 
            +
                exp = video_dict['exp']
         | 
| 27 | 
            +
                idexp_lm3d = face3d_helper.reconstruct_idexp_lm3d(identity, exp).cpu().numpy()
         | 
| 28 | 
            +
                video_dict['idexp_lm3d'] = idexp_lm3d
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
            def load_audio_npy(fn):
         | 
| 32 | 
            +
                assert fn.endswith(".npy")
         | 
| 33 | 
            +
                ret_dict = np.load(fn,allow_pickle=True).item()
         | 
| 34 | 
            +
                audio_dict = {
         | 
| 35 | 
            +
                    "mel": ret_dict['mel'], # [T, 80]
         | 
| 36 | 
            +
                    "f0": ret_dict['f0'], # [T,1]
         | 
| 37 | 
            +
                }
         | 
| 38 | 
            +
                return audio_dict
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
            if __name__ == '__main__':
         | 
| 42 | 
            +
                face3d_helper = Face3DHelper(use_gpu=False)
         | 
| 43 | 
            +
                
         | 
| 44 | 
            +
                import glob,tqdm
         | 
| 45 | 
            +
                prefixs = ['val', 'train']
         | 
| 46 | 
            +
                binarized_ds_path = "data/binary/th1kh"
         | 
| 47 | 
            +
                os.makedirs(binarized_ds_path, exist_ok=True)
         | 
| 48 | 
            +
                for prefix in prefixs:
         | 
| 49 | 
            +
                    databuilder = IndexedDatasetBuilder(os.path.join(binarized_ds_path, prefix), gzip=False, default_idx_size=1024*1024*1024*2)
         | 
| 50 | 
            +
                    raw_base_dir =  '/mnt/bn/ailabrenyi/entries/yezhenhui/datasets/raw/TH1KH_512/video'
         | 
| 51 | 
            +
                    mp4_names = glob.glob(os.path.join(raw_base_dir, '*.mp4'))
         | 
| 52 | 
            +
                    mp4_names = mp4_names[:1000]
         | 
| 53 | 
            +
                    cnt = 0
         | 
| 54 | 
            +
                    scnt = 0
         | 
| 55 | 
            +
                    pbar = tqdm.tqdm(enumerate(mp4_names), total=len(mp4_names))
         | 
| 56 | 
            +
                    for i, mp4_name in pbar:
         | 
| 57 | 
            +
                        cnt += 1
         | 
| 58 | 
            +
                        if prefix == 'train':
         | 
| 59 | 
            +
                            if i % 100 == 0:
         | 
| 60 | 
            +
                                continue
         | 
| 61 | 
            +
                        else:
         | 
| 62 | 
            +
                            if i % 100 != 0:
         | 
| 63 | 
            +
                                continue
         | 
| 64 | 
            +
                        hubert_npy_name = mp4_name.replace("/video/", "/hubert/").replace(".mp4", "_hubert.npy")
         | 
| 65 | 
            +
                        audio_npy_name = mp4_name.replace("/video/", "/mel_f0/").replace(".mp4", "_mel_f0.npy")
         | 
| 66 | 
            +
                        video_npy_name = mp4_name.replace("/video/", "/coeff_fit_mp/").replace(".mp4", "_coeff_fit_mp.npy")
         | 
| 67 | 
            +
                        if not os.path.exists(audio_npy_name):
         | 
| 68 | 
            +
                            print(f"Skip item for audio npy not found.")
         | 
| 69 | 
            +
                            continue
         | 
| 70 | 
            +
                        if not os.path.exists(video_npy_name):
         | 
| 71 | 
            +
                            print(f"Skip item for video npy not found.")
         | 
| 72 | 
            +
                            continue
         | 
| 73 | 
            +
                        if (not os.path.exists(hubert_npy_name)):
         | 
| 74 | 
            +
                            print(f"Skip item for hubert_npy not found.")
         | 
| 75 | 
            +
                            continue
         | 
| 76 | 
            +
                        audio_dict = load_audio_npy(audio_npy_name)
         | 
| 77 | 
            +
                        hubert = np.load(hubert_npy_name)
         | 
| 78 | 
            +
                        video_dict = load_video_npy(video_npy_name)
         | 
| 79 | 
            +
                        com_img_dir = mp4_name.replace("/video/", "/com_imgs/").replace(".mp4", "")
         | 
| 80 | 
            +
                        num_com_imgs = len(glob.glob(os.path.join(com_img_dir, '*')))
         | 
| 81 | 
            +
                        num_frames = len(video_dict['exp'])
         | 
| 82 | 
            +
                        if num_com_imgs != num_frames:
         | 
| 83 | 
            +
                            print(f"Skip item for length mismatch.")
         | 
| 84 | 
            +
                            continue
         | 
| 85 | 
            +
                        mel = audio_dict['mel']
         | 
| 86 | 
            +
                        if mel.shape[0] < 32: # the video is shorter than 0.6s
         | 
| 87 | 
            +
                            print(f"Skip item for too short.")
         | 
| 88 | 
            +
                            continue
         | 
| 89 | 
            +
                        
         | 
| 90 | 
            +
                        audio_dict.update(video_dict)
         | 
| 91 | 
            +
                        audio_dict['item_id'] = os.path.basename(mp4_name)[:-4]
         | 
| 92 | 
            +
                        audio_dict['hubert'] = hubert # [T_x, hid=1024]
         | 
| 93 | 
            +
                        audio_dict['img_dir'] = com_img_dir
         | 
| 94 | 
            +
             | 
| 95 | 
            +
             | 
| 96 | 
            +
                        databuilder.add_item(audio_dict)
         | 
| 97 | 
            +
                        scnt += 1
         | 
| 98 | 
            +
                        pbar.set_postfix({'success': scnt, 'success rate': scnt / cnt})
         | 
| 99 | 
            +
                    databuilder.finalize()
         | 
| 100 | 
            +
                    print(f"{prefix} set has {cnt} samples!")
         | 
    	
        data_gen/runs/nerf/process_guide.md
    ADDED
    
    | @@ -0,0 +1,49 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # 温馨提示:第一次执行可以先一步步跑完下面的命令行,把环境跑通后,之后可以直接运行同目录的run.sh,一键完成下面的所有步骤。
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Step0. 将视频Crop到512x512分辨率,25FPS,确保每一帧都有目标人脸
         | 
| 4 | 
            +
            ```
         | 
| 5 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -vf fps=25,scale=w=512:h=512 -qmin 1 -q:v 1 data/raw/videos/${VIDEO_ID}_512.mp4
         | 
| 6 | 
            +
            mv data/raw/videos/${VIDEO_ID}.mp4 data/raw/videos/${VIDEO_ID}_to_rm.mp4
         | 
| 7 | 
            +
            mv data/raw/videos/${VIDEO_ID}_512.mp4 data/raw/videos/${VIDEO_ID}.mp4
         | 
| 8 | 
            +
            ```
         | 
| 9 | 
            +
            # step1: 提取音频特征, 如mel, f0, hubuert, esperanto
         | 
| 10 | 
            +
            ```
         | 
| 11 | 
            +
            export CUDA_VISIBLE_DEVICES=0
         | 
| 12 | 
            +
            export VIDEO_ID=May
         | 
| 13 | 
            +
            mkdir -p data/processed/videos/${VIDEO_ID}
         | 
| 14 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -f wav -ar 16000 data/processed/videos/${VIDEO_ID}/aud.wav 
         | 
| 15 | 
            +
            python data_gen/utils/process_audio/extract_hubert.py --video_id=${VIDEO_ID}
         | 
| 16 | 
            +
            python data_gen/utils/process_audio/extract_mel_f0.py --video_id=${VIDEO_ID}
         | 
| 17 | 
            +
            ```
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # Step2. 提取图片
         | 
| 20 | 
            +
            ```
         | 
| 21 | 
            +
            export VIDEO_ID=May
         | 
| 22 | 
            +
            export CUDA_VISIBLE_DEVICES=0
         | 
| 23 | 
            +
            mkdir -p data/processed/videos/${VIDEO_ID}/gt_imgs
         | 
| 24 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -vf fps=25,scale=w=512:h=512 -qmin 1 -q:v 1 -start_number 0 data/processed/videos/${VIDEO_ID}/gt_imgs/%08d.jpg
         | 
| 25 | 
            +
            python data_gen/utils/process_video/extract_segment_imgs.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 # extract image, segmap, and background
         | 
| 26 | 
            +
            ```
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            # Step3. 提取lm2d_mediapipe
         | 
| 29 | 
            +
            ### 提取2D landmark用于之后Fit 3DMM
         | 
| 30 | 
            +
            ### num_workers是本机上的CPU worker数量;total_process是使用的机器数;process_id是本机的编号
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ```
         | 
| 33 | 
            +
            export VIDEO_ID=May
         | 
| 34 | 
            +
            python data_gen/utils/process_video/extract_lm2d.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4
         | 
| 35 | 
            +
            ```
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            # Step3. fit 3dmm
         | 
| 38 | 
            +
            ```
         | 
| 39 | 
            +
            export VIDEO_ID=May
         | 
| 40 | 
            +
            export CUDA_VISIBLE_DEVICES=0
         | 
| 41 | 
            +
            python data_gen/utils/process_video/fit_3dmm_landmark.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 --reset  --debug --id_mode=global
         | 
| 42 | 
            +
            ```
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            # Step4. Binarize
         | 
| 45 | 
            +
            ```
         | 
| 46 | 
            +
            export VIDEO_ID=May
         | 
| 47 | 
            +
            python data_gen/runs/binarizer_nerf.py --video_id=${VIDEO_ID}
         | 
| 48 | 
            +
            ```
         | 
| 49 | 
            +
            可以看到在`data/binary/videos/Mayssss`目录下得到了数据集。
         | 
    	
        data_gen/runs/nerf/run.sh
    ADDED
    
    | @@ -0,0 +1,51 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # usage: CUDA_VISIBLE_DEVICES=0 bash data_gen/runs/nerf/run.sh <VIDEO_ID>
         | 
| 2 | 
            +
            # please place video to data/raw/videos/${VIDEO_ID}.mp4 
         | 
| 3 | 
            +
            VIDEO_ID=$1
         | 
| 4 | 
            +
            echo Processing $VIDEO_ID
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            echo Resizing the video to 512x512
         | 
| 7 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -vf fps=25,scale=w=512:h=512 -qmin 1 -q:v 1 -y data/raw/videos/${VIDEO_ID}_512.mp4
         | 
| 8 | 
            +
            mv data/raw/videos/${VIDEO_ID}.mp4 data/raw/videos/${VIDEO_ID}_to_rm.mp4
         | 
| 9 | 
            +
            mv data/raw/videos/${VIDEO_ID}_512.mp4 data/raw/videos/${VIDEO_ID}.mp4
         | 
| 10 | 
            +
            echo Done
         | 
| 11 | 
            +
            echo The old video is moved to data/raw/videos/${VIDEO_ID}.mp4 data/raw/videos/${VIDEO_ID}_to_rm.mp4
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            echo mkdir -p data/processed/videos/${VIDEO_ID}
         | 
| 14 | 
            +
            mkdir -p data/processed/videos/${VIDEO_ID}
         | 
| 15 | 
            +
            echo Done
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            # extract audio file from the training video
         | 
| 18 | 
            +
            echo ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -f wav -ar 16000 -v quiet -y data/processed/videos/${VIDEO_ID}/aud.wav 
         | 
| 19 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -f wav -ar 16000 -v quiet -y data/processed/videos/${VIDEO_ID}/aud.wav 
         | 
| 20 | 
            +
            echo Done
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # extract hubert_mel_f0 from audio
         | 
| 23 | 
            +
            echo python data_gen/utils/process_audio/extract_hubert.py --video_id=${VIDEO_ID}
         | 
| 24 | 
            +
            python data_gen/utils/process_audio/extract_hubert.py --video_id=${VIDEO_ID}
         | 
| 25 | 
            +
            echo python data_gen/utils/process_audio/extract_mel_f0.py --video_id=${VIDEO_ID}
         | 
| 26 | 
            +
            python data_gen/utils/process_audio/extract_mel_f0.py --video_id=${VIDEO_ID}
         | 
| 27 | 
            +
            echo Done
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            # extract segment images
         | 
| 30 | 
            +
            echo mkdir -p data/processed/videos/${VIDEO_ID}/gt_imgs
         | 
| 31 | 
            +
            mkdir -p data/processed/videos/${VIDEO_ID}/gt_imgs
         | 
| 32 | 
            +
            echo ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -vf fps=25,scale=w=512:h=512 -qmin 1 -q:v 1 -start_number 0 -v quiet data/processed/videos/${VIDEO_ID}/gt_imgs/%08d.jpg
         | 
| 33 | 
            +
            ffmpeg -i data/raw/videos/${VIDEO_ID}.mp4 -vf fps=25,scale=w=512:h=512 -qmin 1 -q:v 1 -start_number 0 -v quiet data/processed/videos/${VIDEO_ID}/gt_imgs/%08d.jpg
         | 
| 34 | 
            +
            echo Done
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            echo python data_gen/utils/process_video/extract_segment_imgs.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 # extract image, segmap, and background
         | 
| 37 | 
            +
            python data_gen/utils/process_video/extract_segment_imgs.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 # extract image, segmap, and background
         | 
| 38 | 
            +
            echo Done
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            echo python data_gen/utils/process_video/extract_lm2d.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4
         | 
| 41 | 
            +
            python data_gen/utils/process_video/extract_lm2d.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4
         | 
| 42 | 
            +
            echo Done
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            pkill -f void*
         | 
| 45 | 
            +
            echo python data_gen/utils/process_video/fit_3dmm_landmark.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 --reset --debug --id_mode=global
         | 
| 46 | 
            +
            python data_gen/utils/process_video/fit_3dmm_landmark.py --ds_name=nerf --vid_dir=data/raw/videos/${VIDEO_ID}.mp4 --reset --debug --id_mode=global
         | 
| 47 | 
            +
            echo Done
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            echo python data_gen/runs/binarizer_nerf.py --video_id=${VIDEO_ID}
         | 
| 50 | 
            +
            python data_gen/runs/binarizer_nerf.py --video_id=${VIDEO_ID}
         | 
| 51 | 
            +
            echo Done
         | 
    	
        data_gen/utils/mp_feature_extractors/face_landmarker.py
    ADDED
    
    | @@ -0,0 +1,130 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import mediapipe as mp
         | 
| 2 | 
            +
            from mediapipe.tasks import python
         | 
| 3 | 
            +
            from mediapipe.tasks.python import vision
         | 
| 4 | 
            +
            import numpy as np
         | 
| 5 | 
            +
            import cv2
         | 
| 6 | 
            +
            import os
         | 
| 7 | 
            +
            import copy
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # simplified mediapipe ldm at https://github.com/k-m-irfan/simplified_mediapipe_face_landmarks
         | 
| 10 | 
            +
            index_lm141_from_lm478 = [70,63,105,66,107,55,65,52,53,46] + [300,293,334,296,336,285,295,282,283,276] + [33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7] + [263,466,388,387,386,385,384,398,362,382,381,380,374,373,390,249] + [78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95] + [61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146] + [10,338,297,332,284,251,389,356,454,323,361,288,397,365,379,378,400,377,152,148,176,149,150,136,172,58,132,93,234,127,162,21,54,103,67,109] + [468,469,470,471,472] + [473,474,475,476,477] + [64,4,294]
         | 
| 11 | 
            +
            # lm141 without iris
         | 
| 12 | 
            +
            index_lm131_from_lm478 = [70,63,105,66,107,55,65,52,53,46] + [300,293,334,296,336,285,295,282,283,276] + [33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7] + [263,466,388,387,386,385,384,398,362,382,381,380,374,373,390,249] + [78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95] + [61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146] + [10,338,297,332,284,251,389,356,454,323,361,288,397,365,379,378,400,377,152,148,176,149,150,136,172,58,132,93,234,127,162,21,54,103,67,109] + [64,4,294]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            # face alignment lm68
         | 
| 15 | 
            +
            index_lm68_from_lm478 = [127,234,93,132,58,136,150,176,152,400,379,365,288,361,323,454,356,70,63,105,66,107,336,296,334,293,300,168,197,5,4,75,97,2,326,305,
         | 
| 16 | 
            +
                                     33,160,158,133,153,144,362,385,387,263,373,380,61,40,37,0,267,270,291,321,314,17,84,91,78,81,13,311,308,402,14,178]
         | 
| 17 | 
            +
            # used for weights for key parts
         | 
| 18 | 
            +
            unmatch_mask_from_lm478 = [ 93, 127, 132, 234, 323, 356, 361, 454]
         | 
| 19 | 
            +
            index_eye_from_lm478 = [33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7] + [263,466,388,387,386,385,384,398,362,382,381,380,374,373,390,249]
         | 
| 20 | 
            +
            index_innerlip_from_lm478 = [78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95]
         | 
| 21 | 
            +
            index_outerlip_from_lm478 = [61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146]
         | 
| 22 | 
            +
            index_withinmouth_from_lm478 = [76, 62] + [184, 183, 74, 72, 73, 41, 72, 38, 11, 12, 302, 268, 303, 271, 304, 272, 408, 407] + [292, 306] +  [325, 307, 319, 320, 403, 404, 316, 315, 15, 16, 86, 85, 179, 180, 89, 90, 96, 77]
         | 
| 23 | 
            +
            index_mouth_from_lm478 = index_innerlip_from_lm478 + index_outerlip_from_lm478 + index_withinmouth_from_lm478
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            index_yaw_from_lm68 = list(range(0, 17))
         | 
| 26 | 
            +
            index_brow_from_lm68 = list(range(17, 27))
         | 
| 27 | 
            +
            index_nose_from_lm68 = list(range(27, 36))
         | 
| 28 | 
            +
            index_eye_from_lm68 = list(range(36, 48))
         | 
| 29 | 
            +
            index_mouth_from_lm68 = list(range(48, 68))
         | 
| 30 | 
            +
             | 
| 31 | 
            +
             | 
| 32 | 
            +
            def read_video_to_frames(video_name):
         | 
| 33 | 
            +
                frames = []
         | 
| 34 | 
            +
                cap = cv2.VideoCapture(video_name)
         | 
| 35 | 
            +
                while cap.isOpened():
         | 
| 36 | 
            +
                    ret, frame_bgr = cap.read()
         | 
| 37 | 
            +
                    if frame_bgr is None:
         | 
| 38 | 
            +
                        break
         | 
| 39 | 
            +
                    frames.append(frame_bgr)
         | 
| 40 | 
            +
                frames = np.stack(frames)
         | 
| 41 | 
            +
                frames = np.flip(frames, -1) # BGR ==> RGB
         | 
| 42 | 
            +
                return frames
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            class MediapipeLandmarker:
         | 
| 45 | 
            +
                def __init__(self):
         | 
| 46 | 
            +
                    model_path = 'data_gen/utils/mp_feature_extractors/face_landmarker.task'
         | 
| 47 | 
            +
                    if not os.path.exists(model_path):
         | 
| 48 | 
            +
                        os.makedirs(os.path.dirname(model_path), exist_ok=True)
         | 
| 49 | 
            +
                        print("downloading face_landmarker model from mediapipe...")
         | 
| 50 | 
            +
                        model_url = 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task'
         | 
| 51 | 
            +
                        os.system(f"wget {model_url}")
         | 
| 52 | 
            +
                        os.system(f"mv face_landmarker.task {model_path}")
         | 
| 53 | 
            +
                        print("download success")
         | 
| 54 | 
            +
                    base_options = python.BaseOptions(model_asset_path=model_path)
         | 
| 55 | 
            +
                    self.image_mode_options = vision.FaceLandmarkerOptions(base_options=base_options, 
         | 
| 56 | 
            +
                                    running_mode=vision.RunningMode.IMAGE, # IMAGE, VIDEO, LIVE_STREAM
         | 
| 57 | 
            +
                                    num_faces=1)
         | 
| 58 | 
            +
                    self.video_mode_options = vision.FaceLandmarkerOptions(base_options=base_options, 
         | 
| 59 | 
            +
                                    running_mode=vision.RunningMode.VIDEO, # IMAGE, VIDEO, LIVE_STREAM
         | 
| 60 | 
            +
                                    num_faces=1)
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def extract_lm478_from_img_name(self, img_name):
         | 
| 63 | 
            +
                    img = cv2.imread(img_name)
         | 
| 64 | 
            +
                    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
         | 
| 65 | 
            +
                    img_lm478 = self.extract_lm478_from_img(img)
         | 
| 66 | 
            +
                    return img_lm478
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                def extract_lm478_from_img(self, img):
         | 
| 69 | 
            +
                    img_landmarker = vision.FaceLandmarker.create_from_options(self.image_mode_options)
         | 
| 70 | 
            +
                    frame = mp.Image(image_format=mp.ImageFormat.SRGB, data=img.astype(np.uint8))
         | 
| 71 | 
            +
                    img_face_landmarker_result = img_landmarker.detect(image=frame)
         | 
| 72 | 
            +
                    img_ldm_i = img_face_landmarker_result.face_landmarks[0]
         | 
| 73 | 
            +
                    img_face_landmarks = np.array([[l.x, l.y, l.z] for l in img_ldm_i])
         | 
| 74 | 
            +
                    H, W, _ = img.shape
         | 
| 75 | 
            +
                    img_lm478 = np.array(img_face_landmarks)[:, :2] * np.array([W, H]).reshape([1,2]) # [478, 2]
         | 
| 76 | 
            +
                    return img_lm478
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def extract_lm478_from_video_name(self, video_name, fps=25, anti_smooth_factor=2):
         | 
| 79 | 
            +
                    frames = read_video_to_frames(video_name)
         | 
| 80 | 
            +
                    img_lm478, vid_lm478 = self.extract_lm478_from_frames(frames, fps, anti_smooth_factor)
         | 
| 81 | 
            +
                    return img_lm478, vid_lm478
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def extract_lm478_from_frames(self, frames, fps=25, anti_smooth_factor=20):
         | 
| 84 | 
            +
                    """
         | 
| 85 | 
            +
                    frames: RGB, uint8
         | 
| 86 | 
            +
                    anti_smooth_factor: float, 对video模式的interval进行修改, 1代表无修改, 越大越接近image mode
         | 
| 87 | 
            +
                    """
         | 
| 88 | 
            +
                    img_mpldms = []
         | 
| 89 | 
            +
                    vid_mpldms = []
         | 
| 90 | 
            +
                    img_landmarker = vision.FaceLandmarker.create_from_options(self.image_mode_options)
         | 
| 91 | 
            +
                    vid_landmarker = vision.FaceLandmarker.create_from_options(self.video_mode_options)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    for i in range(len(frames)):
         | 
| 94 | 
            +
                        frame = mp.Image(image_format=mp.ImageFormat.SRGB, data=frames[i].astype(np.uint8))
         | 
| 95 | 
            +
                        img_face_landmarker_result = img_landmarker.detect(image=frame)
         | 
| 96 | 
            +
                        vid_face_landmarker_result = vid_landmarker.detect_for_video(image=frame, timestamp_ms=int((1000/fps)*anti_smooth_factor*i))
         | 
| 97 | 
            +
                        try:
         | 
| 98 | 
            +
                            img_ldm_i = img_face_landmarker_result.face_landmarks[0]
         | 
| 99 | 
            +
                            vid_ldm_i = vid_face_landmarker_result.face_landmarks[0]
         | 
| 100 | 
            +
                        except:
         | 
| 101 | 
            +
                            print(f"Warning: failed detect ldm in idx={i}, use previous frame results.")
         | 
| 102 | 
            +
                        img_face_landmarks = np.array([[l.x, l.y, l.z] for l in img_ldm_i])
         | 
| 103 | 
            +
                        vid_face_landmarks = np.array([[l.x, l.y, l.z] for l in vid_ldm_i])
         | 
| 104 | 
            +
                        img_mpldms.append(img_face_landmarks)
         | 
| 105 | 
            +
                        vid_mpldms.append(vid_face_landmarks)
         | 
| 106 | 
            +
                    img_lm478 = np.stack(img_mpldms)[..., :2]
         | 
| 107 | 
            +
                    vid_lm478 = np.stack(vid_mpldms)[..., :2]
         | 
| 108 | 
            +
                    bs, H, W, _ = frames.shape
         | 
| 109 | 
            +
                    img_lm478 = np.array(img_lm478)[..., :2] * np.array([W, H]).reshape([1,1,2]) # [T, 478, 2]
         | 
| 110 | 
            +
                    vid_lm478 = np.array(vid_lm478)[..., :2] * np.array([W, H]).reshape([1,1,2]) # [T, 478, 2]
         | 
| 111 | 
            +
                    return img_lm478, vid_lm478
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def combine_vid_img_lm478_to_lm68(self, img_lm478, vid_lm478):
         | 
| 114 | 
            +
                    img_lm68 = img_lm478[:, index_lm68_from_lm478]
         | 
| 115 | 
            +
                    vid_lm68 = vid_lm478[:, index_lm68_from_lm478]
         | 
| 116 | 
            +
                    combined_lm68 = copy.deepcopy(img_lm68)
         | 
| 117 | 
            +
                    combined_lm68[:, index_yaw_from_lm68] = vid_lm68[:, index_yaw_from_lm68]
         | 
| 118 | 
            +
                    combined_lm68[:, index_brow_from_lm68] = vid_lm68[:, index_brow_from_lm68]
         | 
| 119 | 
            +
                    combined_lm68[:, index_nose_from_lm68] = vid_lm68[:, index_nose_from_lm68]
         | 
| 120 | 
            +
                    return combined_lm68
         | 
| 121 | 
            +
                 
         | 
| 122 | 
            +
                def combine_vid_img_lm478_to_lm478(self, img_lm478, vid_lm478):
         | 
| 123 | 
            +
                    combined_lm478 = copy.deepcopy(vid_lm478)
         | 
| 124 | 
            +
                    combined_lm478[:, index_mouth_from_lm478] = img_lm478[:, index_mouth_from_lm478]
         | 
| 125 | 
            +
                    combined_lm478[:, index_eye_from_lm478] = img_lm478[:, index_eye_from_lm478]
         | 
| 126 | 
            +
                    return combined_lm478
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            if __name__ == '__main__':
         | 
| 129 | 
            +
                landmarker = MediapipeLandmarker()
         | 
| 130 | 
            +
                ret = landmarker.extract_lm478_from_video_name("00000.mp4")
         | 
    	
        data_gen/utils/mp_feature_extractors/face_landmarker.task
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:64184e229b263107bc2b804c6625db1341ff2bb731874b0bcc2fe6544e0bc9ff
         | 
| 3 | 
            +
            size 3758596
         | 
    	
        data_gen/utils/mp_feature_extractors/mp_segmenter.py
    ADDED
    
    | @@ -0,0 +1,303 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            import copy
         | 
| 3 | 
            +
            import numpy as np
         | 
| 4 | 
            +
            import tqdm
         | 
| 5 | 
            +
            import mediapipe as mp
         | 
| 6 | 
            +
            import torch
         | 
| 7 | 
            +
            from mediapipe.tasks import python
         | 
| 8 | 
            +
            from mediapipe.tasks.python import vision
         | 
| 9 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm, multiprocess_run
         | 
| 10 | 
            +
            from utils.commons.tensor_utils import convert_to_np
         | 
| 11 | 
            +
            from sklearn.neighbors import NearestNeighbors
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            def scatter_np(condition_img, classSeg=5):
         | 
| 14 | 
            +
            # def scatter(condition_img, classSeg=19, label_size=(512, 512)):
         | 
| 15 | 
            +
                batch, c, height, width = condition_img.shape
         | 
| 16 | 
            +
                # if height != label_size[0] or width != label_size[1]:
         | 
| 17 | 
            +
                    # condition_img= F.interpolate(condition_img, size=label_size, mode='nearest')
         | 
| 18 | 
            +
                input_label = np.zeros([batch, classSeg, condition_img.shape[2], condition_img.shape[3]]).astype(np.int_)
         | 
| 19 | 
            +
                # input_label = torch.zeros(batch, classSeg, *label_size, device=condition_img.device)
         | 
| 20 | 
            +
                np.put_along_axis(input_label, condition_img, 1, 1)
         | 
| 21 | 
            +
                return input_label
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            def scatter(condition_img, classSeg=19):
         | 
| 24 | 
            +
            # def scatter(condition_img, classSeg=19, label_size=(512, 512)):
         | 
| 25 | 
            +
                batch, c, height, width = condition_img.size()
         | 
| 26 | 
            +
                # if height != label_size[0] or width != label_size[1]:
         | 
| 27 | 
            +
                    # condition_img= F.interpolate(condition_img, size=label_size, mode='nearest')
         | 
| 28 | 
            +
                input_label = torch.zeros(batch, classSeg, condition_img.shape[2], condition_img.shape[3], device=condition_img.device)
         | 
| 29 | 
            +
                # input_label = torch.zeros(batch, classSeg, *label_size, device=condition_img.device)
         | 
| 30 | 
            +
                return input_label.scatter_(1, condition_img.long(), 1)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            def encode_segmap_mask_to_image(segmap):
         | 
| 33 | 
            +
                # rgb
         | 
| 34 | 
            +
                _,h,w = segmap.shape
         | 
| 35 | 
            +
                encoded_img = np.ones([h,w,3],dtype=np.uint8) * 255
         | 
| 36 | 
            +
                colors = [(255,255,255),(255,255,0),(255,0,255),(0,255,255),(255,0,0),(0,255,0)]
         | 
| 37 | 
            +
                for i, color in enumerate(colors):
         | 
| 38 | 
            +
                    mask = segmap[i].astype(int)
         | 
| 39 | 
            +
                    index = np.where(mask != 0)
         | 
| 40 | 
            +
                    encoded_img[index[0], index[1], :] = np.array(color)
         | 
| 41 | 
            +
                return encoded_img.astype(np.uint8)
         | 
| 42 | 
            +
                    
         | 
| 43 | 
            +
            def decode_segmap_mask_from_image(encoded_img):
         | 
| 44 | 
            +
                # rgb
         | 
| 45 | 
            +
                colors = [(255,255,255),(255,255,0),(255,0,255),(0,255,255),(255,0,0),(0,255,0)]
         | 
| 46 | 
            +
                bg = (encoded_img[..., 0] == 255) & (encoded_img[..., 1] == 255) & (encoded_img[..., 2] == 255)
         | 
| 47 | 
            +
                hair = (encoded_img[..., 0] == 255) & (encoded_img[..., 1] == 255) & (encoded_img[..., 2] == 0)
         | 
| 48 | 
            +
                body_skin = (encoded_img[..., 0] == 255) & (encoded_img[..., 1] == 0) & (encoded_img[..., 2] == 255)
         | 
| 49 | 
            +
                face_skin = (encoded_img[..., 0] == 0) & (encoded_img[..., 1] == 255) & (encoded_img[..., 2] == 255)
         | 
| 50 | 
            +
                clothes = (encoded_img[..., 0] == 255) & (encoded_img[..., 1] == 0) & (encoded_img[..., 2] == 0)
         | 
| 51 | 
            +
                others = (encoded_img[..., 0] == 0) & (encoded_img[..., 1] == 255) & (encoded_img[..., 2] == 0)
         | 
| 52 | 
            +
                segmap = np.stack([bg, hair, body_skin, face_skin, clothes, others], axis=0)
         | 
| 53 | 
            +
                return segmap.astype(np.uint8)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            def read_video_frame(video_name, frame_id):
         | 
| 56 | 
            +
                # https://blog.csdn.net/bby1987/article/details/108923361
         | 
| 57 | 
            +
                # frame_num = video_capture.get(cv2.CAP_PROP_FRAME_COUNT) # ==> 总帧数
         | 
| 58 | 
            +
                # fps = video_capture.get(cv2.CAP_PROP_FPS)               # ==> 帧率
         | 
| 59 | 
            +
                # width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)     # ==> 视频宽度
         | 
| 60 | 
            +
                # height = video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)   # ==> 视频高度
         | 
| 61 | 
            +
                # pos = video_capture.get(cv2.CAP_PROP_POS_FRAMES)        # ==> 句柄位置
         | 
| 62 | 
            +
                # video_capture.set(cv2.CAP_PROP_POS_FRAMES, 1000)        # ==> 设置句柄位置
         | 
| 63 | 
            +
                # pos = video_capture.get(cv2.CAP_PROP_POS_FRAMES)        # ==> 此时 pos = 1000.0
         | 
| 64 | 
            +
                # video_capture.release()
         | 
| 65 | 
            +
                vr = cv2.VideoCapture(video_name)
         | 
| 66 | 
            +
                vr.set(cv2.CAP_PROP_POS_FRAMES, frame_id)
         | 
| 67 | 
            +
                _, frame = vr.read()
         | 
| 68 | 
            +
                return frame
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            def decode_segmap_mask_from_segmap_video_frame(video_frame):
         | 
| 71 | 
            +
                # video_frame: 0~255 BGR, obtained by read_video_frame
         | 
| 72 | 
            +
                def assign_values(array):
         | 
| 73 | 
            +
                    remainder = array % 40  # 计算数组中每个值与40的余数
         | 
| 74 | 
            +
                    assigned_values = np.where(remainder <= 20, array - remainder, array + (40 - remainder))
         | 
| 75 | 
            +
                    return assigned_values
         | 
| 76 | 
            +
                segmap = video_frame.mean(-1)
         | 
| 77 | 
            +
                segmap = assign_values(segmap) // 40 # [H, W] with value 0~5 
         | 
| 78 | 
            +
                segmap_mask = scatter_np(segmap[None, None, ...], classSeg=6)[0] # [6, H, W]
         | 
| 79 | 
            +
                return segmap.astype(np.uint8)
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            def extract_background(img_lst, segmap_lst=None):
         | 
| 82 | 
            +
                """
         | 
| 83 | 
            +
                img_lst: list of rgb ndarray
         | 
| 84 | 
            +
                """
         | 
| 85 | 
            +
                # only use 1/20 images
         | 
| 86 | 
            +
                num_frames = len(img_lst)
         | 
| 87 | 
            +
                img_lst = img_lst[::20] if num_frames > 20 else img_lst[0:1]
         | 
| 88 | 
            +
                    
         | 
| 89 | 
            +
                if segmap_lst is not None:
         | 
| 90 | 
            +
                    segmap_lst = segmap_lst[::20] if num_frames > 20 else segmap_lst[0:1]
         | 
| 91 | 
            +
                    assert len(img_lst) == len(segmap_lst)
         | 
| 92 | 
            +
                # get H/W
         | 
| 93 | 
            +
                h, w = img_lst[0].shape[:2]
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                # nearest neighbors
         | 
| 96 | 
            +
                all_xys = np.mgrid[0:h, 0:w].reshape(2, -1).transpose()
         | 
| 97 | 
            +
                distss = []
         | 
| 98 | 
            +
                for idx, img in enumerate(img_lst):
         | 
| 99 | 
            +
                    if segmap_lst is not None:
         | 
| 100 | 
            +
                        segmap = segmap_lst[idx]
         | 
| 101 | 
            +
                    else:
         | 
| 102 | 
            +
                        segmap = seg_model._cal_seg_map(img)
         | 
| 103 | 
            +
                    bg = (segmap[0]).astype(bool)
         | 
| 104 | 
            +
                    fg_xys = np.stack(np.nonzero(~bg)).transpose(1, 0)
         | 
| 105 | 
            +
                    nbrs = NearestNeighbors(n_neighbors=1, algorithm='kd_tree').fit(fg_xys)
         | 
| 106 | 
            +
                    dists, _ = nbrs.kneighbors(all_xys)
         | 
| 107 | 
            +
                    distss.append(dists)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                distss = np.stack(distss)
         | 
| 110 | 
            +
                max_dist = np.max(distss, 0)
         | 
| 111 | 
            +
                max_id = np.argmax(distss, 0)
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                bc_pixs = max_dist > 10 # 5
         | 
| 114 | 
            +
                bc_pixs_id = np.nonzero(bc_pixs)
         | 
| 115 | 
            +
                bc_ids = max_id[bc_pixs]
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                num_pixs = distss.shape[1]
         | 
| 118 | 
            +
                imgs = np.stack(img_lst).reshape(-1, num_pixs, 3)
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                bg_img = np.zeros((h*w, 3), dtype=np.uint8)
         | 
| 121 | 
            +
                bg_img[bc_pixs_id, :] = imgs[bc_ids, bc_pixs_id, :]
         | 
| 122 | 
            +
                bg_img = bg_img.reshape(h, w, 3)
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                max_dist = max_dist.reshape(h, w)
         | 
| 125 | 
            +
                bc_pixs = max_dist > 10 # 5
         | 
| 126 | 
            +
                bg_xys = np.stack(np.nonzero(~bc_pixs)).transpose()
         | 
| 127 | 
            +
                fg_xys = np.stack(np.nonzero(bc_pixs)).transpose()
         | 
| 128 | 
            +
                nbrs = NearestNeighbors(n_neighbors=1, algorithm='kd_tree').fit(fg_xys)
         | 
| 129 | 
            +
                distances, indices = nbrs.kneighbors(bg_xys)
         | 
| 130 | 
            +
                bg_fg_xys = fg_xys[indices[:, 0]]
         | 
| 131 | 
            +
                bg_img[bg_xys[:, 0], bg_xys[:, 1], :] = bg_img[bg_fg_xys[:, 0], bg_fg_xys[:, 1], :]
         | 
| 132 | 
            +
                return bg_img
         | 
| 133 | 
            +
             | 
| 134 | 
            +
             | 
| 135 | 
            +
            global_segmenter = None
         | 
| 136 | 
            +
            def job_cal_seg_map_for_image(img, segmenter_options=None, segmenter=None):
         | 
| 137 | 
            +
                """
         | 
| 138 | 
            +
                被 MediapipeSegmenter.multiprocess_cal_seg_map_for_a_video所使用, 专门用来处理单个长视频.
         | 
| 139 | 
            +
                """
         | 
| 140 | 
            +
                global global_segmenter
         | 
| 141 | 
            +
                if segmenter is not None:
         | 
| 142 | 
            +
                    segmenter_actual = segmenter
         | 
| 143 | 
            +
                else:
         | 
| 144 | 
            +
                    global_segmenter = vision.ImageSegmenter.create_from_options(segmenter_options) if global_segmenter is None else global_segmenter
         | 
| 145 | 
            +
                    segmenter_actual = global_segmenter
         | 
| 146 | 
            +
                mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=img)
         | 
| 147 | 
            +
                out = segmenter_actual.segment(mp_image)
         | 
| 148 | 
            +
                segmap = out.category_mask.numpy_view().copy() # [H, W]
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                segmap_mask = scatter_np(segmap[None, None, ...], classSeg=6)[0] # [6, H, W]
         | 
| 151 | 
            +
                segmap_image = segmap[:, :, None].repeat(3, 2).astype(float)
         | 
| 152 | 
            +
                segmap_image = (segmap_image * 40).astype(np.uint8)
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                return segmap_mask, segmap_image
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            class MediapipeSegmenter:
         | 
| 157 | 
            +
                def __init__(self):
         | 
| 158 | 
            +
                    model_path = 'data_gen/utils/mp_feature_extractors/selfie_multiclass_256x256.tflite'
         | 
| 159 | 
            +
                    if not os.path.exists(model_path):
         | 
| 160 | 
            +
                        os.makedirs(os.path.dirname(model_path), exist_ok=True)
         | 
| 161 | 
            +
                        print("downloading segmenter model from mediapipe...")
         | 
| 162 | 
            +
                        os.system(f"wget https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite")
         | 
| 163 | 
            +
                        os.system(f"mv selfie_multiclass_256x256.tflite {model_path}")
         | 
| 164 | 
            +
                        print("download success")
         | 
| 165 | 
            +
                    base_options = python.BaseOptions(model_asset_path=model_path)
         | 
| 166 | 
            +
                    self.options = vision.ImageSegmenterOptions(base_options=base_options,running_mode=vision.RunningMode.IMAGE, output_category_mask=True)
         | 
| 167 | 
            +
                    self.video_options = vision.ImageSegmenterOptions(base_options=base_options,running_mode=vision.RunningMode.VIDEO, output_category_mask=True)
         | 
| 168 | 
            +
                
         | 
| 169 | 
            +
                def multiprocess_cal_seg_map_for_a_video(self, imgs, num_workers=4):
         | 
| 170 | 
            +
                    """
         | 
| 171 | 
            +
                    并行处理单个长视频
         | 
| 172 | 
            +
                    imgs: list of rgb array in 0~255
         | 
| 173 | 
            +
                    """
         | 
| 174 | 
            +
                    segmap_masks = []
         | 
| 175 | 
            +
                    segmap_images = []
         | 
| 176 | 
            +
                    img_lst = [(self.options, imgs[i]) for i in range(len(imgs))]
         | 
| 177 | 
            +
                    for (i, res) in multiprocess_run_tqdm(job_cal_seg_map_for_image, args=img_lst, num_workers=num_workers, desc='extracting from a video in multi-process'):
         | 
| 178 | 
            +
                        segmap_mask, segmap_image = res
         | 
| 179 | 
            +
                        segmap_masks.append(segmap_mask)
         | 
| 180 | 
            +
                        segmap_images.append(segmap_image)
         | 
| 181 | 
            +
                    return segmap_masks, segmap_images
         | 
| 182 | 
            +
                    
         | 
| 183 | 
            +
                def _cal_seg_map_for_video(self, imgs, segmenter=None, return_onehot_mask=True, return_segmap_image=True):
         | 
| 184 | 
            +
                    segmenter = vision.ImageSegmenter.create_from_options(self.video_options) if segmenter is None else segmenter
         | 
| 185 | 
            +
                    assert return_onehot_mask or return_segmap_image # you should at least return one
         | 
| 186 | 
            +
                    segmap_masks = []
         | 
| 187 | 
            +
                    segmap_images = []
         | 
| 188 | 
            +
                    for i in tqdm.trange(len(imgs), desc="extracting segmaps from a video..."):
         | 
| 189 | 
            +
                        img = imgs[i]
         | 
| 190 | 
            +
                        mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=img)
         | 
| 191 | 
            +
                        out = segmenter.segment_for_video(mp_image, 40 * i)
         | 
| 192 | 
            +
                        segmap = out.category_mask.numpy_view().copy() # [H, W]
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                        if return_onehot_mask:
         | 
| 195 | 
            +
                            segmap_mask = scatter_np(segmap[None, None, ...], classSeg=6)[0] # [6, H, W]
         | 
| 196 | 
            +
                            segmap_masks.append(segmap_mask)
         | 
| 197 | 
            +
                        if return_segmap_image:
         | 
| 198 | 
            +
                            segmap_image = segmap[:, :, None].repeat(3, 2).astype(float)
         | 
| 199 | 
            +
                            segmap_image = (segmap_image * 40).astype(np.uint8)
         | 
| 200 | 
            +
                            segmap_images.append(segmap_image)
         | 
| 201 | 
            +
                    
         | 
| 202 | 
            +
                    if return_onehot_mask and return_segmap_image:
         | 
| 203 | 
            +
                        return segmap_masks, segmap_images
         | 
| 204 | 
            +
                    elif return_onehot_mask:
         | 
| 205 | 
            +
                        return segmap_masks
         | 
| 206 | 
            +
                    elif return_segmap_image:
         | 
| 207 | 
            +
                        return segmap_images
         | 
| 208 | 
            +
                
         | 
| 209 | 
            +
                def _cal_seg_map(self, img, segmenter=None, return_onehot_mask=True):
         | 
| 210 | 
            +
                    """
         | 
| 211 | 
            +
                    segmenter: vision.ImageSegmenter.create_from_options(options)
         | 
| 212 | 
            +
                    img: numpy, [H, W, 3], 0~255
         | 
| 213 | 
            +
                    segmap: [C, H, W]
         | 
| 214 | 
            +
                    0 - background
         | 
| 215 | 
            +
                    1 - hair
         | 
| 216 | 
            +
                    2 - body-skin
         | 
| 217 | 
            +
                    3 - face-skin
         | 
| 218 | 
            +
                    4 - clothes
         | 
| 219 | 
            +
                    5 - others (accessories)
         | 
| 220 | 
            +
                    """
         | 
| 221 | 
            +
                    assert img.ndim == 3
         | 
| 222 | 
            +
                    segmenter = vision.ImageSegmenter.create_from_options(self.options) if segmenter is None else segmenter 
         | 
| 223 | 
            +
                    image = mp.Image(image_format=mp.ImageFormat.SRGB, data=img)
         | 
| 224 | 
            +
                    out = segmenter.segment(image) 
         | 
| 225 | 
            +
                    segmap = out.category_mask.numpy_view().copy() # [H, W]
         | 
| 226 | 
            +
                    if return_onehot_mask:
         | 
| 227 | 
            +
                        segmap = scatter_np(segmap[None, None, ...], classSeg=6)[0] # [6, H, W]
         | 
| 228 | 
            +
                    return segmap
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                def _seg_out_img_with_segmap(self, img, segmap, mode='head'):
         | 
| 231 | 
            +
                    """
         | 
| 232 | 
            +
                    img: [h,w,c], img is in 0~255, np
         | 
| 233 | 
            +
                    """
         | 
| 234 | 
            +
                    # 
         | 
| 235 | 
            +
                    img = copy.deepcopy(img)
         | 
| 236 | 
            +
                    if mode == 'head':
         | 
| 237 | 
            +
                        selected_mask = segmap[[1,3,5] , :, :].sum(axis=0)[None,:] > 0.5 # glasses 也属于others
         | 
| 238 | 
            +
                        img[~selected_mask.repeat(3,axis=0).transpose(1,2,0)] = 0 # (-1,-1,-1) denotes black in our [-1,1] convention
         | 
| 239 | 
            +
                        # selected_mask = segmap[[1,3] , :, :].sum(dim=0, keepdim=True) > 0.5
         | 
| 240 | 
            +
                    elif mode == 'person':
         | 
| 241 | 
            +
                        selected_mask = segmap[[1,2,3,4,5], :, :].sum(axis=0)[None,:] > 0.5 
         | 
| 242 | 
            +
                        img[~selected_mask.repeat(3,axis=0).transpose(1,2,0)] = 0 # (-1,-1,-1) denotes black in our [-1,1] convention
         | 
| 243 | 
            +
                    elif mode == 'torso':
         | 
| 244 | 
            +
                        selected_mask = segmap[[2,4], :, :].sum(axis=0)[None,:] > 0.5
         | 
| 245 | 
            +
                        img[~selected_mask.repeat(3,axis=0).transpose(1,2,0)] = 0 # (-1,-1,-1) denotes black in our [-1,1] convention
         | 
| 246 | 
            +
                    elif mode == 'torso_with_bg':
         | 
| 247 | 
            +
                        selected_mask = segmap[[0, 2,4], :, :].sum(axis=0)[None,:] > 0.5
         | 
| 248 | 
            +
                        img[~selected_mask.repeat(3,axis=0).transpose(1,2,0)] = 0 # (-1,-1,-1) denotes black in our [-1,1] convention
         | 
| 249 | 
            +
                    elif mode == 'bg':
         | 
| 250 | 
            +
                        selected_mask = segmap[[0], :, :].sum(axis=0)[None,:] > 0.5  # only seg out 0, which means background
         | 
| 251 | 
            +
                        img[~selected_mask.repeat(3,axis=0).transpose(1,2,0)] = 0 # (-1,-1,-1) denotes black in our [-1,1] convention
         | 
| 252 | 
            +
                    elif mode == 'full':
         | 
| 253 | 
            +
                        pass
         | 
| 254 | 
            +
                    else:
         | 
| 255 | 
            +
                        raise NotImplementedError()
         | 
| 256 | 
            +
                    return img, selected_mask
         | 
| 257 | 
            +
                
         | 
| 258 | 
            +
                def _seg_out_img(self, img, segmenter=None, mode='head'):
         | 
| 259 | 
            +
                    """
         | 
| 260 | 
            +
                    imgs [H, W, 3] 0-255
         | 
| 261 | 
            +
                    return : person_img [B, 3, H, W]
         | 
| 262 | 
            +
                    """
         | 
| 263 | 
            +
                    segmenter = vision.ImageSegmenter.create_from_options(self.options) if segmenter is None else segmenter 
         | 
| 264 | 
            +
                    segmap = self._cal_seg_map(img, segmenter=segmenter, return_onehot_mask=True) # [B, 19, H, W]
         | 
| 265 | 
            +
                    return self._seg_out_img_with_segmap(img, segmap, mode=mode)
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                def seg_out_imgs(self, img, mode='head'):
         | 
| 268 | 
            +
                    """
         | 
| 269 | 
            +
                    api for pytorch img, -1~1
         | 
| 270 | 
            +
                    img: [B, 3, H, W], -1~1
         | 
| 271 | 
            +
                    """
         | 
| 272 | 
            +
                    device = img.device
         | 
| 273 | 
            +
                    img = convert_to_np(img.permute(0, 2, 3, 1)) # [B, H, W, 3]
         | 
| 274 | 
            +
                    img = ((img + 1) * 127.5).astype(np.uint8)
         | 
| 275 | 
            +
                    img_lst = [copy.deepcopy(img[i]) for i in range(len(img))]
         | 
| 276 | 
            +
                    out_lst = []
         | 
| 277 | 
            +
                    for im in img_lst:
         | 
| 278 | 
            +
                        out = self._seg_out_img(im, mode=mode)
         | 
| 279 | 
            +
                        out_lst.append(out)
         | 
| 280 | 
            +
                    seg_imgs = np.stack(out_lst) # [B, H, W, 3]
         | 
| 281 | 
            +
                    seg_imgs = (seg_imgs - 127.5) / 127.5
         | 
| 282 | 
            +
                    seg_imgs = torch.from_numpy(seg_imgs).permute(0, 3, 1, 2).to(device)
         | 
| 283 | 
            +
                    return seg_imgs
         | 
| 284 | 
            +
             | 
| 285 | 
            +
            if __name__ == '__main__':
         | 
| 286 | 
            +
                import imageio, cv2, tqdm
         | 
| 287 | 
            +
                import torchshow as ts
         | 
| 288 | 
            +
                img = imageio.imread("1.png")
         | 
| 289 | 
            +
                img = cv2.resize(img, (512,512))
         | 
| 290 | 
            +
             | 
| 291 | 
            +
                seg_model = MediapipeSegmenter()
         | 
| 292 | 
            +
                img = torch.tensor(img).unsqueeze(0).repeat([1, 1, 1, 1]).permute(0, 3,1,2)
         | 
| 293 | 
            +
                img = (img-127.5)/127.5
         | 
| 294 | 
            +
                out = seg_model.seg_out_imgs(img, 'torso')
         | 
| 295 | 
            +
                ts.save(out,"torso.png")
         | 
| 296 | 
            +
                out = seg_model.seg_out_imgs(img, 'head')
         | 
| 297 | 
            +
                ts.save(out,"head.png")
         | 
| 298 | 
            +
                out = seg_model.seg_out_imgs(img, 'bg')
         | 
| 299 | 
            +
                ts.save(out,"bg.png")
         | 
| 300 | 
            +
                img = convert_to_np(img.permute(0, 2, 3, 1)) # [B, H, W, 3]
         | 
| 301 | 
            +
                img = ((img + 1) * 127.5).astype(np.uint8)
         | 
| 302 | 
            +
                bg = extract_background(img)
         | 
| 303 | 
            +
                ts.save(bg,"bg2.png")
         | 
    	
        data_gen/utils/mp_feature_extractors/selfie_multiclass_256x256.tflite
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:c6748b1253a99067ef71f7e26ca71096cd449baefa8f101900ea23016507e0e0
         | 
| 3 | 
            +
            size 16371837
         | 
    	
        data_gen/utils/path_converter.py
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class PathConverter():
         | 
| 5 | 
            +
                def __init__(self):
         | 
| 6 | 
            +
                    self.prefixs = {
         | 
| 7 | 
            +
                        "vid": "/video/",
         | 
| 8 | 
            +
                        "gt": "/gt_imgs/",
         | 
| 9 | 
            +
                        "head": "/head_imgs/", 
         | 
| 10 | 
            +
                        "torso": "/torso_imgs/", 
         | 
| 11 | 
            +
                        "person": "/person_imgs/", 
         | 
| 12 | 
            +
                        "torso_with_bg": "/torso_with_bg_imgs/", 
         | 
| 13 | 
            +
                        "single_bg": "/bg_img/",
         | 
| 14 | 
            +
                        "bg": "/bg_imgs/",
         | 
| 15 | 
            +
                        "segmaps": "/segmaps/",
         | 
| 16 | 
            +
                        "inpaint_torso": "/inpaint_torso_imgs/",
         | 
| 17 | 
            +
                        "com": "/com_imgs/",
         | 
| 18 | 
            +
                        "inpaint_torso_with_com_bg": "/inpaint_torso_with_com_bg_imgs/",
         | 
| 19 | 
            +
                    }
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                def to(self, path: str, old_pattern: str, new_pattern: str):
         | 
| 22 | 
            +
                    return path.replace(self.prefixs[old_pattern], self.prefixs[new_pattern], 1)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            pc = PathConverter()
         | 
    	
        data_gen/utils/process_audio/extract_hubert.py
    ADDED
    
    | @@ -0,0 +1,95 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            from transformers import Wav2Vec2Processor, HubertModel
         | 
| 2 | 
            +
            import soundfile as sf
         | 
| 3 | 
            +
            import numpy as np
         | 
| 4 | 
            +
            import torch
         | 
| 5 | 
            +
            import os
         | 
| 6 | 
            +
            from utils.commons.hparams import set_hparams, hparams
         | 
| 7 | 
            +
             | 
| 8 | 
            +
             | 
| 9 | 
            +
            wav2vec2_processor = None
         | 
| 10 | 
            +
            hubert_model = None
         | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
            def get_hubert_from_16k_wav(wav_16k_name):
         | 
| 14 | 
            +
                speech_16k, _ = sf.read(wav_16k_name)
         | 
| 15 | 
            +
                hubert = get_hubert_from_16k_speech(speech_16k)
         | 
| 16 | 
            +
                return hubert
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            @torch.no_grad()
         | 
| 19 | 
            +
            def get_hubert_from_16k_speech(speech, device="cuda:0"):
         | 
| 20 | 
            +
                global hubert_model, wav2vec2_processor
         | 
| 21 | 
            +
                local_path = '/home/tiger/.cache/huggingface/hub/models--facebook--hubert-large-ls960-ft/snapshots/ece5fabbf034c1073acae96d5401b25be96709d8'
         | 
| 22 | 
            +
                if hubert_model is None:
         | 
| 23 | 
            +
                    print("Loading the HuBERT Model...")
         | 
| 24 | 
            +
                    if os.path.exists(local_path):
         | 
| 25 | 
            +
                        hubert_model = HubertModel.from_pretrained(local_path)
         | 
| 26 | 
            +
                    else:
         | 
| 27 | 
            +
                        hubert_model = HubertModel.from_pretrained("facebook/hubert-large-ls960-ft")
         | 
| 28 | 
            +
                hubert_model = hubert_model.to(device)
         | 
| 29 | 
            +
                if wav2vec2_processor is None:
         | 
| 30 | 
            +
                    print("Loading the Wav2Vec2 Processor...")
         | 
| 31 | 
            +
                    if os.path.exists(local_path):
         | 
| 32 | 
            +
                        wav2vec2_processor = Wav2Vec2Processor.from_pretrained(local_path)
         | 
| 33 | 
            +
                    else:
         | 
| 34 | 
            +
                        wav2vec2_processor = Wav2Vec2Processor.from_pretrained("facebook/hubert-large-ls960-ft")
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                if speech.ndim ==2:
         | 
| 37 | 
            +
                    speech = speech[:, 0] # [T, 2] ==> [T,]
         | 
| 38 | 
            +
                
         | 
| 39 | 
            +
                input_values_all = wav2vec2_processor(speech, return_tensors="pt", sampling_rate=16000).input_values # [1, T]
         | 
| 40 | 
            +
                input_values_all = input_values_all.to(device)
         | 
| 41 | 
            +
                # For long audio sequence, due to the memory limitation, we cannot process them in one run
         | 
| 42 | 
            +
                # HuBERT process the wav with a CNN of stride [5,2,2,2,2,2], making a stride of 320
         | 
| 43 | 
            +
                # Besides, the kernel is [10,3,3,3,3,2,2], making 400 a fundamental unit to get 1 time step.
         | 
| 44 | 
            +
                # So the CNN is euqal to a big Conv1D with kernel k=400 and stride s=320
         | 
| 45 | 
            +
                # We have the equation to calculate out time step: T = floor((t-k)/s)
         | 
| 46 | 
            +
                # To prevent overlap, we set each clip length of (K+S*(N-1)), where N is the expected length T of this clip
         | 
| 47 | 
            +
                # The start point of next clip should roll back with a length of (kernel-stride) so it is stride * N
         | 
| 48 | 
            +
                kernel = 400
         | 
| 49 | 
            +
                stride = 320
         | 
| 50 | 
            +
                clip_length = stride * 1000
         | 
| 51 | 
            +
                num_iter = input_values_all.shape[1] // clip_length
         | 
| 52 | 
            +
                expected_T = (input_values_all.shape[1] - (kernel-stride)) // stride
         | 
| 53 | 
            +
                res_lst = []
         | 
| 54 | 
            +
                for i in range(num_iter):
         | 
| 55 | 
            +
                    if i == 0:
         | 
| 56 | 
            +
                        start_idx = 0
         | 
| 57 | 
            +
                        end_idx = clip_length - stride + kernel
         | 
| 58 | 
            +
                    else:
         | 
| 59 | 
            +
                        start_idx = clip_length * i
         | 
| 60 | 
            +
                        end_idx = start_idx + (clip_length - stride + kernel)
         | 
| 61 | 
            +
                    input_values = input_values_all[:, start_idx: end_idx]
         | 
| 62 | 
            +
                    hidden_states = hubert_model.forward(input_values).last_hidden_state # [B=1, T=pts//320, hid=1024]
         | 
| 63 | 
            +
                    res_lst.append(hidden_states[0])
         | 
| 64 | 
            +
                if num_iter > 0:
         | 
| 65 | 
            +
                    input_values = input_values_all[:, clip_length * num_iter:]
         | 
| 66 | 
            +
                else:
         | 
| 67 | 
            +
                    input_values = input_values_all
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                if input_values.shape[1] >= kernel: # if the last batch is shorter than kernel_size, skip it            
         | 
| 70 | 
            +
                    hidden_states = hubert_model(input_values).last_hidden_state # [B=1, T=pts//320, hid=1024]
         | 
| 71 | 
            +
                    res_lst.append(hidden_states[0])
         | 
| 72 | 
            +
                ret = torch.cat(res_lst, dim=0).cpu() # [T, 1024]
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                assert abs(ret.shape[0] - expected_T) <= 1
         | 
| 75 | 
            +
                if ret.shape[0] < expected_T: # if skipping the last short 
         | 
| 76 | 
            +
                    ret = torch.cat([ret, ret[:, -1:, :].repeat([1,expected_T-ret.shape[0],1])], dim=1)
         | 
| 77 | 
            +
                else:
         | 
| 78 | 
            +
                    ret = ret[:expected_T]
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                return ret
         | 
| 81 | 
            +
             | 
| 82 | 
            +
             | 
| 83 | 
            +
            if __name__ == '__main__':
         | 
| 84 | 
            +
                from argparse import ArgumentParser
         | 
| 85 | 
            +
                parser = ArgumentParser()
         | 
| 86 | 
            +
                parser.add_argument('--video_id', type=str, default='May', help='')
         | 
| 87 | 
            +
                args = parser.parse_args()
         | 
| 88 | 
            +
                ### Process Single Long Audio for NeRF dataset
         | 
| 89 | 
            +
                person_id = args.video_id
         | 
| 90 | 
            +
                wav_16k_name = f"data/processed/videos/{person_id}/aud.wav"
         | 
| 91 | 
            +
                hubert_npy_name = f"data/processed/videos/{person_id}/aud_hubert.npy"
         | 
| 92 | 
            +
                speech_16k, _ = sf.read(wav_16k_name)
         | 
| 93 | 
            +
                hubert_hidden = get_hubert_from_16k_speech(speech_16k)
         | 
| 94 | 
            +
                np.save(hubert_npy_name, hubert_hidden.detach().numpy())
         | 
| 95 | 
            +
                print(f"Saved at {hubert_npy_name}")
         | 
    	
        data_gen/utils/process_audio/extract_mel_f0.py
    ADDED
    
    | @@ -0,0 +1,148 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import numpy as np
         | 
| 2 | 
            +
            import torch
         | 
| 3 | 
            +
            import glob
         | 
| 4 | 
            +
            import os
         | 
| 5 | 
            +
            import tqdm
         | 
| 6 | 
            +
            import librosa
         | 
| 7 | 
            +
            import parselmouth
         | 
| 8 | 
            +
            from utils.commons.pitch_utils import f0_to_coarse
         | 
| 9 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 10 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 11 | 
            +
            from utils.audio.io import save_wav
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            from moviepy.editor import VideoFileClip
         | 
| 14 | 
            +
            from utils.commons.hparams import hparams, set_hparams
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            def resample_wav(wav_name, out_name, sr=16000):
         | 
| 17 | 
            +
                wav_raw, sr = librosa.core.load(wav_name, sr=sr)
         | 
| 18 | 
            +
                save_wav(wav_raw, out_name, sr)
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
            def split_wav(mp4_name, wav_name=None):
         | 
| 21 | 
            +
                if wav_name is None:
         | 
| 22 | 
            +
                    wav_name = mp4_name.replace(".mp4", ".wav").replace("/video/", "/audio/")
         | 
| 23 | 
            +
                if os.path.exists(wav_name):
         | 
| 24 | 
            +
                    return wav_name
         | 
| 25 | 
            +
                os.makedirs(os.path.dirname(wav_name), exist_ok=True)
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                video = VideoFileClip(mp4_name,verbose=False)
         | 
| 28 | 
            +
                dur = video.duration
         | 
| 29 | 
            +
                audio = video.audio 
         | 
| 30 | 
            +
                assert audio is not None
         | 
| 31 | 
            +
                audio.write_audiofile(wav_name,fps=16000,verbose=False,logger=None)
         | 
| 32 | 
            +
                return wav_name
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            def librosa_pad_lr(x, fsize, fshift, pad_sides=1):
         | 
| 35 | 
            +
                '''compute right padding (final frame) or both sides padding (first and final frames)
         | 
| 36 | 
            +
                '''
         | 
| 37 | 
            +
                assert pad_sides in (1, 2)
         | 
| 38 | 
            +
                # return int(fsize // 2)
         | 
| 39 | 
            +
                pad = (x.shape[0] // fshift + 1) * fshift - x.shape[0]
         | 
| 40 | 
            +
                if pad_sides == 1:
         | 
| 41 | 
            +
                    return 0, pad
         | 
| 42 | 
            +
                else:
         | 
| 43 | 
            +
                    return pad // 2, pad // 2 + pad % 2
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            def extract_mel_from_fname(wav_path,
         | 
| 46 | 
            +
                                  fft_size=512,
         | 
| 47 | 
            +
                                  hop_size=320,
         | 
| 48 | 
            +
                                  win_length=512,
         | 
| 49 | 
            +
                                  window="hann",
         | 
| 50 | 
            +
                                  num_mels=80,
         | 
| 51 | 
            +
                                  fmin=80,
         | 
| 52 | 
            +
                                  fmax=7600,
         | 
| 53 | 
            +
                                  eps=1e-6,
         | 
| 54 | 
            +
                                  sample_rate=16000,
         | 
| 55 | 
            +
                                  min_level_db=-100):
         | 
| 56 | 
            +
                if isinstance(wav_path, str):
         | 
| 57 | 
            +
                    wav, _ = librosa.core.load(wav_path, sr=sample_rate)
         | 
| 58 | 
            +
                else:
         | 
| 59 | 
            +
                    wav = wav_path
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # get amplitude spectrogram
         | 
| 62 | 
            +
                x_stft = librosa.stft(wav, n_fft=fft_size, hop_length=hop_size,
         | 
| 63 | 
            +
                                      win_length=win_length, window=window, center=False)
         | 
| 64 | 
            +
                spc = np.abs(x_stft)  # (n_bins, T)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                # get mel basis
         | 
| 67 | 
            +
                fmin = 0 if fmin == -1 else fmin
         | 
| 68 | 
            +
                fmax = sample_rate / 2 if fmax == -1 else fmax
         | 
| 69 | 
            +
                mel_basis = librosa.filters.mel(sr=sample_rate, n_fft=fft_size, n_mels=num_mels, fmin=fmin, fmax=fmax)
         | 
| 70 | 
            +
                mel = mel_basis @ spc
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                mel = np.log10(np.maximum(eps, mel))  # (n_mel_bins, T)
         | 
| 73 | 
            +
                mel = mel.T
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                l_pad, r_pad = librosa_pad_lr(wav, fft_size, hop_size, 1)
         | 
| 76 | 
            +
                wav = np.pad(wav, (l_pad, r_pad), mode='constant', constant_values=0.0)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                return wav.T, mel
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            def extract_f0_from_wav_and_mel(wav, mel,
         | 
| 81 | 
            +
                                    hop_size=320,
         | 
| 82 | 
            +
                                    audio_sample_rate=16000,
         | 
| 83 | 
            +
                                    ):
         | 
| 84 | 
            +
                time_step = hop_size / audio_sample_rate * 1000
         | 
| 85 | 
            +
                f0_min = 80
         | 
| 86 | 
            +
                f0_max = 750
         | 
| 87 | 
            +
                f0 = parselmouth.Sound(wav, audio_sample_rate).to_pitch_ac(
         | 
| 88 | 
            +
                    time_step=time_step / 1000, voicing_threshold=0.6,
         | 
| 89 | 
            +
                    pitch_floor=f0_min, pitch_ceiling=f0_max).selected_array['frequency']
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                delta_l = len(mel) - len(f0)
         | 
| 92 | 
            +
                assert np.abs(delta_l) <= 8
         | 
| 93 | 
            +
                if delta_l > 0:
         | 
| 94 | 
            +
                    f0 = np.concatenate([f0, [f0[-1]] * delta_l], 0)
         | 
| 95 | 
            +
                f0 = f0[:len(mel)]
         | 
| 96 | 
            +
                pitch_coarse = f0_to_coarse(f0)
         | 
| 97 | 
            +
                return f0, pitch_coarse
         | 
| 98 | 
            +
             | 
| 99 | 
            +
             | 
| 100 | 
            +
            def extract_mel_f0_from_fname(wav_name=None, out_name=None):
         | 
| 101 | 
            +
                try:
         | 
| 102 | 
            +
                    out_name = wav_name.replace(".wav", "_mel_f0.npy").replace("/audio/", "/mel_f0/")
         | 
| 103 | 
            +
                    os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                    wav, mel = extract_mel_from_fname(wav_name)
         | 
| 106 | 
            +
                    f0, f0_coarse = extract_f0_from_wav_and_mel(wav, mel)
         | 
| 107 | 
            +
                    out_dict = {
         | 
| 108 | 
            +
                        "mel": mel, # [T, 80]
         | 
| 109 | 
            +
                        "f0": f0,
         | 
| 110 | 
            +
                    }
         | 
| 111 | 
            +
                    np.save(out_name, out_dict)
         | 
| 112 | 
            +
                except Exception as e:
         | 
| 113 | 
            +
                    print(e)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            def extract_mel_f0_from_video_name(mp4_name, wav_name=None, out_name=None):
         | 
| 116 | 
            +
                if mp4_name.endswith(".mp4"):
         | 
| 117 | 
            +
                    wav_name = split_wav(mp4_name, wav_name)
         | 
| 118 | 
            +
                    if out_name is None:
         | 
| 119 | 
            +
                        out_name = mp4_name.replace(".mp4", "_mel_f0.npy").replace("/video/", "/mel_f0/")
         | 
| 120 | 
            +
                elif mp4_name.endswith(".wav"):
         | 
| 121 | 
            +
                    wav_name = mp4_name
         | 
| 122 | 
            +
                    if out_name is None:
         | 
| 123 | 
            +
                        out_name = mp4_name.replace(".wav", "_mel_f0.npy").replace("/audio/", "/mel_f0/")
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                wav, mel = extract_mel_from_fname(wav_name)
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                f0, f0_coarse = extract_f0_from_wav_and_mel(wav, mel)
         | 
| 130 | 
            +
                out_dict = {
         | 
| 131 | 
            +
                    "mel": mel, # [T, 80]
         | 
| 132 | 
            +
                    "f0": f0,
         | 
| 133 | 
            +
                }
         | 
| 134 | 
            +
                np.save(out_name, out_dict)
         | 
| 135 | 
            +
             | 
| 136 | 
            +
             | 
| 137 | 
            +
            if __name__ == '__main__':
         | 
| 138 | 
            +
                from argparse import ArgumentParser
         | 
| 139 | 
            +
                parser = ArgumentParser()
         | 
| 140 | 
            +
                parser.add_argument('--video_id', type=str, default='May', help='')
         | 
| 141 | 
            +
                args = parser.parse_args()
         | 
| 142 | 
            +
                ### Process Single Long Audio for NeRF dataset
         | 
| 143 | 
            +
                person_id = args.video_id
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                wav_16k_name = f"data/processed/videos/{person_id}/aud.wav"
         | 
| 146 | 
            +
                out_name = f"data/processed/videos/{person_id}/aud_mel_f0.npy"
         | 
| 147 | 
            +
                extract_mel_f0_from_video_name(wav_16k_name, out_name)
         | 
| 148 | 
            +
                print(f"Saved at {out_name}")
         | 
    	
        data_gen/utils/process_audio/resample_audio_to_16k.py
    ADDED
    
    | @@ -0,0 +1,49 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os, glob
         | 
| 2 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 3 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 4 | 
            +
             | 
| 5 | 
            +
             | 
| 6 | 
            +
            def extract_wav16k_job(audio_name:str):
         | 
| 7 | 
            +
                out_path = audio_name.replace("/audio_raw/","/audio/",1)
         | 
| 8 | 
            +
                assert out_path != audio_name # prevent inplace
         | 
| 9 | 
            +
                os.makedirs(os.path.dirname(out_path), exist_ok=True)
         | 
| 10 | 
            +
                ffmpeg_path = "/usr/bin/ffmpeg"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                cmd = f'{ffmpeg_path} -i {audio_name} -ar 16000 -v quiet -y {out_path}'
         | 
| 13 | 
            +
                os.system(cmd)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            if __name__ == '__main__':
         | 
| 16 | 
            +
                import argparse, glob, tqdm, random
         | 
| 17 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 18 | 
            +
                parser.add_argument("--aud_dir", default='/home/tiger/datasets/raw/CMLR/audio_raw/')
         | 
| 19 | 
            +
                parser.add_argument("--ds_name", default='CMLR')
         | 
| 20 | 
            +
                parser.add_argument("--num_workers", default=64, type=int)
         | 
| 21 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 22 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 23 | 
            +
                args = parser.parse_args()
         | 
| 24 | 
            +
                print(f"args {args}")
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                aud_dir = args.aud_dir
         | 
| 27 | 
            +
                ds_name = args.ds_name
         | 
| 28 | 
            +
                if ds_name in ['CMLR']:
         | 
| 29 | 
            +
                    aud_name_pattern = os.path.join(aud_dir, "*/*/*.wav")
         | 
| 30 | 
            +
                    aud_names = multiprocess_glob(aud_name_pattern)
         | 
| 31 | 
            +
                else:
         | 
| 32 | 
            +
                    raise NotImplementedError()
         | 
| 33 | 
            +
                aud_names = sorted(aud_names)
         | 
| 34 | 
            +
                print(f"total audio number : {len(aud_names)}")
         | 
| 35 | 
            +
                print(f"first {aud_names[0]} last {aud_names[-1]}")
         | 
| 36 | 
            +
                # exit()
         | 
| 37 | 
            +
                process_id = args.process_id
         | 
| 38 | 
            +
                total_process = args.total_process
         | 
| 39 | 
            +
                if total_process > 1:
         | 
| 40 | 
            +
                    assert process_id <= total_process -1
         | 
| 41 | 
            +
                    num_samples_per_process = len(aud_names) // total_process
         | 
| 42 | 
            +
                    if process_id == total_process:
         | 
| 43 | 
            +
                        aud_names = aud_names[process_id * num_samples_per_process : ]
         | 
| 44 | 
            +
                    else:
         | 
| 45 | 
            +
                        aud_names = aud_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                for i, res in multiprocess_run_tqdm(extract_wav16k_job, aud_names, num_workers=args.num_workers, desc="resampling videos"):
         | 
| 48 | 
            +
                    pass
         | 
| 49 | 
            +
             | 
    	
        data_gen/utils/process_image/extract_lm2d.py
    ADDED
    
    | @@ -0,0 +1,197 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            os.environ["OMP_NUM_THREADS"] = "1"
         | 
| 3 | 
            +
            import sys
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            import glob
         | 
| 6 | 
            +
            import cv2
         | 
| 7 | 
            +
            import tqdm
         | 
| 8 | 
            +
            import numpy as np
         | 
| 9 | 
            +
            from data_gen.utils.mp_feature_extractors.face_landmarker import MediapipeLandmarker
         | 
| 10 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 11 | 
            +
            import warnings
         | 
| 12 | 
            +
            warnings.filterwarnings('ignore')
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            import random
         | 
| 15 | 
            +
            random.seed(42)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            import pickle
         | 
| 18 | 
            +
            import json
         | 
| 19 | 
            +
            import gzip
         | 
| 20 | 
            +
            from typing import Any
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            def load_file(filename, is_gzip: bool = False, is_json: bool = False) -> Any:
         | 
| 23 | 
            +
                if is_json:
         | 
| 24 | 
            +
                    if is_gzip:
         | 
| 25 | 
            +
                        with gzip.open(filename, "r", encoding="utf-8") as f:
         | 
| 26 | 
            +
                            loaded_object = json.load(f)
         | 
| 27 | 
            +
                            return loaded_object
         | 
| 28 | 
            +
                    else:
         | 
| 29 | 
            +
                        with open(filename, "r", encoding="utf-8") as f:
         | 
| 30 | 
            +
                            loaded_object = json.load(f)
         | 
| 31 | 
            +
                            return loaded_object
         | 
| 32 | 
            +
                else:
         | 
| 33 | 
            +
                    if is_gzip:
         | 
| 34 | 
            +
                        with gzip.open(filename, "rb") as f:
         | 
| 35 | 
            +
                            loaded_object = pickle.load(f)
         | 
| 36 | 
            +
                            return loaded_object
         | 
| 37 | 
            +
                    else:
         | 
| 38 | 
            +
                        with open(filename, "rb") as f:
         | 
| 39 | 
            +
                            loaded_object = pickle.load(f)
         | 
| 40 | 
            +
                            return loaded_object
         | 
| 41 | 
            +
                    
         | 
| 42 | 
            +
            def save_file(filename, content, is_gzip: bool = False, is_json: bool = False) -> None:
         | 
| 43 | 
            +
                if is_json:
         | 
| 44 | 
            +
                    if is_gzip:
         | 
| 45 | 
            +
                        with gzip.open(filename, "w", encoding="utf-8") as f:
         | 
| 46 | 
            +
                            json.dump(content, f)
         | 
| 47 | 
            +
                    else:
         | 
| 48 | 
            +
                        with open(filename, "w", encoding="utf-8") as f:
         | 
| 49 | 
            +
                            json.dump(content, f)
         | 
| 50 | 
            +
                else:
         | 
| 51 | 
            +
                    if is_gzip:
         | 
| 52 | 
            +
                        with gzip.open(filename, "wb") as f:
         | 
| 53 | 
            +
                            pickle.dump(content, f)
         | 
| 54 | 
            +
                    else:
         | 
| 55 | 
            +
                        with open(filename, "wb") as f:
         | 
| 56 | 
            +
                            pickle.dump(content, f)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            face_landmarker = None
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            def extract_lms_mediapipe_job(img):
         | 
| 61 | 
            +
                if img is None:
         | 
| 62 | 
            +
                    return None
         | 
| 63 | 
            +
                global face_landmarker
         | 
| 64 | 
            +
                if face_landmarker is None:
         | 
| 65 | 
            +
                    face_landmarker = MediapipeLandmarker()
         | 
| 66 | 
            +
                lm478 = face_landmarker.extract_lm478_from_img(img)
         | 
| 67 | 
            +
                return lm478
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
            def extract_landmark_job(img_name):
         | 
| 70 | 
            +
                try:
         | 
| 71 | 
            +
                    # if img_name == 'datasets/PanoHeadGen/raw/images/multi_view/chunk_0/seed0000002.png':
         | 
| 72 | 
            +
                        # print(1)
         | 
| 73 | 
            +
                        # input()
         | 
| 74 | 
            +
                    out_name = img_name.replace("/images_512/", "/lms_2d/").replace(".png","_lms.npy")
         | 
| 75 | 
            +
                    if os.path.exists(out_name):
         | 
| 76 | 
            +
                        print("out exists, skip...")
         | 
| 77 | 
            +
                        return
         | 
| 78 | 
            +
                    try:
         | 
| 79 | 
            +
                        os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 80 | 
            +
                    except:
         | 
| 81 | 
            +
                        pass
         | 
| 82 | 
            +
                    img = cv2.imread(img_name)[:,:,::-1]
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    if img is not None:
         | 
| 85 | 
            +
                        lm468 = extract_lms_mediapipe_job(img)
         | 
| 86 | 
            +
                        if lm468 is not None:
         | 
| 87 | 
            +
                            np.save(out_name, lm468)
         | 
| 88 | 
            +
                    # print("Hahaha, solve one item!!!")
         | 
| 89 | 
            +
                except Exception as e:
         | 
| 90 | 
            +
                    print(e)
         | 
| 91 | 
            +
                    pass
         | 
| 92 | 
            +
                    
         | 
| 93 | 
            +
            def out_exist_job(img_name):
         | 
| 94 | 
            +
                out_name = img_name.replace("/images_512/", "/lms_2d/").replace(".png","_lms.npy") 
         | 
| 95 | 
            +
                if  os.path.exists(out_name):
         | 
| 96 | 
            +
                    return None
         | 
| 97 | 
            +
                else:
         | 
| 98 | 
            +
                    return img_name
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            # def get_todo_img_names(img_names):
         | 
| 101 | 
            +
            #     todo_img_names = []
         | 
| 102 | 
            +
            #     for i, res in multiprocess_run_tqdm(out_exist_job, img_names, num_workers=64):
         | 
| 103 | 
            +
            #         if res is not None:
         | 
| 104 | 
            +
            #             todo_img_names.append(res)
         | 
| 105 | 
            +
            #     return todo_img_names
         | 
| 106 | 
            +
             | 
| 107 | 
            +
             | 
| 108 | 
            +
            if __name__ == '__main__':
         | 
| 109 | 
            +
                import argparse, glob, tqdm, random
         | 
| 110 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 111 | 
            +
                parser.add_argument("--img_dir", default='/home/tiger/datasets/raw/FFHQ/images_512/')
         | 
| 112 | 
            +
                parser.add_argument("--ds_name", default='FFHQ')
         | 
| 113 | 
            +
                parser.add_argument("--num_workers", default=64, type=int)
         | 
| 114 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 115 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 116 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 117 | 
            +
                parser.add_argument("--img_names_file", default="img_names.pkl", type=str)
         | 
| 118 | 
            +
                parser.add_argument("--load_img_names", action="store_true")
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                args = parser.parse_args()
         | 
| 121 | 
            +
                print(f"args {args}")
         | 
| 122 | 
            +
                img_dir = args.img_dir
         | 
| 123 | 
            +
                img_names_file = os.path.join(img_dir, args.img_names_file)
         | 
| 124 | 
            +
                if args.load_img_names:
         | 
| 125 | 
            +
                    img_names = load_file(img_names_file)
         | 
| 126 | 
            +
                    print(f"load image names from {img_names_file}")
         | 
| 127 | 
            +
                else:
         | 
| 128 | 
            +
                    if args.ds_name == 'FFHQ_MV':
         | 
| 129 | 
            +
                        img_name_pattern1 = os.path.join(img_dir, "ref_imgs/*.png")
         | 
| 130 | 
            +
                        img_names1 = glob.glob(img_name_pattern1)
         | 
| 131 | 
            +
                        img_name_pattern2 = os.path.join(img_dir, "mv_imgs/*.png")
         | 
| 132 | 
            +
                        img_names2 = glob.glob(img_name_pattern2)
         | 
| 133 | 
            +
                        img_names = img_names1 + img_names2
         | 
| 134 | 
            +
                        img_names = sorted(img_names)
         | 
| 135 | 
            +
                    elif args.ds_name == 'FFHQ':
         | 
| 136 | 
            +
                        img_name_pattern = os.path.join(img_dir, "*.png")
         | 
| 137 | 
            +
                        img_names = glob.glob(img_name_pattern)
         | 
| 138 | 
            +
                        img_names = sorted(img_names)
         | 
| 139 | 
            +
                    elif args.ds_name == "PanoHeadGen":
         | 
| 140 | 
            +
                        # img_name_patterns = ["ref/*/*.png", "multi_view/*/*.png", "reverse/*/*.png"]
         | 
| 141 | 
            +
                        img_name_patterns = ["ref/*/*.png"]
         | 
| 142 | 
            +
                        img_names = []
         | 
| 143 | 
            +
                        for img_name_pattern in img_name_patterns:
         | 
| 144 | 
            +
                            img_name_pattern_full = os.path.join(img_dir, img_name_pattern)
         | 
| 145 | 
            +
                            img_names_part = glob.glob(img_name_pattern_full)
         | 
| 146 | 
            +
                            img_names.extend(img_names_part)
         | 
| 147 | 
            +
                        img_names = sorted(img_names)
         | 
| 148 | 
            +
                    
         | 
| 149 | 
            +
                # save image names
         | 
| 150 | 
            +
                if not args.load_img_names:
         | 
| 151 | 
            +
                    save_file(img_names_file, img_names)
         | 
| 152 | 
            +
                    print(f"save image names in {img_names_file}")
         | 
| 153 | 
            +
                    
         | 
| 154 | 
            +
                print(f"total images number: {len(img_names)}")
         | 
| 155 | 
            +
                    
         | 
| 156 | 
            +
                    
         | 
| 157 | 
            +
                process_id = args.process_id
         | 
| 158 | 
            +
                total_process = args.total_process
         | 
| 159 | 
            +
                if total_process > 1:
         | 
| 160 | 
            +
                    assert process_id <= total_process -1
         | 
| 161 | 
            +
                    num_samples_per_process = len(img_names) // total_process
         | 
| 162 | 
            +
                    if process_id == total_process:
         | 
| 163 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : ]
         | 
| 164 | 
            +
                    else:
         | 
| 165 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 166 | 
            +
                
         | 
| 167 | 
            +
                # if not args.reset:
         | 
| 168 | 
            +
                    # img_names = get_todo_img_names(img_names)
         | 
| 169 | 
            +
                    
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                print(f"todo_image {img_names[:10]}")
         | 
| 172 | 
            +
                print(f"processing images number in this process: {len(img_names)}")
         | 
| 173 | 
            +
                # print(f"todo images number: {len(img_names)}")
         | 
| 174 | 
            +
                # input()
         | 
| 175 | 
            +
                # exit()
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                if args.num_workers == 1:
         | 
| 178 | 
            +
                    index = 0
         | 
| 179 | 
            +
                    for img_name in tqdm.tqdm(img_names, desc=f"Root process {args.process_id}: extracting MP-based landmark2d"):
         | 
| 180 | 
            +
                        try:
         | 
| 181 | 
            +
                            extract_landmark_job(img_name)
         | 
| 182 | 
            +
                        except Exception as e:
         | 
| 183 | 
            +
                            print(e)
         | 
| 184 | 
            +
                            pass
         | 
| 185 | 
            +
                        if index % max(1, int(len(img_names) * 0.003)) == 0:
         | 
| 186 | 
            +
                            print(f"processed {index} / {len(img_names)}")
         | 
| 187 | 
            +
                            sys.stdout.flush()
         | 
| 188 | 
            +
                        index += 1
         | 
| 189 | 
            +
                else:
         | 
| 190 | 
            +
                    for i, res in multiprocess_run_tqdm(
         | 
| 191 | 
            +
                        extract_landmark_job, img_names, 
         | 
| 192 | 
            +
                        num_workers=args.num_workers, 
         | 
| 193 | 
            +
                        desc=f"Root {args.process_id}: extracing MP-based landmark2d"): 
         | 
| 194 | 
            +
                        # if index % max(1, int(len(img_names) * 0.003)) == 0:
         | 
| 195 | 
            +
                        print(f"processed {i+1} / {len(img_names)}")
         | 
| 196 | 
            +
                        sys.stdout.flush()
         | 
| 197 | 
            +
                    print(f"Root {args.process_id}: Finished extracting.")
         | 
    	
        data_gen/utils/process_image/extract_segment_imgs.py
    ADDED
    
    | @@ -0,0 +1,114 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            os.environ["OMP_NUM_THREADS"] = "1"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            import glob
         | 
| 5 | 
            +
            import cv2
         | 
| 6 | 
            +
            import tqdm
         | 
| 7 | 
            +
            import numpy as np
         | 
| 8 | 
            +
            import PIL
         | 
| 9 | 
            +
            from utils.commons.tensor_utils import convert_to_np
         | 
| 10 | 
            +
            import torch
         | 
| 11 | 
            +
            import mediapipe as mp
         | 
| 12 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 13 | 
            +
            from data_gen.utils.mp_feature_extractors.mp_segmenter import MediapipeSegmenter
         | 
| 14 | 
            +
            from data_gen.utils.process_video.extract_segment_imgs import inpaint_torso_job, extract_background, save_rgb_image_to_path
         | 
| 15 | 
            +
            seg_model = MediapipeSegmenter()
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            def extract_segment_job(img_name):
         | 
| 19 | 
            +
                try:
         | 
| 20 | 
            +
                    img = cv2.imread(img_name)
         | 
| 21 | 
            +
                    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    segmap = seg_model._cal_seg_map(img)
         | 
| 24 | 
            +
                    bg_img = extract_background([img], [segmap])
         | 
| 25 | 
            +
                    out_img_name = img_name.replace("/images_512/",f"/bg_img/").replace(".mp4", ".jpg")
         | 
| 26 | 
            +
                    save_rgb_image_to_path(bg_img, out_img_name)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    com_img = img.copy()
         | 
| 29 | 
            +
                    bg_part = segmap[0].astype(bool)[..., None].repeat(3,axis=-1)
         | 
| 30 | 
            +
                    com_img[bg_part] = bg_img[bg_part]
         | 
| 31 | 
            +
                    out_img_name = img_name.replace("/images_512/",f"/com_imgs/")
         | 
| 32 | 
            +
                    save_rgb_image_to_path(com_img, out_img_name)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    for mode in ['head', 'torso', 'person', 'torso_with_bg', 'bg']:
         | 
| 35 | 
            +
                        out_img, _ = seg_model._seg_out_img_with_segmap(img, segmap, mode=mode)
         | 
| 36 | 
            +
                        out_img_name = img_name.replace("/images_512/",f"/{mode}_imgs/")
         | 
| 37 | 
            +
                        out_img = cv2.cvtColor(out_img, cv2.COLOR_RGB2BGR)
         | 
| 38 | 
            +
                        try: os.makedirs(os.path.dirname(out_img_name), exist_ok=True)
         | 
| 39 | 
            +
                        except: pass
         | 
| 40 | 
            +
                        cv2.imwrite(out_img_name, out_img)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    inpaint_torso_img, inpaint_torso_with_bg_img, _, _ = inpaint_torso_job(img, segmap)
         | 
| 43 | 
            +
                    out_img_name = img_name.replace("/images_512/",f"/inpaint_torso_imgs/")
         | 
| 44 | 
            +
                    save_rgb_image_to_path(inpaint_torso_img, out_img_name)
         | 
| 45 | 
            +
                    inpaint_torso_with_bg_img[bg_part] = bg_img[bg_part]
         | 
| 46 | 
            +
                    out_img_name = img_name.replace("/images_512/",f"/inpaint_torso_with_com_bg_imgs/")
         | 
| 47 | 
            +
                    save_rgb_image_to_path(inpaint_torso_with_bg_img, out_img_name)
         | 
| 48 | 
            +
                    return 0
         | 
| 49 | 
            +
                except Exception as e:
         | 
| 50 | 
            +
                    print(e)
         | 
| 51 | 
            +
                    return 1
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            def out_exist_job(img_name):
         | 
| 54 | 
            +
                out_name1 = img_name.replace("/images_512/", "/head_imgs/")
         | 
| 55 | 
            +
                out_name2 = img_name.replace("/images_512/", "/com_imgs/")
         | 
| 56 | 
            +
                out_name3 = img_name.replace("/images_512/", "/inpaint_torso_with_com_bg_imgs/")
         | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                if  os.path.exists(out_name1) and os.path.exists(out_name2) and os.path.exists(out_name3):
         | 
| 59 | 
            +
                    return None
         | 
| 60 | 
            +
                else:
         | 
| 61 | 
            +
                    return img_name
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            def get_todo_img_names(img_names):
         | 
| 64 | 
            +
                todo_img_names = []
         | 
| 65 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, img_names, num_workers=64):
         | 
| 66 | 
            +
                    if res is not None:
         | 
| 67 | 
            +
                        todo_img_names.append(res)
         | 
| 68 | 
            +
                return todo_img_names
         | 
| 69 | 
            +
             | 
| 70 | 
            +
             | 
| 71 | 
            +
            if __name__ == '__main__':
         | 
| 72 | 
            +
                import argparse, glob, tqdm, random
         | 
| 73 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 74 | 
            +
                parser.add_argument("--img_dir", default='./images_512')
         | 
| 75 | 
            +
                # parser.add_argument("--img_dir", default='/home/tiger/datasets/raw/FFHQ/images_512')
         | 
| 76 | 
            +
                parser.add_argument("--ds_name", default='FFHQ')
         | 
| 77 | 
            +
                parser.add_argument("--num_workers", default=1, type=int)
         | 
| 78 | 
            +
                parser.add_argument("--seed", default=0, type=int)
         | 
| 79 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 80 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 81 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                args = parser.parse_args()
         | 
| 84 | 
            +
                img_dir = args.img_dir
         | 
| 85 | 
            +
                if args.ds_name == 'FFHQ_MV':
         | 
| 86 | 
            +
                    img_name_pattern1 = os.path.join(img_dir, "ref_imgs/*.png")
         | 
| 87 | 
            +
                    img_names1 = glob.glob(img_name_pattern1)
         | 
| 88 | 
            +
                    img_name_pattern2 = os.path.join(img_dir, "mv_imgs/*.png")
         | 
| 89 | 
            +
                    img_names2 = glob.glob(img_name_pattern2)
         | 
| 90 | 
            +
                    img_names = img_names1 + img_names2
         | 
| 91 | 
            +
                elif args.ds_name == 'FFHQ':
         | 
| 92 | 
            +
                    img_name_pattern = os.path.join(img_dir, "*.png")
         | 
| 93 | 
            +
                    img_names = glob.glob(img_name_pattern)
         | 
| 94 | 
            +
                
         | 
| 95 | 
            +
                img_names = sorted(img_names)
         | 
| 96 | 
            +
                random.seed(args.seed)
         | 
| 97 | 
            +
                random.shuffle(img_names)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                process_id = args.process_id
         | 
| 100 | 
            +
                total_process = args.total_process
         | 
| 101 | 
            +
                if total_process > 1:
         | 
| 102 | 
            +
                    assert process_id <= total_process -1
         | 
| 103 | 
            +
                    num_samples_per_process = len(img_names) // total_process
         | 
| 104 | 
            +
                    if process_id == total_process:
         | 
| 105 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : ]
         | 
| 106 | 
            +
                    else:
         | 
| 107 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 108 | 
            +
                
         | 
| 109 | 
            +
                if not args.reset:
         | 
| 110 | 
            +
                    img_names = get_todo_img_names(img_names)
         | 
| 111 | 
            +
                print(f"todo images number: {len(img_names)}")
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                for vid_name in multiprocess_run_tqdm(extract_segment_job ,img_names, desc=f"Root process {args.process_id}: extracting segment images", num_workers=args.num_workers):
         | 
| 114 | 
            +
                    pass
         | 
    	
        data_gen/utils/process_image/fit_3dmm_landmark.py
    ADDED
    
    | @@ -0,0 +1,369 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            from numpy.core.numeric import require
         | 
| 2 | 
            +
            from numpy.lib.function_base import quantile
         | 
| 3 | 
            +
            import torch
         | 
| 4 | 
            +
            import torch.nn.functional as F
         | 
| 5 | 
            +
            import copy
         | 
| 6 | 
            +
            import numpy as np
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            import os
         | 
| 9 | 
            +
            import sys
         | 
| 10 | 
            +
            import cv2
         | 
| 11 | 
            +
            import argparse
         | 
| 12 | 
            +
            import tqdm
         | 
| 13 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 14 | 
            +
            from data_gen.utils.mp_feature_extractors.face_landmarker import MediapipeLandmarker
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            from deep_3drecon.deep_3drecon_models.bfm import ParametricFaceModel
         | 
| 17 | 
            +
            import pickle
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            face_model = ParametricFaceModel(bfm_folder='deep_3drecon/BFM', 
         | 
| 20 | 
            +
                        camera_distance=10, focal=1015, keypoint_mode='mediapipe')
         | 
| 21 | 
            +
            face_model.to("cuda")
         | 
| 22 | 
            +
                 
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            index_lm68_from_lm468 = [127,234,93,132,58,136,150,176,152,400,379,365,288,361,323,454,356,70,63,105,66,107,336,296,334,293,300,168,197,5,4,75,97,2,326,305,
         | 
| 25 | 
            +
                                     33,160,158,133,153,144,362,385,387,263,373,380,61,40,37,0,267,270,291,321,314,17,84,91,78,81,13,311,308,402,14,178]
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            dir_path = os.path.dirname(os.path.realpath(__file__))
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            LAMBDA_REG_ID = 0.3
         | 
| 30 | 
            +
            LAMBDA_REG_EXP = 0.05
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            def save_file(name, content):
         | 
| 33 | 
            +
                with open(name, "wb") as f:
         | 
| 34 | 
            +
                    pickle.dump(content, f) 
         | 
| 35 | 
            +
                    
         | 
| 36 | 
            +
            def load_file(name):
         | 
| 37 | 
            +
                with open(name, "rb") as f:
         | 
| 38 | 
            +
                    content = pickle.load(f)
         | 
| 39 | 
            +
                return content
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            def cal_lan_loss_mp(proj_lan, gt_lan):
         | 
| 42 | 
            +
                # [B, 68, 2]
         | 
| 43 | 
            +
                loss = (proj_lan - gt_lan).pow(2)
         | 
| 44 | 
            +
                # loss = (proj_lan - gt_lan).abs()
         | 
| 45 | 
            +
                unmatch_mask = [ 93, 127, 132, 234, 323, 356, 361, 454]
         | 
| 46 | 
            +
                eye = [33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7] + [263,466,388,387,386,385,384,398,362,382,381,380,374,373,390,249]
         | 
| 47 | 
            +
                inner_lip = [78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95]
         | 
| 48 | 
            +
                outer_lip = [61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146]
         | 
| 49 | 
            +
                weights = torch.ones_like(loss)
         | 
| 50 | 
            +
                weights[:, eye] = 5
         | 
| 51 | 
            +
                weights[:, inner_lip] = 2
         | 
| 52 | 
            +
                weights[:, outer_lip] = 2
         | 
| 53 | 
            +
                weights[:, unmatch_mask] = 0
         | 
| 54 | 
            +
                loss = loss * weights
         | 
| 55 | 
            +
                return torch.mean(loss)
         | 
| 56 | 
            +
             
         | 
| 57 | 
            +
            def cal_lan_loss(proj_lan, gt_lan):
         | 
| 58 | 
            +
                # [B, 68, 2]
         | 
| 59 | 
            +
                loss = (proj_lan - gt_lan)** 2
         | 
| 60 | 
            +
                # use the ldm weights from deep3drecon, see deep_3drecon/deep_3drecon_models/losses.py
         | 
| 61 | 
            +
                weights = torch.zeros_like(loss)
         | 
| 62 | 
            +
                weights = torch.ones_like(loss)
         | 
| 63 | 
            +
                weights[:, 36:48, :] = 3 # eye 12 points
         | 
| 64 | 
            +
                weights[:, -8:, :] =  3 # inner lip 8 points
         | 
| 65 | 
            +
                weights[:, 28:31, :] =  3 # nose 3 points
         | 
| 66 | 
            +
                loss = loss * weights
         | 
| 67 | 
            +
                return torch.mean(loss)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            def set_requires_grad(tensor_list):
         | 
| 70 | 
            +
                for tensor in tensor_list:
         | 
| 71 | 
            +
                    tensor.requires_grad = True
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            def read_video_to_frames(img_name):
         | 
| 74 | 
            +
                frames = []
         | 
| 75 | 
            +
                cap = cv2.VideoCapture(img_name)
         | 
| 76 | 
            +
                while cap.isOpened():
         | 
| 77 | 
            +
                    ret, frame_bgr = cap.read()
         | 
| 78 | 
            +
                    if frame_bgr is None:
         | 
| 79 | 
            +
                        break
         | 
| 80 | 
            +
                    frame_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
         | 
| 81 | 
            +
                    frames.append(frame_rgb)
         | 
| 82 | 
            +
                return np.stack(frames)
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
            @torch.enable_grad()
         | 
| 85 | 
            +
            def fit_3dmm_for_a_image(img_name, debug=False, keypoint_mode='mediapipe', device="cuda:0", save=True):
         | 
| 86 | 
            +
                img = cv2.imread(img_name)
         | 
| 87 | 
            +
                img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
         | 
| 88 | 
            +
                img_h, img_w = img.shape[0], img.shape[0]
         | 
| 89 | 
            +
                assert img_h == img_w
         | 
| 90 | 
            +
                num_frames = 1
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                lm_name = img_name.replace("/images_512/", "/lms_2d/").replace(".png", "_lms.npy")
         | 
| 93 | 
            +
                if lm_name.endswith('_lms.npy') and os.path.exists(lm_name):
         | 
| 94 | 
            +
                    lms = np.load(lm_name)
         | 
| 95 | 
            +
                else:
         | 
| 96 | 
            +
                    # print("lms_2d file not found, try to extract it from image...")
         | 
| 97 | 
            +
                    try:
         | 
| 98 | 
            +
                        landmarker = MediapipeLandmarker()
         | 
| 99 | 
            +
                        lms = landmarker.extract_lm478_from_img_name(img_name)
         | 
| 100 | 
            +
                        # lms = landmarker.extract_lm478_from_img(img)
         | 
| 101 | 
            +
                    except Exception as e:
         | 
| 102 | 
            +
                        print(e)
         | 
| 103 | 
            +
                        return
         | 
| 104 | 
            +
                    if lms is None:
         | 
| 105 | 
            +
                        print("get None lms_2d, please check whether each frame has one head, exiting...")
         | 
| 106 | 
            +
                        return
         | 
| 107 | 
            +
                lms = lms[:468].reshape([468,2])
         | 
| 108 | 
            +
                lms = torch.FloatTensor(lms).to(device=device)
         | 
| 109 | 
            +
                lms[..., 1] = img_h - lms[..., 1] # flip the height axis
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                if keypoint_mode == 'mediapipe':
         | 
| 112 | 
            +
                    cal_lan_loss_fn = cal_lan_loss_mp
         | 
| 113 | 
            +
                    out_name = img_name.replace("/images_512/", "/coeff_fit_mp/").replace(".png", "_coeff_fit_mp.npy")
         | 
| 114 | 
            +
                else:
         | 
| 115 | 
            +
                    cal_lan_loss_fn = cal_lan_loss
         | 
| 116 | 
            +
                    out_name = img_name.replace("/images_512/", "/coeff_fit_lm68/").replace(".png", "_coeff_fit_lm68.npy")
         | 
| 117 | 
            +
                try:
         | 
| 118 | 
            +
                    os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 119 | 
            +
                except:
         | 
| 120 | 
            +
                    pass
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                id_dim, exp_dim = 80, 64
         | 
| 123 | 
            +
                sel_ids = np.arange(0, num_frames, 40)
         | 
| 124 | 
            +
                sel_num = sel_ids.shape[0]
         | 
| 125 | 
            +
                arg_focal = face_model.focal
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                h = w = face_model.center * 2
         | 
| 128 | 
            +
                img_scale_factor = img_h / h
         | 
| 129 | 
            +
                lms /= img_scale_factor
         | 
| 130 | 
            +
                cxy = torch.tensor((w / 2.0, h / 2.0), dtype=torch.float).to(device=device)
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                id_para = lms.new_zeros((num_frames, id_dim), requires_grad=True) # lms.new_zeros((1, id_dim), requires_grad=True)
         | 
| 133 | 
            +
                exp_para = lms.new_zeros((num_frames, exp_dim), requires_grad=True)
         | 
| 134 | 
            +
                euler_angle = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 135 | 
            +
                trans = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                focal_length = lms.new_zeros(1, requires_grad=True)
         | 
| 138 | 
            +
                focal_length.data += arg_focal
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                set_requires_grad([id_para, exp_para, euler_angle, trans])
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                optimizer_idexp = torch.optim.Adam([id_para, exp_para], lr=.1)
         | 
| 143 | 
            +
                optimizer_frame = torch.optim.Adam([euler_angle, trans], lr=.1)
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                # 其他参数初始化,先训练euler和trans
         | 
| 146 | 
            +
                for _ in range(200):
         | 
| 147 | 
            +
                    proj_geo = face_model.compute_for_landmark_fit(
         | 
| 148 | 
            +
                        id_para, exp_para, euler_angle, trans)
         | 
| 149 | 
            +
                    loss_lan = cal_lan_loss_fn(proj_geo[:, :, :2], lms.detach())
         | 
| 150 | 
            +
                    loss = loss_lan
         | 
| 151 | 
            +
                    optimizer_frame.zero_grad()
         | 
| 152 | 
            +
                    loss.backward()
         | 
| 153 | 
            +
                    optimizer_frame.step()
         | 
| 154 | 
            +
                # print(f"loss_lan: {loss_lan.item():.2f}, euler_abs_mean: {euler_angle.abs().mean().item():.4f}, euler_std: {euler_angle.std().item():.4f}, euler_min: {euler_angle.min().item():.4f}, euler_max: {euler_angle.max().item():.4f}")
         | 
| 155 | 
            +
                # print(f"trans_z_mean: {trans[...,2].mean().item():.4f}, trans_z_std: {trans[...,2].std().item():.4f}, trans_min: {trans[...,2].min().item():.4f}, trans_max: {trans[...,2].max().item():.4f}")
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                for param_group in optimizer_frame.param_groups:
         | 
| 158 | 
            +
                    param_group['lr'] = 0.1
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                # "jointly roughly training id exp euler trans"
         | 
| 161 | 
            +
                for _ in range(200):
         | 
| 162 | 
            +
                    proj_geo = face_model.compute_for_landmark_fit(
         | 
| 163 | 
            +
                        id_para, exp_para, euler_angle, trans)
         | 
| 164 | 
            +
                    loss_lan = cal_lan_loss_fn(
         | 
| 165 | 
            +
                        proj_geo[:, :, :2], lms.detach())
         | 
| 166 | 
            +
                    loss_regid = torch.mean(id_para*id_para) # 正则化
         | 
| 167 | 
            +
                    loss_regexp = torch.mean(exp_para * exp_para)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                    loss = loss_lan  + loss_regid * LAMBDA_REG_ID + loss_regexp * LAMBDA_REG_EXP
         | 
| 170 | 
            +
                    optimizer_idexp.zero_grad()
         | 
| 171 | 
            +
                    optimizer_frame.zero_grad()
         | 
| 172 | 
            +
                    loss.backward()
         | 
| 173 | 
            +
                    optimizer_idexp.step()
         | 
| 174 | 
            +
                    optimizer_frame.step()
         | 
| 175 | 
            +
                # print(f"loss_lan: {loss_lan.item():.2f}, loss_reg_id: {loss_regid.item():.2f},loss_reg_exp: {loss_regexp.item():.2f},")
         | 
| 176 | 
            +
                # print(f"euler_abs_mean: {euler_angle.abs().mean().item():.4f}, euler_std: {euler_angle.std().item():.4f}, euler_min: {euler_angle.min().item():.4f}, euler_max: {euler_angle.max().item():.4f}")
         | 
| 177 | 
            +
                # print(f"trans_z_mean: {trans[...,2].mean().item():.4f}, trans_z_std: {trans[...,2].std().item():.4f}, trans_min: {trans[...,2].min().item():.4f}, trans_max: {trans[...,2].max().item():.4f}")
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                # start fine training, intialize from the roughly trained results
         | 
| 180 | 
            +
                id_para_ = lms.new_zeros((num_frames, id_dim), requires_grad=True)
         | 
| 181 | 
            +
                id_para_.data = id_para.data.clone()
         | 
| 182 | 
            +
                id_para = id_para_
         | 
| 183 | 
            +
                exp_para_ = lms.new_zeros((num_frames, exp_dim), requires_grad=True)
         | 
| 184 | 
            +
                exp_para_.data = exp_para.data.clone()
         | 
| 185 | 
            +
                exp_para = exp_para_
         | 
| 186 | 
            +
                euler_angle_ = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 187 | 
            +
                euler_angle_.data = euler_angle.data.clone()
         | 
| 188 | 
            +
                euler_angle = euler_angle_
         | 
| 189 | 
            +
                trans_ = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 190 | 
            +
                trans_.data = trans.data.clone()
         | 
| 191 | 
            +
                trans = trans_
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                batch_size = 1
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                # "fine fitting the 3DMM in batches"
         | 
| 196 | 
            +
                for i in range(int((num_frames-1)/batch_size+1)):
         | 
| 197 | 
            +
                    if (i+1)*batch_size > num_frames:
         | 
| 198 | 
            +
                        start_n = num_frames-batch_size
         | 
| 199 | 
            +
                        sel_ids = np.arange(max(num_frames-batch_size,0), num_frames)
         | 
| 200 | 
            +
                    else:
         | 
| 201 | 
            +
                        start_n = i*batch_size
         | 
| 202 | 
            +
                        sel_ids = np.arange(i*batch_size, i*batch_size+batch_size)
         | 
| 203 | 
            +
                    sel_lms = lms[sel_ids]
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                    sel_id_para = id_para.new_zeros(
         | 
| 206 | 
            +
                        (batch_size, id_dim), requires_grad=True)
         | 
| 207 | 
            +
                    sel_id_para.data = id_para[sel_ids].clone()
         | 
| 208 | 
            +
                    sel_exp_para = exp_para.new_zeros(
         | 
| 209 | 
            +
                        (batch_size, exp_dim), requires_grad=True)
         | 
| 210 | 
            +
                    sel_exp_para.data = exp_para[sel_ids].clone()
         | 
| 211 | 
            +
                    sel_euler_angle = euler_angle.new_zeros(
         | 
| 212 | 
            +
                        (batch_size, 3), requires_grad=True)
         | 
| 213 | 
            +
                    sel_euler_angle.data = euler_angle[sel_ids].clone()
         | 
| 214 | 
            +
                    sel_trans = trans.new_zeros((batch_size, 3), requires_grad=True)
         | 
| 215 | 
            +
                    sel_trans.data = trans[sel_ids].clone()
         | 
| 216 | 
            +
                    
         | 
| 217 | 
            +
                    set_requires_grad([sel_id_para, sel_exp_para, sel_euler_angle, sel_trans])
         | 
| 218 | 
            +
                    optimizer_cur_batch = torch.optim.Adam(
         | 
| 219 | 
            +
                        [sel_id_para, sel_exp_para, sel_euler_angle, sel_trans], lr=0.005)
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                    for j in range(50):
         | 
| 222 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 223 | 
            +
                            sel_id_para, sel_exp_para, sel_euler_angle, sel_trans)
         | 
| 224 | 
            +
                        loss_lan = cal_lan_loss_fn(
         | 
| 225 | 
            +
                            proj_geo[:, :, :2], lms.unsqueeze(0).detach())
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                        loss_regid = torch.mean(sel_id_para*sel_id_para) # 正则化
         | 
| 228 | 
            +
                        loss_regexp = torch.mean(sel_exp_para*sel_exp_para)
         | 
| 229 | 
            +
                        loss = loss_lan + loss_regid * LAMBDA_REG_ID + loss_regexp * LAMBDA_REG_EXP 
         | 
| 230 | 
            +
                        optimizer_cur_batch.zero_grad()
         | 
| 231 | 
            +
                        loss.backward()
         | 
| 232 | 
            +
                        optimizer_cur_batch.step()
         | 
| 233 | 
            +
                    print(f"batch {i} | loss_lan: {loss_lan.item():.2f}, loss_reg_id: {loss_regid.item():.2f},loss_reg_exp: {loss_regexp.item():.2f}")
         | 
| 234 | 
            +
                    id_para[sel_ids].data = sel_id_para.data.clone()
         | 
| 235 | 
            +
                    exp_para[sel_ids].data = sel_exp_para.data.clone()
         | 
| 236 | 
            +
                    euler_angle[sel_ids].data = sel_euler_angle.data.clone()
         | 
| 237 | 
            +
                    trans[sel_ids].data = sel_trans.data.clone()
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                coeff_dict = {'id': id_para.detach().cpu().numpy(), 'exp': exp_para.detach().cpu().numpy(),
         | 
| 240 | 
            +
                            'euler': euler_angle.detach().cpu().numpy(), 'trans': trans.detach().cpu().numpy()}
         | 
| 241 | 
            +
                if save:
         | 
| 242 | 
            +
                    np.save(out_name, coeff_dict, allow_pickle=True)
         | 
| 243 | 
            +
                
         | 
| 244 | 
            +
                if debug:
         | 
| 245 | 
            +
                    import imageio
         | 
| 246 | 
            +
                    debug_name = img_name.replace("/images_512/", "/coeff_fit_mp_debug/").replace(".png", "_debug.png").replace(".jpg", "_debug.jpg")
         | 
| 247 | 
            +
                    try: os.makedirs(os.path.dirname(debug_name), exist_ok=True)
         | 
| 248 | 
            +
                    except: pass
         | 
| 249 | 
            +
                    proj_geo = face_model.compute_for_landmark_fit(id_para, exp_para, euler_angle, trans)
         | 
| 250 | 
            +
                    lm68s = proj_geo[:,:,:2].detach().cpu().numpy()  # [T, 68,2]
         | 
| 251 | 
            +
                    lm68s = lm68s * img_scale_factor
         | 
| 252 | 
            +
                    lms = lms * img_scale_factor
         | 
| 253 | 
            +
                    lm68s[..., 1] = img_h - lm68s[..., 1] # flip the height axis
         | 
| 254 | 
            +
                    lms[..., 1] = img_h - lms[..., 1] # flip the height axis
         | 
| 255 | 
            +
                    lm68s = lm68s.astype(int)
         | 
| 256 | 
            +
                    lm68s = lm68s.reshape([-1,2])
         | 
| 257 | 
            +
                    lms = lms.cpu().numpy().astype(int).reshape([-1,2])
         | 
| 258 | 
            +
                    for lm in lm68s:
         | 
| 259 | 
            +
                        img = cv2.circle(img, lm, 1, (0, 0, 255), thickness=-1)
         | 
| 260 | 
            +
                    for gt_lm in lms:
         | 
| 261 | 
            +
                        img = cv2.circle(img, gt_lm, 2, (255, 0, 0), thickness=1)
         | 
| 262 | 
            +
                    imageio.imwrite(debug_name, img)
         | 
| 263 | 
            +
                    print(f"debug img saved at {debug_name}")
         | 
| 264 | 
            +
                return coeff_dict
         | 
| 265 | 
            +
             | 
| 266 | 
            +
            def out_exist_job(vid_name):
         | 
| 267 | 
            +
                out_name = vid_name.replace("/images_512/", "/coeff_fit_mp/").replace(".png","_coeff_fit_mp.npy") 
         | 
| 268 | 
            +
                # if os.path.exists(out_name) or not os.path.exists(lms_name):
         | 
| 269 | 
            +
                if os.path.exists(out_name):
         | 
| 270 | 
            +
                    return None
         | 
| 271 | 
            +
                else:
         | 
| 272 | 
            +
                    return vid_name
         | 
| 273 | 
            +
             | 
| 274 | 
            +
            def get_todo_img_names(img_names):
         | 
| 275 | 
            +
                todo_img_names = []
         | 
| 276 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, img_names, num_workers=16):
         | 
| 277 | 
            +
                    if res is not None:
         | 
| 278 | 
            +
                        todo_img_names.append(res)
         | 
| 279 | 
            +
                return todo_img_names
         | 
| 280 | 
            +
             | 
| 281 | 
            +
             | 
| 282 | 
            +
            if __name__ == '__main__':
         | 
| 283 | 
            +
                import argparse, glob, tqdm
         | 
| 284 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 285 | 
            +
                parser.add_argument("--img_dir", default='/home/tiger/datasets/raw/FFHQ/images_512')
         | 
| 286 | 
            +
                parser.add_argument("--ds_name", default='FFHQ')
         | 
| 287 | 
            +
                parser.add_argument("--seed", default=0, type=int)
         | 
| 288 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 289 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 290 | 
            +
                parser.add_argument("--keypoint_mode", default='mediapipe', type=str)
         | 
| 291 | 
            +
                parser.add_argument("--debug", action='store_true')
         | 
| 292 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 293 | 
            +
                parser.add_argument("--device", default="cuda:0", type=str)
         | 
| 294 | 
            +
                parser.add_argument("--output_log", action='store_true')
         | 
| 295 | 
            +
                parser.add_argument("--load_names", action="store_true")
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                args = parser.parse_args()
         | 
| 298 | 
            +
                img_dir = args.img_dir
         | 
| 299 | 
            +
                load_names = args.load_names
         | 
| 300 | 
            +
                
         | 
| 301 | 
            +
                print(f"args {args}")
         | 
| 302 | 
            +
                
         | 
| 303 | 
            +
                if args.ds_name == 'single_img':
         | 
| 304 | 
            +
                    img_names = [img_dir]
         | 
| 305 | 
            +
                else:
         | 
| 306 | 
            +
                    img_names_path = os.path.join(img_dir, "img_dir.pkl")
         | 
| 307 | 
            +
                    if os.path.exists(img_names_path) and load_names:
         | 
| 308 | 
            +
                        print(f"loading vid names from {img_names_path}")
         | 
| 309 | 
            +
                        img_names = load_file(img_names_path)
         | 
| 310 | 
            +
                    else:
         | 
| 311 | 
            +
                        if args.ds_name == 'FFHQ_MV':
         | 
| 312 | 
            +
                            img_name_pattern1 = os.path.join(img_dir, "ref_imgs/*.png")
         | 
| 313 | 
            +
                            img_names1 = glob.glob(img_name_pattern1)
         | 
| 314 | 
            +
                            img_name_pattern2 = os.path.join(img_dir, "mv_imgs/*.png")
         | 
| 315 | 
            +
                            img_names2 = glob.glob(img_name_pattern2)
         | 
| 316 | 
            +
                            img_names = img_names1 + img_names2
         | 
| 317 | 
            +
                            img_names = sorted(img_names)
         | 
| 318 | 
            +
                        elif args.ds_name == 'FFHQ':
         | 
| 319 | 
            +
                            img_name_pattern = os.path.join(img_dir, "*.png")
         | 
| 320 | 
            +
                            img_names = glob.glob(img_name_pattern)
         | 
| 321 | 
            +
                            img_names = sorted(img_names)
         | 
| 322 | 
            +
                        elif args.ds_name == "PanoHeadGen":
         | 
| 323 | 
            +
                            img_name_patterns = ["ref/*/*.png"]
         | 
| 324 | 
            +
                            img_names = []
         | 
| 325 | 
            +
                            for img_name_pattern in img_name_patterns:
         | 
| 326 | 
            +
                                img_name_pattern_full = os.path.join(img_dir, img_name_pattern)
         | 
| 327 | 
            +
                                img_names_part = glob.glob(img_name_pattern_full)
         | 
| 328 | 
            +
                                img_names.extend(img_names_part)
         | 
| 329 | 
            +
                            img_names = sorted(img_names)
         | 
| 330 | 
            +
                        print(f"saving image names to {img_names_path}")
         | 
| 331 | 
            +
                        save_file(img_names_path, img_names)
         | 
| 332 | 
            +
                        
         | 
| 333 | 
            +
                # import random
         | 
| 334 | 
            +
                # random.seed(args.seed)
         | 
| 335 | 
            +
                # random.shuffle(img_names)
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                face_model = ParametricFaceModel(bfm_folder='deep_3drecon/BFM', 
         | 
| 338 | 
            +
                            camera_distance=10, focal=1015, keypoint_mode=args.keypoint_mode)
         | 
| 339 | 
            +
                face_model.to(torch.device(args.device))
         | 
| 340 | 
            +
                 
         | 
| 341 | 
            +
                process_id = args.process_id
         | 
| 342 | 
            +
                total_process = args.total_process
         | 
| 343 | 
            +
                if total_process > 1:
         | 
| 344 | 
            +
                    assert process_id <= total_process -1 and process_id >= 0
         | 
| 345 | 
            +
                    num_samples_per_process = len(img_names) // total_process
         | 
| 346 | 
            +
                    if process_id == total_process:
         | 
| 347 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : ]
         | 
| 348 | 
            +
                    else:
         | 
| 349 | 
            +
                        img_names = img_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 350 | 
            +
                print(f"image names number (before fileter): {len(img_names)}")
         | 
| 351 | 
            +
             | 
| 352 | 
            +
             | 
| 353 | 
            +
                if not args.reset:
         | 
| 354 | 
            +
                    img_names = get_todo_img_names(img_names)
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                print(f"image names number (after  fileter): {len(img_names)}")
         | 
| 357 | 
            +
                for i in tqdm.trange(len(img_names), desc=f"process {process_id}: fitting 3dmm ..."):
         | 
| 358 | 
            +
                    img_name = img_names[i]
         | 
| 359 | 
            +
                    try:
         | 
| 360 | 
            +
                        fit_3dmm_for_a_image(img_name, args.debug, device=args.device)
         | 
| 361 | 
            +
                    except Exception as e:
         | 
| 362 | 
            +
                        print(img_name, e)
         | 
| 363 | 
            +
                    if args.output_log and i % max(int(len(img_names) * 0.003), 1) == 0:
         | 
| 364 | 
            +
                        print(f"process {process_id}: {i + 1} / {len(img_names)} done")
         | 
| 365 | 
            +
                        sys.stdout.flush()
         | 
| 366 | 
            +
                        sys.stderr.flush()
         | 
| 367 | 
            +
                        
         | 
| 368 | 
            +
                print(f"process {process_id}: fitting 3dmm all done")
         | 
| 369 | 
            +
             | 
    	
        data_gen/utils/process_video/euler2quaterion.py
    ADDED
    
    | @@ -0,0 +1,35 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import numpy as np
         | 
| 2 | 
            +
            import torch
         | 
| 3 | 
            +
            import math
         | 
| 4 | 
            +
            import numba
         | 
| 5 | 
            +
            from scipy.spatial.transform import Rotation as R
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            def euler2quaterion(euler, use_radian=True):
         | 
| 8 | 
            +
                """
         | 
| 9 | 
            +
                euler: np.array, [batch, 3]
         | 
| 10 | 
            +
                return: the quaterion, np.array, [batch, 4]
         | 
| 11 | 
            +
                """
         | 
| 12 | 
            +
                r = R.from_euler('xyz',euler, degrees=not use_radian)
         | 
| 13 | 
            +
                return r.as_quat()
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            def quaterion2euler(quat, use_radian=True):
         | 
| 16 | 
            +
                """
         | 
| 17 | 
            +
                quat: np.array, [batch, 4]
         | 
| 18 | 
            +
                return: the euler, np.array, [batch, 3]
         | 
| 19 | 
            +
                """
         | 
| 20 | 
            +
                r = R.from_quat(quat)
         | 
| 21 | 
            +
                return r.as_euler('xyz', degrees=not use_radian)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            def rot2quaterion(rot):
         | 
| 24 | 
            +
                r = R.from_matrix(rot)
         | 
| 25 | 
            +
                return r.as_quat()
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            def quaterion2rot(quat):
         | 
| 28 | 
            +
                r = R.from_quat(quat)
         | 
| 29 | 
            +
                return r.as_matrix()
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            if __name__ == '__main__':
         | 
| 32 | 
            +
                euler = np.array([89.999,89.999,89.999] * 100).reshape([100,3])
         | 
| 33 | 
            +
                q = euler2quaterion(euler, use_radian=False)
         | 
| 34 | 
            +
                e = quaterion2euler(q, use_radian=False)
         | 
| 35 | 
            +
                print(" ")
         | 
    	
        data_gen/utils/process_video/extract_blink.py
    ADDED
    
    | @@ -0,0 +1,50 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import numpy as np
         | 
| 2 | 
            +
            from data_util.face3d_helper import Face3DHelper
         | 
| 3 | 
            +
            from utils.commons.tensor_utils import convert_to_tensor
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            def polygon_area(x, y):
         | 
| 6 | 
            +
                """
         | 
| 7 | 
            +
                x: [T, K=6]
         | 
| 8 | 
            +
                y: [T, K=6]
         | 
| 9 | 
            +
                return: [T,]
         | 
| 10 | 
            +
                """
         | 
| 11 | 
            +
                x_ = x - x.mean(axis=-1, keepdims=True)
         | 
| 12 | 
            +
                y_ = y - y.mean(axis=-1, keepdims=True)
         | 
| 13 | 
            +
                correction = x_[:,-1] * y_[:,0] - y_[:,-1]* x_[:,0]
         | 
| 14 | 
            +
                main_area = (x_[:,:-1] * y_[:,1:]).sum(axis=-1) - (y_[:,:-1] * x_[:,1:]).sum(axis=-1)
         | 
| 15 | 
            +
                return 0.5 * np.abs(main_area + correction)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            def get_eye_area_percent(id, exp, face3d_helper):
         | 
| 18 | 
            +
                id = convert_to_tensor(id)
         | 
| 19 | 
            +
                exp = convert_to_tensor(exp)
         | 
| 20 | 
            +
                cano_lm3d = face3d_helper.reconstruct_cano_lm3d(id, exp)
         | 
| 21 | 
            +
                cano_lm2d = (cano_lm3d[..., :2] + 1) / 2
         | 
| 22 | 
            +
                lms = cano_lm2d.cpu().numpy()
         | 
| 23 | 
            +
                eyes_left = slice(36, 42)
         | 
| 24 | 
            +
                eyes_right = slice(42, 48)
         | 
| 25 | 
            +
                area_left = polygon_area(lms[:, eyes_left, 0], lms[:, eyes_left, 1])
         | 
| 26 | 
            +
                area_right = polygon_area(lms[:, eyes_right, 0], lms[:, eyes_right, 1])
         | 
| 27 | 
            +
                # area percentage of two eyes of the whole image...
         | 
| 28 | 
            +
                area_percent = (area_left + area_right) / 1 * 100 # recommend threshold is 0.25%
         | 
| 29 | 
            +
                return area_percent # [T,]
         | 
| 30 | 
            +
             | 
| 31 | 
            +
             | 
| 32 | 
            +
            if __name__ == '__main__':
         | 
| 33 | 
            +
                import numpy as np
         | 
| 34 | 
            +
                import imageio
         | 
| 35 | 
            +
                import cv2
         | 
| 36 | 
            +
                import torch
         | 
| 37 | 
            +
                from data_gen.utils.process_video.extract_lm2d import extract_lms_mediapipe_job, read_video_to_frames, index_lm68_from_lm468
         | 
| 38 | 
            +
                from data_gen.utils.process_video.fit_3dmm_landmark import fit_3dmm_for_a_video
         | 
| 39 | 
            +
                from data_util.face3d_helper import Face3DHelper
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                face3d_helper = Face3DHelper()
         | 
| 42 | 
            +
                video_name = 'data/raw/videos/May_10s.mp4'
         | 
| 43 | 
            +
                frames = read_video_to_frames(video_name)
         | 
| 44 | 
            +
                coeff = fit_3dmm_for_a_video(video_name, save=False)
         | 
| 45 | 
            +
                area_percent = get_eye_area_percent(torch.tensor(coeff['id']), torch.tensor(coeff['exp']), face3d_helper)
         | 
| 46 | 
            +
                writer = imageio.get_writer("1.mp4", fps=25)
         | 
| 47 | 
            +
                for idx, frame in enumerate(frames):
         | 
| 48 | 
            +
                    frame = cv2.putText(frame, f"{area_percent[idx]:.2f}", org=(128,128), fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=1, color=(255,0,0), thickness=1)
         | 
| 49 | 
            +
                    writer.append_data(frame)
         | 
| 50 | 
            +
                writer.close()
         | 
    	
        data_gen/utils/process_video/extract_lm2d.py
    ADDED
    
    | @@ -0,0 +1,164 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            os.environ["OMP_NUM_THREADS"] = "1"
         | 
| 3 | 
            +
            import sys
         | 
| 4 | 
            +
            import glob
         | 
| 5 | 
            +
            import cv2
         | 
| 6 | 
            +
            import pickle
         | 
| 7 | 
            +
            import tqdm
         | 
| 8 | 
            +
            import numpy as np
         | 
| 9 | 
            +
            import mediapipe as mp
         | 
| 10 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 11 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 12 | 
            +
            from data_gen.utils.mp_feature_extractors.face_landmarker import MediapipeLandmarker
         | 
| 13 | 
            +
            import warnings
         | 
| 14 | 
            +
            import traceback
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            warnings.filterwarnings('ignore')
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            """
         | 
| 19 | 
            +
            基于Face_aligment的lm68已被弃用,因为其:
         | 
| 20 | 
            +
            1. 对眼睛部位的预测精度极低
         | 
| 21 | 
            +
            2. 无法在大偏转角度时准确预测被遮挡的下颚线, 导致大角度时3dmm的GT label就是有问题的, 从而影响性能
         | 
| 22 | 
            +
            我们目前转而使用基于mediapipe的lm68
         | 
| 23 | 
            +
            """
         | 
| 24 | 
            +
            # def extract_landmarks(ori_imgs_dir):
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            #     print(f'[INFO] ===== extract face landmarks from {ori_imgs_dir} =====')
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            #     fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, flip_input=False)
         | 
| 29 | 
            +
            #     image_paths = glob.glob(os.path.join(ori_imgs_dir, '*.png'))
         | 
| 30 | 
            +
            #     for image_path in tqdm.tqdm(image_paths):
         | 
| 31 | 
            +
            #         out_name = image_path.replace("/images_512/", "/lms_2d/").replace(".png",".lms")
         | 
| 32 | 
            +
            #         if os.path.exists(out_name):
         | 
| 33 | 
            +
            #             continue
         | 
| 34 | 
            +
            #         input = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) # [H, W, 3]
         | 
| 35 | 
            +
            #         input = cv2.cvtColor(input, cv2.COLOR_BGR2RGB)
         | 
| 36 | 
            +
            #         preds = fa.get_landmarks(input)
         | 
| 37 | 
            +
            #         if preds is None:
         | 
| 38 | 
            +
            #             print(f"Skip {image_path} for no face detected")
         | 
| 39 | 
            +
            #             continue
         | 
| 40 | 
            +
            #         if len(preds) > 0:
         | 
| 41 | 
            +
            #             lands = preds[0].reshape(-1, 2)[:,:2]
         | 
| 42 | 
            +
            #             os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 43 | 
            +
            #             np.savetxt(out_name, lands, '%f')
         | 
| 44 | 
            +
            #     del fa
         | 
| 45 | 
            +
            #     print(f'[INFO] ===== extracted face landmarks =====')
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            def save_file(name, content):
         | 
| 48 | 
            +
                with open(name, "wb") as f:
         | 
| 49 | 
            +
                    pickle.dump(content, f) 
         | 
| 50 | 
            +
                    
         | 
| 51 | 
            +
            def load_file(name):
         | 
| 52 | 
            +
                with open(name, "rb") as f:
         | 
| 53 | 
            +
                    content = pickle.load(f)
         | 
| 54 | 
            +
                return content
         | 
| 55 | 
            +
             | 
| 56 | 
            +
             | 
| 57 | 
            +
            face_landmarker = None
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
            def extract_landmark_job(video_name, nerf=False):
         | 
| 60 | 
            +
                try:
         | 
| 61 | 
            +
                    if nerf:
         | 
| 62 | 
            +
                        out_name = video_name.replace("/raw/", "/processed/").replace(".mp4","/lms_2d.npy")
         | 
| 63 | 
            +
                    else:
         | 
| 64 | 
            +
                        out_name = video_name.replace("/video/", "/lms_2d/").replace(".mp4","_lms.npy")
         | 
| 65 | 
            +
                    if os.path.exists(out_name):
         | 
| 66 | 
            +
                        # print("out exists, skip...")
         | 
| 67 | 
            +
                        return
         | 
| 68 | 
            +
                    try:
         | 
| 69 | 
            +
                        os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 70 | 
            +
                    except:
         | 
| 71 | 
            +
                        pass
         | 
| 72 | 
            +
                    global face_landmarker
         | 
| 73 | 
            +
                    if face_landmarker is None:
         | 
| 74 | 
            +
                        face_landmarker = MediapipeLandmarker()
         | 
| 75 | 
            +
                    img_lm478, vid_lm478 = face_landmarker.extract_lm478_from_video_name(video_name)
         | 
| 76 | 
            +
                    lm478 = face_landmarker.combine_vid_img_lm478_to_lm478(img_lm478, vid_lm478)
         | 
| 77 | 
            +
                    np.save(out_name, lm478)
         | 
| 78 | 
            +
                    return True
         | 
| 79 | 
            +
                    # print("Hahaha, solve one item!!!")
         | 
| 80 | 
            +
                except Exception as e:
         | 
| 81 | 
            +
                    traceback.print_exc()
         | 
| 82 | 
            +
                    return False
         | 
| 83 | 
            +
                    
         | 
| 84 | 
            +
            def out_exist_job(vid_name):
         | 
| 85 | 
            +
                out_name = vid_name.replace("/video/", "/lms_2d/").replace(".mp4","_lms.npy") 
         | 
| 86 | 
            +
                if os.path.exists(out_name):
         | 
| 87 | 
            +
                    return None
         | 
| 88 | 
            +
                else:
         | 
| 89 | 
            +
                    return vid_name
         | 
| 90 | 
            +
                
         | 
| 91 | 
            +
            def get_todo_vid_names(vid_names):
         | 
| 92 | 
            +
                if len(vid_names) == 1: # nerf
         | 
| 93 | 
            +
                    return vid_names
         | 
| 94 | 
            +
                todo_vid_names = []
         | 
| 95 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, vid_names, num_workers=128):
         | 
| 96 | 
            +
                    if res is not None:
         | 
| 97 | 
            +
                        todo_vid_names.append(res)
         | 
| 98 | 
            +
                return todo_vid_names
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            if __name__ == '__main__':
         | 
| 101 | 
            +
                import argparse, glob, tqdm, random
         | 
| 102 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 103 | 
            +
                parser.add_argument("--vid_dir", default='nerf')
         | 
| 104 | 
            +
                parser.add_argument("--ds_name", default='data/raw/videos/May.mp4')
         | 
| 105 | 
            +
                parser.add_argument("--num_workers", default=2, type=int)
         | 
| 106 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 107 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 108 | 
            +
                parser.add_argument("--reset", action="store_true")
         | 
| 109 | 
            +
                parser.add_argument("--load_names", action="store_true")
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                args = parser.parse_args()
         | 
| 112 | 
            +
                vid_dir = args.vid_dir
         | 
| 113 | 
            +
                ds_name = args.ds_name
         | 
| 114 | 
            +
                load_names = args.load_names
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                if ds_name.lower() == 'nerf': # 处理单个视频
         | 
| 117 | 
            +
                    vid_names = [vid_dir]
         | 
| 118 | 
            +
                    out_names = [video_name.replace("/raw/", "/processed/").replace(".mp4","/lms_2d.npy") for video_name in vid_names]
         | 
| 119 | 
            +
                else: # 处理整个数据集
         | 
| 120 | 
            +
                    if ds_name in ['lrs3_trainval']:
         | 
| 121 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 122 | 
            +
                    elif ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 123 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*.mp4")
         | 
| 124 | 
            +
                    elif ds_name in ['lrs2', 'lrs3', 'voxceleb2', 'CMLR']:
         | 
| 125 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 126 | 
            +
                    elif ds_name in ["RAVDESS", 'VFHQ']:
         | 
| 127 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*/*.mp4")
         | 
| 128 | 
            +
                    else:
         | 
| 129 | 
            +
                        raise NotImplementedError()
         | 
| 130 | 
            +
                    
         | 
| 131 | 
            +
                    vid_names_path = os.path.join(vid_dir, "vid_names.pkl")
         | 
| 132 | 
            +
                    if os.path.exists(vid_names_path) and load_names:
         | 
| 133 | 
            +
                        print(f"loading vid names from {vid_names_path}")
         | 
| 134 | 
            +
                        vid_names = load_file(vid_names_path)
         | 
| 135 | 
            +
                    else:
         | 
| 136 | 
            +
                        vid_names = multiprocess_glob(vid_name_pattern)
         | 
| 137 | 
            +
                    vid_names = sorted(vid_names)
         | 
| 138 | 
            +
                    if not load_names:
         | 
| 139 | 
            +
                        print(f"saving vid names to {vid_names_path}")
         | 
| 140 | 
            +
                        save_file(vid_names_path, vid_names)
         | 
| 141 | 
            +
                    out_names = [video_name.replace("/video/", "/lms_2d/").replace(".mp4","_lms.npy") for video_name in vid_names]
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                process_id = args.process_id
         | 
| 144 | 
            +
                total_process = args.total_process
         | 
| 145 | 
            +
                if total_process > 1:
         | 
| 146 | 
            +
                    assert process_id <= total_process -1
         | 
| 147 | 
            +
                    num_samples_per_process = len(vid_names) // total_process
         | 
| 148 | 
            +
                    if process_id == total_process:
         | 
| 149 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 150 | 
            +
                    else:
         | 
| 151 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 152 | 
            +
                
         | 
| 153 | 
            +
                if not args.reset:
         | 
| 154 | 
            +
                    vid_names = get_todo_vid_names(vid_names)
         | 
| 155 | 
            +
                print(f"todo videos number: {len(vid_names)}")
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                fail_cnt = 0
         | 
| 158 | 
            +
                job_args = [(vid_name, ds_name=='nerf') for vid_name in vid_names]
         | 
| 159 | 
            +
                for (i, res) in multiprocess_run_tqdm(extract_landmark_job, job_args, num_workers=args.num_workers, desc=f"Root {args.process_id}: extracing MP-based landmark2d"): 
         | 
| 160 | 
            +
                    if res is False:
         | 
| 161 | 
            +
                        fail_cnt += 1
         | 
| 162 | 
            +
                    print(f"finished {i + 1} / {len(vid_names)} = {(i + 1) / len(vid_names):.4f}, failed {fail_cnt} / {i + 1} = {fail_cnt / (i + 1):.4f}")
         | 
| 163 | 
            +
                    sys.stdout.flush()
         | 
| 164 | 
            +
                    pass
         | 
    	
        data_gen/utils/process_video/extract_segment_imgs.py
    ADDED
    
    | @@ -0,0 +1,494 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            os.environ["OMP_NUM_THREADS"] = "1"
         | 
| 3 | 
            +
            import random
         | 
| 4 | 
            +
            import glob
         | 
| 5 | 
            +
            import cv2
         | 
| 6 | 
            +
            import tqdm
         | 
| 7 | 
            +
            import numpy as np
         | 
| 8 | 
            +
            from typing import Union
         | 
| 9 | 
            +
            from utils.commons.tensor_utils import convert_to_np
         | 
| 10 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 11 | 
            +
            import pickle
         | 
| 12 | 
            +
            import traceback
         | 
| 13 | 
            +
            import multiprocessing
         | 
| 14 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 15 | 
            +
            from scipy.ndimage import binary_erosion, binary_dilation
         | 
| 16 | 
            +
            from sklearn.neighbors import NearestNeighbors
         | 
| 17 | 
            +
            from mediapipe.tasks.python import vision
         | 
| 18 | 
            +
            from data_gen.utils.mp_feature_extractors.mp_segmenter import MediapipeSegmenter, encode_segmap_mask_to_image, decode_segmap_mask_from_image, job_cal_seg_map_for_image
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            seg_model   = None
         | 
| 21 | 
            +
            segmenter   = None
         | 
| 22 | 
            +
            mat_model   = None
         | 
| 23 | 
            +
            lama_model  = None
         | 
| 24 | 
            +
            lama_config = None
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            from data_gen.utils.process_video.split_video_to_imgs import extract_img_job
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            BG_NAME_MAP = {
         | 
| 29 | 
            +
                "knn": "",
         | 
| 30 | 
            +
            }
         | 
| 31 | 
            +
            FRAME_SELECT_INTERVAL = 5
         | 
| 32 | 
            +
            SIM_METHOD = "mse"
         | 
| 33 | 
            +
            SIM_THRESHOLD = 3
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            def save_file(name, content):
         | 
| 36 | 
            +
                with open(name, "wb") as f:
         | 
| 37 | 
            +
                    pickle.dump(content, f) 
         | 
| 38 | 
            +
                    
         | 
| 39 | 
            +
            def load_file(name):
         | 
| 40 | 
            +
                with open(name, "rb") as f:
         | 
| 41 | 
            +
                    content = pickle.load(f)
         | 
| 42 | 
            +
                return content
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            def save_rgb_alpha_image_to_path(img, alpha, img_path):
         | 
| 45 | 
            +
                try: os.makedirs(os.path.dirname(img_path), exist_ok=True)
         | 
| 46 | 
            +
                except: pass
         | 
| 47 | 
            +
                cv2.imwrite(img_path, np.concatenate([cv2.cvtColor(img, cv2.COLOR_RGB2BGR), alpha], axis=-1))
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            def save_rgb_image_to_path(img, img_path):
         | 
| 50 | 
            +
                try: os.makedirs(os.path.dirname(img_path), exist_ok=True)
         | 
| 51 | 
            +
                except: pass
         | 
| 52 | 
            +
                cv2.imwrite(img_path, cv2.cvtColor(img, cv2.COLOR_RGB2BGR))
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            def load_rgb_image_to_path(img_path):
         | 
| 55 | 
            +
                return cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            def image_similarity(x: np.ndarray, y: np.ndarray, method="mse"):
         | 
| 58 | 
            +
                if method == "mse":
         | 
| 59 | 
            +
                    return np.mean((x - y) ** 2)
         | 
| 60 | 
            +
                else:
         | 
| 61 | 
            +
                    raise NotImplementedError
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            def extract_background(img_lst, segmap_mask_lst=None, method="knn", device='cpu', mix_bg=True):
         | 
| 64 | 
            +
                """
         | 
| 65 | 
            +
                img_lst: list of rgb ndarray
         | 
| 66 | 
            +
                method: "knn"
         | 
| 67 | 
            +
                """
         | 
| 68 | 
            +
                global segmenter
         | 
| 69 | 
            +
                global seg_model
         | 
| 70 | 
            +
                global mat_model
         | 
| 71 | 
            +
                global lama_model
         | 
| 72 | 
            +
                global lama_config
         | 
| 73 | 
            +
                
         | 
| 74 | 
            +
                assert len(img_lst) > 0
         | 
| 75 | 
            +
                if segmap_mask_lst is not None:
         | 
| 76 | 
            +
                    assert len(segmap_mask_lst) == len(img_lst)
         | 
| 77 | 
            +
                else:
         | 
| 78 | 
            +
                    del segmenter
         | 
| 79 | 
            +
                    del seg_model
         | 
| 80 | 
            +
                    seg_model = MediapipeSegmenter()
         | 
| 81 | 
            +
                    segmenter = vision.ImageSegmenter.create_from_options(seg_model.video_options)
         | 
| 82 | 
            +
                    
         | 
| 83 | 
            +
                def get_segmap_mask(img_lst, segmap_mask_lst, index):
         | 
| 84 | 
            +
                    if segmap_mask_lst is not None:
         | 
| 85 | 
            +
                        segmap = refresh_segment_mask(segmap_mask_lst[index])
         | 
| 86 | 
            +
                    else:
         | 
| 87 | 
            +
                        segmap = seg_model._cal_seg_map(refresh_image(img_lst[index]), segmenter=segmenter)
         | 
| 88 | 
            +
                    return segmap
         | 
| 89 | 
            +
                    
         | 
| 90 | 
            +
                if method == "knn":
         | 
| 91 | 
            +
                    num_frames = len(img_lst)
         | 
| 92 | 
            +
                    if num_frames < 100:
         | 
| 93 | 
            +
                        FRAME_SELECT_INTERVAL = 5
         | 
| 94 | 
            +
                    elif num_frames < 10000:
         | 
| 95 | 
            +
                        FRAME_SELECT_INTERVAL = 20
         | 
| 96 | 
            +
                    else:
         | 
| 97 | 
            +
                        FRAME_SELECT_INTERVAL = num_frames // 500
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    img_lst = img_lst[::FRAME_SELECT_INTERVAL] if num_frames > FRAME_SELECT_INTERVAL else img_lst[0:1]
         | 
| 100 | 
            +
                        
         | 
| 101 | 
            +
                    if segmap_mask_lst is not None:
         | 
| 102 | 
            +
                        segmap_mask_lst = segmap_mask_lst[::FRAME_SELECT_INTERVAL] if num_frames > FRAME_SELECT_INTERVAL else segmap_mask_lst[0:1]
         | 
| 103 | 
            +
                        assert len(img_lst) == len(segmap_mask_lst)
         | 
| 104 | 
            +
                    # get H/W
         | 
| 105 | 
            +
                    h, w = refresh_image(img_lst[0]).shape[:2]
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    # nearest neighbors
         | 
| 108 | 
            +
                    all_xys = np.mgrid[0:h, 0:w].reshape(2, -1).transpose() # [512*512, 2] coordinate grid
         | 
| 109 | 
            +
                    distss = []
         | 
| 110 | 
            +
                    for idx, img in tqdm.tqdm(enumerate(img_lst), desc='combining backgrounds...', total=len(img_lst)):
         | 
| 111 | 
            +
                        segmap = get_segmap_mask(img_lst=img_lst, segmap_mask_lst=segmap_mask_lst, index=idx)
         | 
| 112 | 
            +
                        bg = (segmap[0]).astype(bool) # [h,w] bool mask
         | 
| 113 | 
            +
                        fg_xys = np.stack(np.nonzero(~bg)).transpose(1, 0) # [N_nonbg,2] coordinate of non-bg pixels
         | 
| 114 | 
            +
                        nbrs = NearestNeighbors(n_neighbors=1, algorithm='kd_tree').fit(fg_xys)
         | 
| 115 | 
            +
                        dists, _ = nbrs.kneighbors(all_xys) # [512*512, 1] distance to nearest non-bg pixel
         | 
| 116 | 
            +
                        distss.append(dists)
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    distss = np.stack(distss) # [B, 512*512, 1]
         | 
| 119 | 
            +
                    max_dist = np.max(distss, 0) # [512*512, 1]
         | 
| 120 | 
            +
                    max_id = np.argmax(distss, 0) # id of frame
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    bc_pixs = max_dist > 10 # 在各个frame有一个出现过是bg的pixel,bg标准是离最近的non-bg pixel距离大于10
         | 
| 123 | 
            +
                    bc_pixs_id = np.nonzero(bc_pixs)
         | 
| 124 | 
            +
                    bc_ids = max_id[bc_pixs]
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    # TODO: maybe we should reimplement here to avoid memory costs?
         | 
| 127 | 
            +
                    # though there is upper limits of images here
         | 
| 128 | 
            +
                    num_pixs = distss.shape[1]
         | 
| 129 | 
            +
                    bg_img = np.zeros((h*w, 3), dtype=np.uint8)
         | 
| 130 | 
            +
                    img_lst = [refresh_image(img) for img in img_lst] 
         | 
| 131 | 
            +
                    imgs = np.stack(img_lst).reshape(-1, num_pixs, 3) 
         | 
| 132 | 
            +
                    bg_img[bc_pixs_id, :] = imgs[bc_ids, bc_pixs_id, :] # 对那些铁bg的pixel,直接去对应的image里面采样
         | 
| 133 | 
            +
                    bg_img = bg_img.reshape(h, w, 3)
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                    max_dist = max_dist.reshape(h, w)
         | 
| 136 | 
            +
                    bc_pixs = max_dist > 10 # 5
         | 
| 137 | 
            +
                    bg_xys = np.stack(np.nonzero(~bc_pixs)).transpose()
         | 
| 138 | 
            +
                    fg_xys = np.stack(np.nonzero(bc_pixs)).transpose()
         | 
| 139 | 
            +
                    nbrs = NearestNeighbors(n_neighbors=1, algorithm='kd_tree').fit(fg_xys)
         | 
| 140 | 
            +
                    distances, indices = nbrs.kneighbors(bg_xys) # 对non-bg img,用KNN找最近的bg pixel
         | 
| 141 | 
            +
                    bg_fg_xys = fg_xys[indices[:, 0]]
         | 
| 142 | 
            +
                    bg_img[bg_xys[:, 0], bg_xys[:, 1], :] = bg_img[bg_fg_xys[:, 0], bg_fg_xys[:, 1], :]
         | 
| 143 | 
            +
                else:
         | 
| 144 | 
            +
                    raise NotImplementedError # deperated
         | 
| 145 | 
            +
                
         | 
| 146 | 
            +
                return bg_img
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            def inpaint_torso_job(gt_img, segmap):
         | 
| 149 | 
            +
                bg_part = (segmap[0]).astype(bool)
         | 
| 150 | 
            +
                head_part = (segmap[1] + segmap[3] + segmap[5]).astype(bool)
         | 
| 151 | 
            +
                neck_part = (segmap[2]).astype(bool)
         | 
| 152 | 
            +
                torso_part = (segmap[4]).astype(bool) 
         | 
| 153 | 
            +
                img = gt_img.copy()
         | 
| 154 | 
            +
                img[head_part] = 0
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                # torso part "vertical" in-painting...
         | 
| 157 | 
            +
                L = 8 + 1
         | 
| 158 | 
            +
                torso_coords = np.stack(np.nonzero(torso_part), axis=-1) # [M, 2]
         | 
| 159 | 
            +
                # lexsort: sort 2D coords first by y then by x, 
         | 
| 160 | 
            +
                # ref: https://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple-axes
         | 
| 161 | 
            +
                inds = np.lexsort((torso_coords[:, 0], torso_coords[:, 1]))
         | 
| 162 | 
            +
                torso_coords = torso_coords[inds]
         | 
| 163 | 
            +
                # choose the top pixel for each column
         | 
| 164 | 
            +
                u, uid, ucnt = np.unique(torso_coords[:, 1], return_index=True, return_counts=True)
         | 
| 165 | 
            +
                top_torso_coords = torso_coords[uid] # [m, 2]
         | 
| 166 | 
            +
                # only keep top-is-head pixels
         | 
| 167 | 
            +
                top_torso_coords_up = top_torso_coords.copy() - np.array([1, 0]) # [N, 2]
         | 
| 168 | 
            +
                mask = head_part[tuple(top_torso_coords_up.T)] 
         | 
| 169 | 
            +
                if mask.any():
         | 
| 170 | 
            +
                    top_torso_coords = top_torso_coords[mask]
         | 
| 171 | 
            +
                    # get the color
         | 
| 172 | 
            +
                    top_torso_colors = gt_img[tuple(top_torso_coords.T)] # [m, 3]
         | 
| 173 | 
            +
                    # construct inpaint coords (vertically up, or minus in x)
         | 
| 174 | 
            +
                    inpaint_torso_coords = top_torso_coords[None].repeat(L, 0) # [L, m, 2]
         | 
| 175 | 
            +
                    inpaint_offsets = np.stack([-np.arange(L), np.zeros(L, dtype=np.int32)], axis=-1)[:, None] # [L, 1, 2]
         | 
| 176 | 
            +
                    inpaint_torso_coords += inpaint_offsets
         | 
| 177 | 
            +
                    inpaint_torso_coords = inpaint_torso_coords.reshape(-1, 2) # [Lm, 2]
         | 
| 178 | 
            +
                    inpaint_torso_colors = top_torso_colors[None].repeat(L, 0) # [L, m, 3]
         | 
| 179 | 
            +
                    darken_scaler = 0.98 ** np.arange(L).reshape(L, 1, 1) # [L, 1, 1]
         | 
| 180 | 
            +
                    inpaint_torso_colors = (inpaint_torso_colors * darken_scaler).reshape(-1, 3) # [Lm, 3]
         | 
| 181 | 
            +
                    # set color
         | 
| 182 | 
            +
                    img[tuple(inpaint_torso_coords.T)] = inpaint_torso_colors
         | 
| 183 | 
            +
                    inpaint_torso_mask = np.zeros_like(img[..., 0]).astype(bool)
         | 
| 184 | 
            +
                    inpaint_torso_mask[tuple(inpaint_torso_coords.T)] = True
         | 
| 185 | 
            +
                else:
         | 
| 186 | 
            +
                    inpaint_torso_mask = None
         | 
| 187 | 
            +
                
         | 
| 188 | 
            +
                # neck part "vertical" in-painting...
         | 
| 189 | 
            +
                push_down = 4
         | 
| 190 | 
            +
                L = 48 + push_down + 1
         | 
| 191 | 
            +
                neck_part = binary_dilation(neck_part, structure=np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]], dtype=bool), iterations=3)
         | 
| 192 | 
            +
                neck_coords = np.stack(np.nonzero(neck_part), axis=-1) # [M, 2]
         | 
| 193 | 
            +
                # lexsort: sort 2D coords first by y then by x, 
         | 
| 194 | 
            +
                # ref: https://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple-axes
         | 
| 195 | 
            +
                inds = np.lexsort((neck_coords[:, 0], neck_coords[:, 1]))
         | 
| 196 | 
            +
                neck_coords = neck_coords[inds]
         | 
| 197 | 
            +
                # choose the top pixel for each column
         | 
| 198 | 
            +
                u, uid, ucnt = np.unique(neck_coords[:, 1], return_index=True, return_counts=True)
         | 
| 199 | 
            +
                top_neck_coords = neck_coords[uid] # [m, 2]
         | 
| 200 | 
            +
                # only keep top-is-head pixels
         | 
| 201 | 
            +
                top_neck_coords_up = top_neck_coords.copy() - np.array([1, 0])
         | 
| 202 | 
            +
                mask = head_part[tuple(top_neck_coords_up.T)] 
         | 
| 203 | 
            +
                top_neck_coords = top_neck_coords[mask]
         | 
| 204 | 
            +
                # push these top down for 4 pixels to make the neck inpainting more natural...
         | 
| 205 | 
            +
                offset_down = np.minimum(ucnt[mask] - 1, push_down)
         | 
| 206 | 
            +
                top_neck_coords += np.stack([offset_down, np.zeros_like(offset_down)], axis=-1)
         | 
| 207 | 
            +
                # get the color
         | 
| 208 | 
            +
                top_neck_colors = gt_img[tuple(top_neck_coords.T)] # [m, 3]
         | 
| 209 | 
            +
                # construct inpaint coords (vertically up, or minus in x)
         | 
| 210 | 
            +
                inpaint_neck_coords = top_neck_coords[None].repeat(L, 0) # [L, m, 2]
         | 
| 211 | 
            +
                inpaint_offsets = np.stack([-np.arange(L), np.zeros(L, dtype=np.int32)], axis=-1)[:, None] # [L, 1, 2]
         | 
| 212 | 
            +
                inpaint_neck_coords += inpaint_offsets
         | 
| 213 | 
            +
                inpaint_neck_coords = inpaint_neck_coords.reshape(-1, 2) # [Lm, 2]
         | 
| 214 | 
            +
                inpaint_neck_colors = top_neck_colors[None].repeat(L, 0) # [L, m, 3]
         | 
| 215 | 
            +
                darken_scaler = 0.98 ** np.arange(L).reshape(L, 1, 1) # [L, 1, 1]
         | 
| 216 | 
            +
                inpaint_neck_colors = (inpaint_neck_colors * darken_scaler).reshape(-1, 3) # [Lm, 3]
         | 
| 217 | 
            +
                # set color
         | 
| 218 | 
            +
                img[tuple(inpaint_neck_coords.T)] = inpaint_neck_colors
         | 
| 219 | 
            +
                # apply blurring to the inpaint area to avoid vertical-line artifects...
         | 
| 220 | 
            +
                inpaint_mask = np.zeros_like(img[..., 0]).astype(bool)
         | 
| 221 | 
            +
                inpaint_mask[tuple(inpaint_neck_coords.T)] = True
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                blur_img = img.copy()
         | 
| 224 | 
            +
                blur_img = cv2.GaussianBlur(blur_img, (5, 5), cv2.BORDER_DEFAULT)
         | 
| 225 | 
            +
                img[inpaint_mask] = blur_img[inpaint_mask]
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                # set mask
         | 
| 228 | 
            +
                torso_img_mask = (neck_part | torso_part | inpaint_mask)
         | 
| 229 | 
            +
                torso_with_bg_img_mask = (bg_part | neck_part | torso_part | inpaint_mask)
         | 
| 230 | 
            +
                if inpaint_torso_mask is not None:
         | 
| 231 | 
            +
                    torso_img_mask = torso_img_mask | inpaint_torso_mask
         | 
| 232 | 
            +
                    torso_with_bg_img_mask = torso_with_bg_img_mask | inpaint_torso_mask
         | 
| 233 | 
            +
                
         | 
| 234 | 
            +
                torso_img = img.copy()
         | 
| 235 | 
            +
                torso_img[~torso_img_mask] = 0
         | 
| 236 | 
            +
                torso_with_bg_img = img.copy()
         | 
| 237 | 
            +
                torso_img[~torso_with_bg_img_mask] = 0
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                return torso_img, torso_img_mask, torso_with_bg_img, torso_with_bg_img_mask
         | 
| 240 | 
            +
             | 
| 241 | 
            +
            def load_segment_mask_from_file(filename: str):
         | 
| 242 | 
            +
                encoded_segmap = load_rgb_image_to_path(filename)
         | 
| 243 | 
            +
                segmap_mask = decode_segmap_mask_from_image(encoded_segmap)
         | 
| 244 | 
            +
                return segmap_mask
         | 
| 245 | 
            +
             | 
| 246 | 
            +
            # load segment mask to memory if not loaded yet
         | 
| 247 | 
            +
            def refresh_segment_mask(segmap_mask: Union[str, np.ndarray]):
         | 
| 248 | 
            +
                if isinstance(segmap_mask, str):
         | 
| 249 | 
            +
                    segmap_mask = load_segment_mask_from_file(segmap_mask)
         | 
| 250 | 
            +
                return segmap_mask
         | 
| 251 | 
            +
             | 
| 252 | 
            +
            # load segment mask to memory if not loaded yet
         | 
| 253 | 
            +
            def refresh_image(image: Union[str, np.ndarray]):
         | 
| 254 | 
            +
                if isinstance(image, str):
         | 
| 255 | 
            +
                    image = load_rgb_image_to_path(image)
         | 
| 256 | 
            +
                return image
         | 
| 257 | 
            +
             | 
| 258 | 
            +
            def generate_segment_imgs_job(img_name, segmap, img):
         | 
| 259 | 
            +
                out_img_name = segmap_name = img_name.replace("/gt_imgs/", "/segmaps/").replace(".jpg", ".png") # 存成jpg的话,pixel value会有误差
         | 
| 260 | 
            +
                try: os.makedirs(os.path.dirname(out_img_name), exist_ok=True)
         | 
| 261 | 
            +
                except: pass
         | 
| 262 | 
            +
                encoded_segmap = encode_segmap_mask_to_image(segmap)
         | 
| 263 | 
            +
                save_rgb_image_to_path(encoded_segmap, out_img_name)
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                for mode in ['head', 'torso', 'person', 'bg']:
         | 
| 266 | 
            +
                    out_img, mask = seg_model._seg_out_img_with_segmap(img, segmap, mode=mode)
         | 
| 267 | 
            +
                    img_alpha = 255 * np.ones((img.shape[0], img.shape[1], 1), dtype=np.uint8) # alpha
         | 
| 268 | 
            +
                    mask = mask[0][..., None]
         | 
| 269 | 
            +
                    img_alpha[~mask] = 0
         | 
| 270 | 
            +
                    out_img_name = img_name.replace("/gt_imgs/", f"/{mode}_imgs/").replace(".jpg", ".png")
         | 
| 271 | 
            +
                    save_rgb_alpha_image_to_path(out_img, img_alpha, out_img_name)
         | 
| 272 | 
            +
                
         | 
| 273 | 
            +
                inpaint_torso_img, inpaint_torso_img_mask, inpaint_torso_with_bg_img, inpaint_torso_with_bg_img_mask = inpaint_torso_job(img, segmap)
         | 
| 274 | 
            +
                img_alpha = 255 * np.ones((img.shape[0], img.shape[1], 1), dtype=np.uint8) # alpha
         | 
| 275 | 
            +
                img_alpha[~inpaint_torso_img_mask[..., None]] = 0
         | 
| 276 | 
            +
                out_img_name = img_name.replace("/gt_imgs/", f"/inpaint_torso_imgs/").replace(".jpg", ".png")
         | 
| 277 | 
            +
                save_rgb_alpha_image_to_path(inpaint_torso_img, img_alpha, out_img_name)
         | 
| 278 | 
            +
                return segmap_name
         | 
| 279 | 
            +
                
         | 
| 280 | 
            +
            def segment_and_generate_for_image_job(img_name, img, segmenter_options=None, segmenter=None, store_in_memory=False):
         | 
| 281 | 
            +
                img = refresh_image(img)
         | 
| 282 | 
            +
                segmap_mask, segmap_image = job_cal_seg_map_for_image(img, segmenter_options=segmenter_options, segmenter=segmenter)
         | 
| 283 | 
            +
                segmap_name = generate_segment_imgs_job(img_name=img_name, segmap=segmap_mask, img=img)
         | 
| 284 | 
            +
                if store_in_memory:
         | 
| 285 | 
            +
                    return segmap_mask
         | 
| 286 | 
            +
                else:
         | 
| 287 | 
            +
                    return segmap_name
         | 
| 288 | 
            +
                
         | 
| 289 | 
            +
            def extract_segment_job(
         | 
| 290 | 
            +
                video_name, 
         | 
| 291 | 
            +
                nerf=False, 
         | 
| 292 | 
            +
                background_method='knn', 
         | 
| 293 | 
            +
                device="cpu",
         | 
| 294 | 
            +
                total_gpus=0, 
         | 
| 295 | 
            +
                mix_bg=True,
         | 
| 296 | 
            +
                store_in_memory=False, # set to True to speed up a bit of preprocess, but leads to HUGE memory costs (100GB for 5-min video)
         | 
| 297 | 
            +
                force_single_process=False, # turn this on if you find multi-process does not work on your environment
         | 
| 298 | 
            +
            ):
         | 
| 299 | 
            +
                global segmenter
         | 
| 300 | 
            +
                global seg_model
         | 
| 301 | 
            +
                del segmenter
         | 
| 302 | 
            +
                del seg_model
         | 
| 303 | 
            +
                seg_model = MediapipeSegmenter()
         | 
| 304 | 
            +
                segmenter = vision.ImageSegmenter.create_from_options(seg_model.options)
         | 
| 305 | 
            +
                # nerf means that we extract only one video, so can enable multi-process acceleration
         | 
| 306 | 
            +
                multiprocess_enable = nerf and not force_single_process 
         | 
| 307 | 
            +
                try:
         | 
| 308 | 
            +
                    if "cuda" in device:
         | 
| 309 | 
            +
                        # determine which cuda index from subprocess id
         | 
| 310 | 
            +
                        pname = multiprocessing.current_process().name
         | 
| 311 | 
            +
                        pid = int(pname.rsplit("-", 1)[-1]) - 1
         | 
| 312 | 
            +
                        cuda_id = pid % total_gpus
         | 
| 313 | 
            +
                        device = f"cuda:{cuda_id}"
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                    if nerf: # single video
         | 
| 316 | 
            +
                        raw_img_dir = video_name.replace(".mp4", "/gt_imgs/").replace("/raw/","/processed/")
         | 
| 317 | 
            +
                    else: # whole dataset
         | 
| 318 | 
            +
                        raw_img_dir = video_name.replace(".mp4", "").replace("/video/", "/gt_imgs/")
         | 
| 319 | 
            +
                    if not os.path.exists(raw_img_dir):
         | 
| 320 | 
            +
                        extract_img_job(video_name, raw_img_dir) # use ffmpeg to split video into imgs
         | 
| 321 | 
            +
                    
         | 
| 322 | 
            +
                    img_names = glob.glob(os.path.join(raw_img_dir, "*.jpg"))
         | 
| 323 | 
            +
             | 
| 324 | 
            +
                    img_lst = []
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                    for img_name in img_names:
         | 
| 327 | 
            +
                        if store_in_memory:
         | 
| 328 | 
            +
                            img = load_rgb_image_to_path(img_name)
         | 
| 329 | 
            +
                        else:
         | 
| 330 | 
            +
                            img = img_name
         | 
| 331 | 
            +
                        img_lst.append(img)
         | 
| 332 | 
            +
             | 
| 333 | 
            +
                    print("| Extracting Segmaps && Saving...")
         | 
| 334 | 
            +
                    args = []
         | 
| 335 | 
            +
                    segmap_mask_lst = []
         | 
| 336 | 
            +
                    # preparing parameters for segment
         | 
| 337 | 
            +
                    for i in range(len(img_lst)):
         | 
| 338 | 
            +
                        img_name = img_names[i]
         | 
| 339 | 
            +
                        img = img_lst[i]
         | 
| 340 | 
            +
                        if multiprocess_enable: # create seg_model in subprocesses here
         | 
| 341 | 
            +
                            options = seg_model.options
         | 
| 342 | 
            +
                            segmenter_arg = None
         | 
| 343 | 
            +
                        else: # use seg_model of this process
         | 
| 344 | 
            +
                            options = None
         | 
| 345 | 
            +
                            segmenter_arg = segmenter
         | 
| 346 | 
            +
                        arg = (img_name, img, options, segmenter_arg, store_in_memory)
         | 
| 347 | 
            +
                        args.append(arg)
         | 
| 348 | 
            +
                        
         | 
| 349 | 
            +
                    if multiprocess_enable:
         | 
| 350 | 
            +
                        for (_, res) in multiprocess_run_tqdm(segment_and_generate_for_image_job, args=args, num_workers=16, desc='generating segment images in multi-processes...'):
         | 
| 351 | 
            +
                            segmap_mask = res
         | 
| 352 | 
            +
                            segmap_mask_lst.append(segmap_mask)
         | 
| 353 | 
            +
                    else:
         | 
| 354 | 
            +
                        for index in tqdm.tqdm(range(len(img_lst)), desc="generating segment images in single-process..."):
         | 
| 355 | 
            +
                            segmap_mask = segment_and_generate_for_image_job(*args[index])
         | 
| 356 | 
            +
                            segmap_mask_lst.append(segmap_mask)
         | 
| 357 | 
            +
                    print("| Extracted Segmaps Done.")
         | 
| 358 | 
            +
                    
         | 
| 359 | 
            +
                    print("| Extracting background...")
         | 
| 360 | 
            +
                    bg_prefix_name = f"bg{BG_NAME_MAP[background_method]}"
         | 
| 361 | 
            +
                    bg_img = extract_background(img_lst, segmap_mask_lst, method=background_method, device=device, mix_bg=mix_bg)
         | 
| 362 | 
            +
                    if nerf:
         | 
| 363 | 
            +
                        out_img_name = video_name.replace("/raw/", "/processed/").replace(".mp4", f"/{bg_prefix_name}.jpg")
         | 
| 364 | 
            +
                    else:
         | 
| 365 | 
            +
                        out_img_name = video_name.replace("/video/", f"/{bg_prefix_name}_img/").replace(".mp4", ".jpg")
         | 
| 366 | 
            +
                    save_rgb_image_to_path(bg_img, out_img_name)
         | 
| 367 | 
            +
                    print("| Extracted background done.")
         | 
| 368 | 
            +
                    
         | 
| 369 | 
            +
                    print("| Extracting com_imgs...")
         | 
| 370 | 
            +
                    com_prefix_name = f"com{BG_NAME_MAP[background_method]}"
         | 
| 371 | 
            +
                    for i in tqdm.trange(len(img_names), desc='extracting com_imgs'):
         | 
| 372 | 
            +
                        img_name = img_names[i]
         | 
| 373 | 
            +
                        com_img = refresh_image(img_lst[i]).copy()
         | 
| 374 | 
            +
                        segmap = refresh_segment_mask(segmap_mask_lst[i])
         | 
| 375 | 
            +
                        bg_part = segmap[0].astype(bool)[..., None].repeat(3,axis=-1)
         | 
| 376 | 
            +
                        com_img[bg_part] = bg_img[bg_part]
         | 
| 377 | 
            +
                        out_img_name = img_name.replace("/gt_imgs/", f"/{com_prefix_name}_imgs/")
         | 
| 378 | 
            +
                        save_rgb_image_to_path(com_img, out_img_name)
         | 
| 379 | 
            +
                    print("| Extracted com_imgs done.")
         | 
| 380 | 
            +
                    
         | 
| 381 | 
            +
                    return 0
         | 
| 382 | 
            +
                except Exception as e:
         | 
| 383 | 
            +
                    print(str(type(e)), e)
         | 
| 384 | 
            +
                    traceback.print_exc(e)
         | 
| 385 | 
            +
                    return 1
         | 
| 386 | 
            +
             | 
| 387 | 
            +
            def out_exist_job(vid_name, background_method='knn'):
         | 
| 388 | 
            +
                com_prefix_name = f"com{BG_NAME_MAP[background_method]}"
         | 
| 389 | 
            +
                img_dir = vid_name.replace("/video/", "/gt_imgs/").replace(".mp4", "")
         | 
| 390 | 
            +
                out_dir1 = img_dir.replace("/gt_imgs/", "/head_imgs/")
         | 
| 391 | 
            +
                out_dir2 = img_dir.replace("/gt_imgs/", f"/{com_prefix_name}_imgs/")
         | 
| 392 | 
            +
                
         | 
| 393 | 
            +
                if os.path.exists(img_dir) and os.path.exists(out_dir1) and os.path.exists(out_dir1) and os.path.exists(out_dir2) :
         | 
| 394 | 
            +
                    num_frames = len(os.listdir(img_dir))
         | 
| 395 | 
            +
                    if len(os.listdir(out_dir1)) == num_frames and len(os.listdir(out_dir2)) == num_frames:
         | 
| 396 | 
            +
                        return None
         | 
| 397 | 
            +
                    else:
         | 
| 398 | 
            +
                        return vid_name
         | 
| 399 | 
            +
                else:
         | 
| 400 | 
            +
                    return vid_name
         | 
| 401 | 
            +
             | 
| 402 | 
            +
            def get_todo_vid_names(vid_names, background_method='knn'):
         | 
| 403 | 
            +
                if len(vid_names) == 1: # nerf
         | 
| 404 | 
            +
                    return vid_names
         | 
| 405 | 
            +
                todo_vid_names = []
         | 
| 406 | 
            +
                fn_args = [(vid_name, background_method) for vid_name in vid_names]
         | 
| 407 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, fn_args, num_workers=16, desc="checking todo videos..."):
         | 
| 408 | 
            +
                    if res is not None:
         | 
| 409 | 
            +
                        todo_vid_names.append(res)
         | 
| 410 | 
            +
                return todo_vid_names
         | 
| 411 | 
            +
             | 
| 412 | 
            +
            if __name__ == '__main__':
         | 
| 413 | 
            +
                import argparse, glob, tqdm, random
         | 
| 414 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 415 | 
            +
                parser.add_argument("--vid_dir", default='/home/tiger/datasets/raw/TH1KH_512/video')
         | 
| 416 | 
            +
                parser.add_argument("--ds_name", default='TH1KH_512')
         | 
| 417 | 
            +
                parser.add_argument("--num_workers", default=48, type=int)
         | 
| 418 | 
            +
                parser.add_argument("--seed", default=0, type=int)
         | 
| 419 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 420 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 421 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 422 | 
            +
                parser.add_argument("--load_names", action="store_true")
         | 
| 423 | 
            +
                parser.add_argument("--background_method", choices=['knn', 'mat', 'ddnm', 'lama'], type=str, default='knn')
         | 
| 424 | 
            +
                parser.add_argument("--total_gpus", default=0, type=int) # zero gpus means utilizing cpu
         | 
| 425 | 
            +
                parser.add_argument("--no_mix_bg", action="store_true")
         | 
| 426 | 
            +
                parser.add_argument("--store_in_memory", action="store_true") # set to True to speed up preprocess, but leads to high memory costs
         | 
| 427 | 
            +
                parser.add_argument("--force_single_process", action="store_true") # turn this on if you find multi-process does not work on your environment
         | 
| 428 | 
            +
             | 
| 429 | 
            +
                args = parser.parse_args()
         | 
| 430 | 
            +
                vid_dir = args.vid_dir
         | 
| 431 | 
            +
                ds_name = args.ds_name
         | 
| 432 | 
            +
                load_names = args.load_names
         | 
| 433 | 
            +
                background_method = args.background_method
         | 
| 434 | 
            +
                total_gpus = args.total_gpus
         | 
| 435 | 
            +
                mix_bg = not args.no_mix_bg
         | 
| 436 | 
            +
                store_in_memory = args.store_in_memory
         | 
| 437 | 
            +
                force_single_process = args.force_single_process
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                devices = os.environ.get('CUDA_VISIBLE_DEVICES', '').split(",")
         | 
| 440 | 
            +
                for d in devices[:total_gpus]:
         | 
| 441 | 
            +
                    os.system(f'pkill -f "voidgpu{d}"')
         | 
| 442 | 
            +
                    
         | 
| 443 | 
            +
                if ds_name.lower() == 'nerf': # 处理单个视频
         | 
| 444 | 
            +
                    vid_names = [vid_dir]
         | 
| 445 | 
            +
                    out_names = [video_name.replace("/raw/", "/processed/").replace(".mp4","_lms.npy") for video_name in vid_names]
         | 
| 446 | 
            +
                else: # 处理整个数据集
         | 
| 447 | 
            +
                    if ds_name in ['lrs3_trainval']:
         | 
| 448 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 449 | 
            +
                    elif ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 450 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*.mp4")
         | 
| 451 | 
            +
                    elif ds_name in ['lrs2', 'lrs3', 'voxceleb2']:
         | 
| 452 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 453 | 
            +
                    elif ds_name in ["RAVDESS", 'VFHQ']:
         | 
| 454 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*/*.mp4")
         | 
| 455 | 
            +
                    else:
         | 
| 456 | 
            +
                        raise NotImplementedError()
         | 
| 457 | 
            +
                    
         | 
| 458 | 
            +
                    vid_names_path = os.path.join(vid_dir, "vid_names.pkl")
         | 
| 459 | 
            +
                    if os.path.exists(vid_names_path) and load_names:
         | 
| 460 | 
            +
                        print(f"loading vid names from {vid_names_path}")
         | 
| 461 | 
            +
                        vid_names = load_file(vid_names_path)
         | 
| 462 | 
            +
                    else:
         | 
| 463 | 
            +
                        vid_names = multiprocess_glob(vid_name_pattern)
         | 
| 464 | 
            +
                    vid_names = sorted(vid_names)
         | 
| 465 | 
            +
                    print(f"saving vid names to {vid_names_path}")
         | 
| 466 | 
            +
                    save_file(vid_names_path, vid_names)
         | 
| 467 | 
            +
             | 
| 468 | 
            +
                vid_names = sorted(vid_names)
         | 
| 469 | 
            +
                random.seed(args.seed)
         | 
| 470 | 
            +
                random.shuffle(vid_names)
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                process_id = args.process_id
         | 
| 473 | 
            +
                total_process = args.total_process
         | 
| 474 | 
            +
                if total_process > 1:
         | 
| 475 | 
            +
                    assert process_id <= total_process -1
         | 
| 476 | 
            +
                    num_samples_per_process = len(vid_names) // total_process
         | 
| 477 | 
            +
                    if process_id == total_process:
         | 
| 478 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 479 | 
            +
                    else:
         | 
| 480 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 481 | 
            +
                
         | 
| 482 | 
            +
                if not args.reset:
         | 
| 483 | 
            +
                    vid_names = get_todo_vid_names(vid_names, background_method)
         | 
| 484 | 
            +
                print(f"todo videos number: {len(vid_names)}")
         | 
| 485 | 
            +
             | 
| 486 | 
            +
                device = "cuda" if total_gpus > 0 else "cpu"
         | 
| 487 | 
            +
                extract_job = extract_segment_job
         | 
| 488 | 
            +
                fn_args = [(vid_name, ds_name=='nerf', background_method, device, total_gpus, mix_bg, store_in_memory, force_single_process) for i, vid_name in enumerate(vid_names)]
         | 
| 489 | 
            +
                    
         | 
| 490 | 
            +
                if ds_name == 'nerf': # 处理单个视频
         | 
| 491 | 
            +
                    extract_job(*fn_args[0])
         | 
| 492 | 
            +
                else:
         | 
| 493 | 
            +
                    for vid_name in multiprocess_run_tqdm(extract_job, fn_args, desc=f"Root process {args.process_id}:  segment images", num_workers=args.num_workers):
         | 
| 494 | 
            +
                        pass
         | 
    	
        data_gen/utils/process_video/fit_3dmm_landmark.py
    ADDED
    
    | @@ -0,0 +1,565 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # This is a script for efficienct 3DMM coefficient extraction.
         | 
| 2 | 
            +
            # It could reconstruct accurate 3D face in real-time.
         | 
| 3 | 
            +
            # It is built upon BFM 2009 model and mediapipe landmark extractor.
         | 
| 4 | 
            +
            # It is authored by ZhenhuiYe ([email protected]), free to contact him for any suggestion on improvement!
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            from numpy.core.numeric import require
         | 
| 7 | 
            +
            from numpy.lib.function_base import quantile
         | 
| 8 | 
            +
            import torch
         | 
| 9 | 
            +
            import torch.nn.functional as F
         | 
| 10 | 
            +
            import copy
         | 
| 11 | 
            +
            import numpy as np
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            import random
         | 
| 14 | 
            +
            import pickle
         | 
| 15 | 
            +
            import os
         | 
| 16 | 
            +
            import sys
         | 
| 17 | 
            +
            import cv2
         | 
| 18 | 
            +
            import argparse
         | 
| 19 | 
            +
            import tqdm
         | 
| 20 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 21 | 
            +
            from data_gen.utils.mp_feature_extractors.face_landmarker import MediapipeLandmarker, read_video_to_frames
         | 
| 22 | 
            +
            from deep_3drecon.deep_3drecon_models.bfm import ParametricFaceModel
         | 
| 23 | 
            +
            from deep_3drecon.secc_renderer import SECC_Renderer
         | 
| 24 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            face_model = ParametricFaceModel(bfm_folder='deep_3drecon/BFM', 
         | 
| 28 | 
            +
                        camera_distance=10, focal=1015, keypoint_mode='mediapipe')
         | 
| 29 | 
            +
            face_model.to(torch.device("cuda:0"))
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            dir_path = os.path.dirname(os.path.realpath(__file__))
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| 34 | 
            +
            def draw_axes(img, pitch, yaw, roll, tx, ty, size=50):
         | 
| 35 | 
            +
                # yaw = -yaw
         | 
| 36 | 
            +
                pitch = - pitch
         | 
| 37 | 
            +
                roll = - roll
         | 
| 38 | 
            +
                rotation_matrix = cv2.Rodrigues(np.array([pitch, yaw, roll]))[0].astype(np.float64)
         | 
| 39 | 
            +
                axes_points = np.array([
         | 
| 40 | 
            +
                    [1, 0, 0, 0],
         | 
| 41 | 
            +
                    [0, 1, 0, 0],
         | 
| 42 | 
            +
                    [0, 0, 1, 0]
         | 
| 43 | 
            +
                ], dtype=np.float64)
         | 
| 44 | 
            +
                axes_points = rotation_matrix @ axes_points
         | 
| 45 | 
            +
                axes_points = (axes_points[:2, :] * size).astype(int)
         | 
| 46 | 
            +
                axes_points[0, :] = axes_points[0, :] + tx
         | 
| 47 | 
            +
                axes_points[1, :] = axes_points[1, :] + ty
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                new_img = img.copy()
         | 
| 50 | 
            +
                cv2.line(new_img, tuple(axes_points[:, 3].ravel()), tuple(axes_points[:, 0].ravel()), (255, 0, 0), 3)    
         | 
| 51 | 
            +
                cv2.line(new_img, tuple(axes_points[:, 3].ravel()), tuple(axes_points[:, 1].ravel()), (0, 255, 0), 3)    
         | 
| 52 | 
            +
                cv2.line(new_img, tuple(axes_points[:, 3].ravel()), tuple(axes_points[:, 2].ravel()), (0, 0, 255), 3)
         | 
| 53 | 
            +
                return new_img
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            def save_file(name, content):
         | 
| 56 | 
            +
                with open(name, "wb") as f:
         | 
| 57 | 
            +
                    pickle.dump(content, f) 
         | 
| 58 | 
            +
                    
         | 
| 59 | 
            +
            def load_file(name):
         | 
| 60 | 
            +
                with open(name, "rb") as f:
         | 
| 61 | 
            +
                    content = pickle.load(f)
         | 
| 62 | 
            +
                return content
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            def cal_lap_loss(in_tensor):
         | 
| 65 | 
            +
                # [T, 68, 2]
         | 
| 66 | 
            +
                t = in_tensor.shape[0]
         | 
| 67 | 
            +
                in_tensor = in_tensor.reshape([t, -1]).permute(1,0).unsqueeze(1) # [c, 1, t]
         | 
| 68 | 
            +
                in_tensor = torch.cat([in_tensor[:, :, 0:1], in_tensor, in_tensor[:, :, -1:]], dim=-1)
         | 
| 69 | 
            +
                lap_kernel = torch.Tensor((-0.5, 1.0, -0.5)).reshape([1,1,3]).float().to(in_tensor.device) # [1, 1, kw]
         | 
| 70 | 
            +
                loss_lap = 0
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                out_tensor = F.conv1d(in_tensor, lap_kernel)
         | 
| 73 | 
            +
                loss_lap += torch.mean(out_tensor**2)
         | 
| 74 | 
            +
                return loss_lap
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            def cal_vel_loss(ldm):
         | 
| 77 | 
            +
                # [B, 68, 2]
         | 
| 78 | 
            +
                vel = ldm[1:] - ldm[:-1]
         | 
| 79 | 
            +
                return torch.mean(torch.abs(vel))
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            def cal_lan_loss(proj_lan, gt_lan):
         | 
| 82 | 
            +
                # [B, 68, 2]
         | 
| 83 | 
            +
                loss = (proj_lan - gt_lan)** 2
         | 
| 84 | 
            +
                # use the ldm weights from deep3drecon, see deep_3drecon/deep_3drecon_models/losses.py
         | 
| 85 | 
            +
                weights = torch.zeros_like(loss)
         | 
| 86 | 
            +
                weights = torch.ones_like(loss)
         | 
| 87 | 
            +
                weights[:, 36:48, :] = 3 # eye 12 points
         | 
| 88 | 
            +
                weights[:, -8:, :] =  3 # inner lip 8 points
         | 
| 89 | 
            +
                weights[:, 28:31, :] =  3 # nose 3 points
         | 
| 90 | 
            +
                loss = loss * weights
         | 
| 91 | 
            +
                return torch.mean(loss)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            def cal_lan_loss_mp(proj_lan, gt_lan, mean:bool=True):
         | 
| 94 | 
            +
                # [B, 68, 2]
         | 
| 95 | 
            +
                loss = (proj_lan - gt_lan).pow(2)
         | 
| 96 | 
            +
                # loss = (proj_lan - gt_lan).abs()
         | 
| 97 | 
            +
                unmatch_mask = [ 93, 127, 132, 234, 323, 356, 361, 454]
         | 
| 98 | 
            +
                upper_eye = [161,160,159,158,157] + [388,387,386,385,384]
         | 
| 99 | 
            +
                eye = [33,246,161,160,159,158,157,173,133,155,154,153,145,144,163,7] + [263,466,388,387,386,385,384,398,362,382,381,380,374,373,390,249]
         | 
| 100 | 
            +
                inner_lip = [78,191,80,81,82,13,312,311,310,415,308,324,318,402,317,14,87,178,88,95]
         | 
| 101 | 
            +
                outer_lip = [61,185,40,39,37,0,267,269,270,409,291,375,321,405,314,17,84,181,91,146]
         | 
| 102 | 
            +
                weights = torch.ones_like(loss)
         | 
| 103 | 
            +
                weights[:, eye] = 3
         | 
| 104 | 
            +
                weights[:, upper_eye] = 20
         | 
| 105 | 
            +
                weights[:, inner_lip] = 5
         | 
| 106 | 
            +
                weights[:, outer_lip] = 5
         | 
| 107 | 
            +
                weights[:, unmatch_mask] = 0
         | 
| 108 | 
            +
                loss = loss * weights
         | 
| 109 | 
            +
                if mean:
         | 
| 110 | 
            +
                    loss = torch.mean(loss)
         | 
| 111 | 
            +
                return loss
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            def cal_acceleration_loss(trans):
         | 
| 114 | 
            +
                vel = trans[1:] - trans[:-1]
         | 
| 115 | 
            +
                acc = vel[1:] - vel[:-1]
         | 
| 116 | 
            +
                return torch.mean(torch.abs(acc))
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            def cal_acceleration_ldm_loss(ldm):
         | 
| 119 | 
            +
                # [B, 68, 2]
         | 
| 120 | 
            +
                vel = ldm[1:] - ldm[:-1]
         | 
| 121 | 
            +
                acc = vel[1:] - vel[:-1]
         | 
| 122 | 
            +
                lip_weight = 0.25 # we dont want smooth the lip too much
         | 
| 123 | 
            +
                acc[48:68] *= lip_weight
         | 
| 124 | 
            +
                return torch.mean(torch.abs(acc))
         | 
| 125 | 
            +
             
         | 
| 126 | 
            +
            def set_requires_grad(tensor_list):
         | 
| 127 | 
            +
                for tensor in tensor_list:
         | 
| 128 | 
            +
                    tensor.requires_grad = True
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            @torch.enable_grad()
         | 
| 131 | 
            +
            def fit_3dmm_for_a_video(
         | 
| 132 | 
            +
                video_name, 
         | 
| 133 | 
            +
                nerf=False, # use the file name convention for GeneFace++
         | 
| 134 | 
            +
                id_mode='global', 
         | 
| 135 | 
            +
                debug=False, 
         | 
| 136 | 
            +
                keypoint_mode='mediapipe',
         | 
| 137 | 
            +
                large_yaw_threshold=9999999.9,
         | 
| 138 | 
            +
                save=True
         | 
| 139 | 
            +
            ) -> bool: # True: good, False: bad 
         | 
| 140 | 
            +
                assert video_name.endswith(".mp4"), "this function only support video as input"
         | 
| 141 | 
            +
                if id_mode == 'global':
         | 
| 142 | 
            +
                    LAMBDA_REG_ID = 0.2
         | 
| 143 | 
            +
                    LAMBDA_REG_EXP = 0.6
         | 
| 144 | 
            +
                    LAMBDA_REG_LAP = 1.0
         | 
| 145 | 
            +
                    LAMBDA_REG_VEL_ID = 0.0 # laplcaian is all you need for temporal consistency
         | 
| 146 | 
            +
                    LAMBDA_REG_VEL_EXP = 0.0 # laplcaian is all you need for temporal consistency
         | 
| 147 | 
            +
                else:
         | 
| 148 | 
            +
                    LAMBDA_REG_ID = 0.3
         | 
| 149 | 
            +
                    LAMBDA_REG_EXP = 0.05
         | 
| 150 | 
            +
                    LAMBDA_REG_LAP = 1.0
         | 
| 151 | 
            +
                    LAMBDA_REG_VEL_ID = 0.0 # laplcaian is all you need for temporal consistency
         | 
| 152 | 
            +
                    LAMBDA_REG_VEL_EXP = 0.0 # laplcaian is all you need for temporal consistency
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                frames = read_video_to_frames(video_name) # [T, H, W, 3]
         | 
| 155 | 
            +
                img_h, img_w = frames.shape[1], frames.shape[2]
         | 
| 156 | 
            +
                assert img_h == img_w
         | 
| 157 | 
            +
                num_frames = len(frames)
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                if nerf: # single video
         | 
| 160 | 
            +
                    lm_name = video_name.replace("/raw/", "/processed/").replace(".mp4","/lms_2d.npy")
         | 
| 161 | 
            +
                else:
         | 
| 162 | 
            +
                    lm_name = video_name.replace("/video/", "/lms_2d/").replace(".mp4", "_lms.npy")
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                if os.path.exists(lm_name):
         | 
| 165 | 
            +
                    lms = np.load(lm_name)
         | 
| 166 | 
            +
                else:
         | 
| 167 | 
            +
                    print(f"lms_2d file not found, try to extract it from video... {lm_name}")
         | 
| 168 | 
            +
                    try:
         | 
| 169 | 
            +
                        landmarker = MediapipeLandmarker()
         | 
| 170 | 
            +
                        img_lm478, vid_lm478 = landmarker.extract_lm478_from_frames(frames, anti_smooth_factor=20)
         | 
| 171 | 
            +
                        lms = landmarker.combine_vid_img_lm478_to_lm478(img_lm478, vid_lm478)
         | 
| 172 | 
            +
                    except Exception as e:
         | 
| 173 | 
            +
                        print(e)
         | 
| 174 | 
            +
                        return False
         | 
| 175 | 
            +
                    if lms is None:
         | 
| 176 | 
            +
                        print(f"get None lms_2d, please check whether each frame has one head, exiting... {lm_name}")
         | 
| 177 | 
            +
                        return False
         | 
| 178 | 
            +
                lms = lms[:, :468, :]
         | 
| 179 | 
            +
                lms = torch.FloatTensor(lms).cuda()
         | 
| 180 | 
            +
                lms[..., 1] = img_h - lms[..., 1] # flip the height axis
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                if keypoint_mode == 'mediapipe':
         | 
| 183 | 
            +
                    # default
         | 
| 184 | 
            +
                    cal_lan_loss_fn = cal_lan_loss_mp
         | 
| 185 | 
            +
                    if nerf: # single video
         | 
| 186 | 
            +
                        out_name = video_name.replace("/raw/", "/processed/").replace(".mp4", "/coeff_fit_mp.npy")
         | 
| 187 | 
            +
                    else:
         | 
| 188 | 
            +
                        out_name = video_name.replace("/video/", "/coeff_fit_mp/").replace(".mp4", "_coeff_fit_mp.npy")
         | 
| 189 | 
            +
                else:
         | 
| 190 | 
            +
                    # lm68 is less accurate than mp
         | 
| 191 | 
            +
                    cal_lan_loss_fn = cal_lan_loss
         | 
| 192 | 
            +
                    if nerf: # single video
         | 
| 193 | 
            +
                        out_name = video_name.replace("/raw/", "/processed/").replace(".mp4", "_coeff_fit_lm68.npy")
         | 
| 194 | 
            +
                    else:
         | 
| 195 | 
            +
                        out_name = video_name.replace("/video/", "/coeff_fit_lm68/").replace(".mp4", "_coeff_fit_lm68.npy")
         | 
| 196 | 
            +
                try:
         | 
| 197 | 
            +
                    os.makedirs(os.path.dirname(out_name), exist_ok=True)
         | 
| 198 | 
            +
                except:
         | 
| 199 | 
            +
                    pass
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                id_dim, exp_dim = 80, 64
         | 
| 202 | 
            +
                sel_ids = np.arange(0, num_frames, 40)
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                h = w = face_model.center * 2
         | 
| 205 | 
            +
                img_scale_factor = img_h / h
         | 
| 206 | 
            +
                lms /= img_scale_factor # rescale lms into [0,224]
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                if id_mode == 'global':
         | 
| 209 | 
            +
                    # default choice by GeneFace++ and later works
         | 
| 210 | 
            +
                    id_para = lms.new_zeros((1, id_dim), requires_grad=True)
         | 
| 211 | 
            +
                elif id_mode == 'finegrained':
         | 
| 212 | 
            +
                    # legacy choice by GeneFace1 (ICLR 2023)
         | 
| 213 | 
            +
                    id_para = lms.new_zeros((num_frames, id_dim), requires_grad=True)
         | 
| 214 | 
            +
                else: raise NotImplementedError(f"id mode {id_mode} not supported! we only support global or finegrained.")
         | 
| 215 | 
            +
                exp_para = lms.new_zeros((num_frames, exp_dim), requires_grad=True)
         | 
| 216 | 
            +
                euler_angle = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 217 | 
            +
                trans = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                set_requires_grad([id_para, exp_para, euler_angle, trans])
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                optimizer_idexp = torch.optim.Adam([id_para, exp_para], lr=.1)
         | 
| 222 | 
            +
                optimizer_frame = torch.optim.Adam([euler_angle, trans], lr=.1)
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                # 其他参数初始化,先训练euler和trans
         | 
| 225 | 
            +
                for _ in range(200):
         | 
| 226 | 
            +
                    if id_mode == 'global':
         | 
| 227 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 228 | 
            +
                            id_para.expand((num_frames, id_dim)), exp_para, euler_angle, trans)
         | 
| 229 | 
            +
                    else:
         | 
| 230 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 231 | 
            +
                            id_para, exp_para, euler_angle, trans)
         | 
| 232 | 
            +
                    loss_lan = cal_lan_loss_fn(proj_geo[:, :, :2], lms.detach())
         | 
| 233 | 
            +
                    loss = loss_lan
         | 
| 234 | 
            +
                    optimizer_frame.zero_grad()
         | 
| 235 | 
            +
                    loss.backward()
         | 
| 236 | 
            +
                    optimizer_frame.step()
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                # print(f"loss_lan: {loss_lan.item():.2f}, euler_abs_mean: {euler_angle.abs().mean().item():.4f}, euler_std: {euler_angle.std().item():.4f}, euler_min: {euler_angle.min().item():.4f}, euler_max: {euler_angle.max().item():.4f}")
         | 
| 239 | 
            +
                # print(f"trans_z_mean: {trans[...,2].mean().item():.4f}, trans_z_std: {trans[...,2].std().item():.4f}, trans_min: {trans[...,2].min().item():.4f}, trans_max: {trans[...,2].max().item():.4f}")
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                for param_group in optimizer_frame.param_groups:
         | 
| 242 | 
            +
                    param_group['lr'] = 0.1
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                # "jointly roughly training id exp euler trans"
         | 
| 245 | 
            +
                for _ in range(200):
         | 
| 246 | 
            +
                    ret = {}
         | 
| 247 | 
            +
                    if id_mode == 'global':
         | 
| 248 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 249 | 
            +
                            id_para.expand((num_frames, id_dim)), exp_para, euler_angle, trans, ret)
         | 
| 250 | 
            +
                    else:
         | 
| 251 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 252 | 
            +
                            id_para, exp_para, euler_angle, trans, ret)
         | 
| 253 | 
            +
                    loss_lan = cal_lan_loss_fn(
         | 
| 254 | 
            +
                        proj_geo[:, :, :2], lms.detach())
         | 
| 255 | 
            +
                    # loss_lap = cal_lap_loss(proj_geo)
         | 
| 256 | 
            +
                    # laplacian对euler影响不大,但是对trans的提升很大
         | 
| 257 | 
            +
                    loss_lap = cal_lap_loss(id_para) + cal_lap_loss(exp_para) + cal_lap_loss(euler_angle) * 0.3 + cal_lap_loss(trans) * 0.3
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                    loss_regid = torch.mean(id_para*id_para) # 正则化
         | 
| 260 | 
            +
                    loss_regexp = torch.mean(exp_para * exp_para)
         | 
| 261 | 
            +
             | 
| 262 | 
            +
                    loss_vel_id = cal_vel_loss(id_para)
         | 
| 263 | 
            +
                    loss_vel_exp = cal_vel_loss(exp_para)
         | 
| 264 | 
            +
                    loss = loss_lan  + loss_regid * LAMBDA_REG_ID + loss_regexp * LAMBDA_REG_EXP  + loss_vel_id * LAMBDA_REG_VEL_ID + loss_vel_exp * LAMBDA_REG_VEL_EXP + loss_lap * LAMBDA_REG_LAP
         | 
| 265 | 
            +
                    optimizer_idexp.zero_grad()
         | 
| 266 | 
            +
                    optimizer_frame.zero_grad()
         | 
| 267 | 
            +
                    loss.backward()
         | 
| 268 | 
            +
                    optimizer_idexp.step()
         | 
| 269 | 
            +
                    optimizer_frame.step()
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                # print(f"loss_lan: {loss_lan.item():.2f}, loss_reg_id: {loss_regid.item():.2f},loss_reg_exp: {loss_regexp.item():.2f},")
         | 
| 272 | 
            +
                # print(f"euler_abs_mean: {euler_angle.abs().mean().item():.4f}, euler_std: {euler_angle.std().item():.4f}, euler_min: {euler_angle.min().item():.4f}, euler_max: {euler_angle.max().item():.4f}")
         | 
| 273 | 
            +
                # print(f"trans_z_mean: {trans[...,2].mean().item():.4f}, trans_z_std: {trans[...,2].std().item():.4f}, trans_min: {trans[...,2].min().item():.4f}, trans_max: {trans[...,2].max().item():.4f}")
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                # start fine training, intialize from the roughly trained results
         | 
| 276 | 
            +
                if id_mode == 'global':
         | 
| 277 | 
            +
                    id_para_ = lms.new_zeros((1, id_dim), requires_grad=False)
         | 
| 278 | 
            +
                else:
         | 
| 279 | 
            +
                    id_para_ = lms.new_zeros((num_frames, id_dim), requires_grad=True)
         | 
| 280 | 
            +
                id_para_.data = id_para.data.clone()
         | 
| 281 | 
            +
                id_para = id_para_
         | 
| 282 | 
            +
                exp_para_ = lms.new_zeros((num_frames, exp_dim), requires_grad=True)
         | 
| 283 | 
            +
                exp_para_.data = exp_para.data.clone()
         | 
| 284 | 
            +
                exp_para = exp_para_
         | 
| 285 | 
            +
                euler_angle_ = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 286 | 
            +
                euler_angle_.data = euler_angle.data.clone()
         | 
| 287 | 
            +
                euler_angle = euler_angle_
         | 
| 288 | 
            +
                trans_ = lms.new_zeros((num_frames, 3), requires_grad=True)
         | 
| 289 | 
            +
                trans_.data = trans.data.clone()
         | 
| 290 | 
            +
                trans = trans_
         | 
| 291 | 
            +
                
         | 
| 292 | 
            +
                batch_size = 50
         | 
| 293 | 
            +
                # "fine fitting the 3DMM in batches"
         | 
| 294 | 
            +
                for i in range(int((num_frames-1)/batch_size+1)):
         | 
| 295 | 
            +
                    if (i+1)*batch_size > num_frames:
         | 
| 296 | 
            +
                        start_n = num_frames-batch_size
         | 
| 297 | 
            +
                        sel_ids = np.arange(max(num_frames-batch_size,0), num_frames)
         | 
| 298 | 
            +
                    else:
         | 
| 299 | 
            +
                        start_n = i*batch_size
         | 
| 300 | 
            +
                        sel_ids = np.arange(i*batch_size, i*batch_size+batch_size)
         | 
| 301 | 
            +
                    sel_lms = lms[sel_ids]
         | 
| 302 | 
            +
             | 
| 303 | 
            +
                    if id_mode == 'global':
         | 
| 304 | 
            +
                        sel_id_para = id_para.expand((sel_ids.shape[0], id_dim))
         | 
| 305 | 
            +
                    else:
         | 
| 306 | 
            +
                        sel_id_para = id_para.new_zeros((batch_size, id_dim), requires_grad=True)
         | 
| 307 | 
            +
                        sel_id_para.data = id_para[sel_ids].clone()
         | 
| 308 | 
            +
                    sel_exp_para = exp_para.new_zeros(
         | 
| 309 | 
            +
                        (batch_size, exp_dim), requires_grad=True)
         | 
| 310 | 
            +
                    sel_exp_para.data = exp_para[sel_ids].clone()
         | 
| 311 | 
            +
                    sel_euler_angle = euler_angle.new_zeros(
         | 
| 312 | 
            +
                        (batch_size, 3), requires_grad=True)
         | 
| 313 | 
            +
                    sel_euler_angle.data = euler_angle[sel_ids].clone()
         | 
| 314 | 
            +
                    sel_trans = trans.new_zeros((batch_size, 3), requires_grad=True)
         | 
| 315 | 
            +
                    sel_trans.data = trans[sel_ids].clone()
         | 
| 316 | 
            +
                    
         | 
| 317 | 
            +
                    if id_mode == 'global':
         | 
| 318 | 
            +
                        set_requires_grad([sel_exp_para, sel_euler_angle, sel_trans])
         | 
| 319 | 
            +
                        optimizer_cur_batch = torch.optim.Adam(
         | 
| 320 | 
            +
                            [sel_exp_para, sel_euler_angle, sel_trans], lr=0.005)
         | 
| 321 | 
            +
                    else:
         | 
| 322 | 
            +
                        set_requires_grad([sel_id_para, sel_exp_para, sel_euler_angle, sel_trans])
         | 
| 323 | 
            +
                        optimizer_cur_batch = torch.optim.Adam(
         | 
| 324 | 
            +
                            [sel_id_para, sel_exp_para, sel_euler_angle, sel_trans], lr=0.005)
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                    for j in range(50):
         | 
| 327 | 
            +
                        ret = {}
         | 
| 328 | 
            +
                        proj_geo = face_model.compute_for_landmark_fit(
         | 
| 329 | 
            +
                            sel_id_para, sel_exp_para, sel_euler_angle, sel_trans, ret)
         | 
| 330 | 
            +
                        loss_lan = cal_lan_loss_fn(
         | 
| 331 | 
            +
                            proj_geo[:, :, :2], lms[sel_ids].detach())
         | 
| 332 | 
            +
                        
         | 
| 333 | 
            +
                        # loss_lap = cal_lap_loss(proj_geo)
         | 
| 334 | 
            +
                        loss_lap = cal_lap_loss(sel_id_para) + cal_lap_loss(sel_exp_para) + cal_lap_loss(sel_euler_angle) * 0.3 + cal_lap_loss(sel_trans) * 0.3
         | 
| 335 | 
            +
                        loss_vel_id = cal_vel_loss(sel_id_para)
         | 
| 336 | 
            +
                        loss_vel_exp = cal_vel_loss(sel_exp_para)
         | 
| 337 | 
            +
                        log_dict = {
         | 
| 338 | 
            +
                            'loss_vel_id': loss_vel_id,
         | 
| 339 | 
            +
                            'loss_vel_exp': loss_vel_exp,
         | 
| 340 | 
            +
                            'loss_vel_euler': cal_vel_loss(sel_euler_angle),
         | 
| 341 | 
            +
                            'loss_vel_trans': cal_vel_loss(sel_trans),
         | 
| 342 | 
            +
                        }
         | 
| 343 | 
            +
                        loss_regid = torch.mean(sel_id_para*sel_id_para) # 正则化
         | 
| 344 | 
            +
                        loss_regexp = torch.mean(sel_exp_para*sel_exp_para)
         | 
| 345 | 
            +
                        loss = loss_lan + loss_regid * LAMBDA_REG_ID + loss_regexp * LAMBDA_REG_EXP + loss_lap * LAMBDA_REG_LAP + loss_vel_id * LAMBDA_REG_VEL_ID + loss_vel_exp * LAMBDA_REG_VEL_EXP
         | 
| 346 | 
            +
             | 
| 347 | 
            +
                        optimizer_cur_batch.zero_grad()
         | 
| 348 | 
            +
                        loss.backward()
         | 
| 349 | 
            +
                        optimizer_cur_batch.step()
         | 
| 350 | 
            +
                        
         | 
| 351 | 
            +
                    if debug:
         | 
| 352 | 
            +
                        print(f"batch {i} | loss_lan: {loss_lan.item():.2f}, loss_reg_id: {loss_regid.item():.2f},loss_reg_exp: {loss_regexp.item():.2f},loss_lap_ldm:{loss_lap.item():.4f}")
         | 
| 353 | 
            +
                        print("|--------" + ', '.join([f"{k}: {v:.4f}" for k,v in log_dict.items()]))
         | 
| 354 | 
            +
                    if id_mode != 'global':
         | 
| 355 | 
            +
                        id_para[sel_ids].data = sel_id_para.data.clone()
         | 
| 356 | 
            +
                    exp_para[sel_ids].data = sel_exp_para.data.clone()
         | 
| 357 | 
            +
                    euler_angle[sel_ids].data = sel_euler_angle.data.clone()
         | 
| 358 | 
            +
                    trans[sel_ids].data = sel_trans.data.clone()
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                coeff_dict = {'id': id_para.detach().cpu().numpy(), 'exp': exp_para.detach().cpu().numpy(),
         | 
| 361 | 
            +
                            'euler': euler_angle.detach().cpu().numpy(), 'trans': trans.detach().cpu().numpy()}
         | 
| 362 | 
            +
             | 
| 363 | 
            +
                # filter data by side-view pose    
         | 
| 364 | 
            +
                # bad_yaw = False
         | 
| 365 | 
            +
                # yaws = [] # not so accurate
         | 
| 366 | 
            +
                # for index in range(coeff_dict["trans"].shape[0]):
         | 
| 367 | 
            +
                #     yaw = coeff_dict["euler"][index][1]
         | 
| 368 | 
            +
                #     yaw = np.abs(yaw)
         | 
| 369 | 
            +
                #     yaws.append(yaw)
         | 
| 370 | 
            +
                #     if yaw > large_yaw_threshold:
         | 
| 371 | 
            +
                #         bad_yaw = True
         | 
| 372 | 
            +
                
         | 
| 373 | 
            +
                if debug:
         | 
| 374 | 
            +
                    import imageio
         | 
| 375 | 
            +
                    from utils.visualization.vis_cam3d.camera_pose_visualizer import CameraPoseVisualizer
         | 
| 376 | 
            +
                    from data_util.face3d_helper import Face3DHelper
         | 
| 377 | 
            +
                    from data_gen.utils.process_video.extract_blink import get_eye_area_percent
         | 
| 378 | 
            +
                    face3d_helper = Face3DHelper('deep_3drecon/BFM', keypoint_mode='mediapipe')
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                    t = coeff_dict['exp'].shape[0]
         | 
| 381 | 
            +
                    if len(coeff_dict['id']) == 1:
         | 
| 382 | 
            +
                        coeff_dict['id'] = np.repeat(coeff_dict['id'], t, axis=0)
         | 
| 383 | 
            +
                    idexp_lm3d = face3d_helper.reconstruct_idexp_lm3d_np(coeff_dict['id'], coeff_dict['exp']).reshape([t, -1])
         | 
| 384 | 
            +
                    cano_lm3d = idexp_lm3d / 10 + face3d_helper.key_mean_shape.squeeze().reshape([1, -1]).cpu().numpy()
         | 
| 385 | 
            +
                    cano_lm3d = cano_lm3d.reshape([t, -1, 3])
         | 
| 386 | 
            +
                    WH = 512
         | 
| 387 | 
            +
                    cano_lm3d = (cano_lm3d * WH/2 + WH/2).astype(int)
         | 
| 388 | 
            +
             | 
| 389 | 
            +
                    with torch.no_grad():
         | 
| 390 | 
            +
                        rot = ParametricFaceModel.compute_rotation(euler_angle)
         | 
| 391 | 
            +
                        extrinsic = torch.zeros([rot.shape[0], 4, 4]).to(rot.device)
         | 
| 392 | 
            +
                        extrinsic[:, :3,:3] = rot
         | 
| 393 | 
            +
                        extrinsic[:, :3, 3] = trans # / 10
         | 
| 394 | 
            +
                        extrinsic[:, 3, 3] = 1
         | 
| 395 | 
            +
                    extrinsic = extrinsic.cpu().numpy()
         | 
| 396 | 
            +
             | 
| 397 | 
            +
                    xy_camera_visualizer = CameraPoseVisualizer(xlim=[extrinsic[:,0,3].min().item()-0.5,extrinsic[:,0,3].max().item()+0.5],ylim=[extrinsic[:,1,3].min().item()-0.5,extrinsic[:,1,3].max().item()+0.5], zlim=[extrinsic[:,2,3].min().item()-0.5,extrinsic[:,2,3].max().item()+0.5], view_mode='xy')
         | 
| 398 | 
            +
                    xz_camera_visualizer = CameraPoseVisualizer(xlim=[extrinsic[:,0,3].min().item()-0.5,extrinsic[:,0,3].max().item()+0.5],ylim=[extrinsic[:,1,3].min().item()-0.5,extrinsic[:,1,3].max().item()+0.5], zlim=[extrinsic[:,2,3].min().item()-0.5,extrinsic[:,2,3].max().item()+0.5], view_mode='xz')
         | 
| 399 | 
            +
             | 
| 400 | 
            +
                    if nerf:
         | 
| 401 | 
            +
                        debug_name = video_name.replace("/raw/", "/processed/").replace(".mp4", "/debug_fit_3dmm.mp4")
         | 
| 402 | 
            +
                    else:
         | 
| 403 | 
            +
                        debug_name = video_name.replace("/video/", "/coeff_fit_debug/").replace(".mp4", "_debug.mp4")
         | 
| 404 | 
            +
                    try:
         | 
| 405 | 
            +
                        os.makedirs(os.path.dirname(debug_name), exist_ok=True)
         | 
| 406 | 
            +
                    except: pass
         | 
| 407 | 
            +
                    writer = imageio.get_writer(debug_name, fps=25)
         | 
| 408 | 
            +
                    if id_mode == 'global':
         | 
| 409 | 
            +
                        id_para = id_para.repeat([exp_para.shape[0], 1])
         | 
| 410 | 
            +
                    proj_geo = face_model.compute_for_landmark_fit(id_para, exp_para, euler_angle, trans)
         | 
| 411 | 
            +
                    lm68s = proj_geo[:,:,:2].detach().cpu().numpy()  # [T, 68,2]
         | 
| 412 | 
            +
                    lm68s = lm68s * img_scale_factor
         | 
| 413 | 
            +
                    lms = lms * img_scale_factor
         | 
| 414 | 
            +
                    lm68s[..., 1] = img_h - lm68s[..., 1] # flip the height axis
         | 
| 415 | 
            +
                    lms[..., 1] = img_h - lms[..., 1] # flip the height axis
         | 
| 416 | 
            +
                    lm68s = lm68s.astype(int)
         | 
| 417 | 
            +
                    for i in tqdm.trange(min(250, len(frames)), desc=f'rendering debug video to {debug_name}..'):
         | 
| 418 | 
            +
                        xy_cam3d_img = xy_camera_visualizer.extrinsic2pyramid(extrinsic[i], focal_len_scaled=0.25)
         | 
| 419 | 
            +
                        xy_cam3d_img = cv2.resize(xy_cam3d_img, (512,512))
         | 
| 420 | 
            +
                        xz_cam3d_img = xz_camera_visualizer.extrinsic2pyramid(extrinsic[i], focal_len_scaled=0.25)
         | 
| 421 | 
            +
                        xz_cam3d_img = cv2.resize(xz_cam3d_img, (512,512))
         | 
| 422 | 
            +
                        
         | 
| 423 | 
            +
                        img = copy.deepcopy(frames[i])
         | 
| 424 | 
            +
                        img2 = copy.deepcopy(frames[i])
         | 
| 425 | 
            +
             | 
| 426 | 
            +
                        img = draw_axes(img, euler_angle[i,0].item(), euler_angle[i,1].item(), euler_angle[i,2].item(), lm68s[i][4][0].item(), lm68s[i, 4][1].item(), size=50)
         | 
| 427 | 
            +
             | 
| 428 | 
            +
                        gt_lm_color = (255, 0, 0)
         | 
| 429 | 
            +
                            
         | 
| 430 | 
            +
                        for lm in lm68s[i]:
         | 
| 431 | 
            +
                            img = cv2.circle(img, lm, 1, (0, 0, 255), thickness=-1) # blue
         | 
| 432 | 
            +
                        for gt_lm in lms[i]:
         | 
| 433 | 
            +
                            img2 = cv2.circle(img2, gt_lm.cpu().numpy().astype(int), 2, gt_lm_color, thickness=1)
         | 
| 434 | 
            +
                        
         | 
| 435 | 
            +
                        cano_lm3d_img = np.ones([WH, WH, 3], dtype=np.uint8) * 255
         | 
| 436 | 
            +
                        for j in range(len(cano_lm3d[i])):
         | 
| 437 | 
            +
                            x, y, _ = cano_lm3d[i, j]
         | 
| 438 | 
            +
                            color = (255,0,0)
         | 
| 439 | 
            +
                            cano_lm3d_img = cv2.circle(cano_lm3d_img, center=(x,y), radius=3, color=color, thickness=-1)
         | 
| 440 | 
            +
                        cano_lm3d_img = cv2.flip(cano_lm3d_img, 0)
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                        _, secc_img = secc_renderer(id_para[0:1], exp_para[i:i+1], euler_angle[i:i+1]*0, trans[i:i+1]*0)
         | 
| 443 | 
            +
                        secc_img = (secc_img +1)*127.5
         | 
| 444 | 
            +
                        secc_img = F.interpolate(secc_img, size=(img_h, img_w))
         | 
| 445 | 
            +
                        secc_img = secc_img.permute(0, 2,3,1).int().cpu().numpy()[0]
         | 
| 446 | 
            +
                        out_img1 = np.concatenate([img, img2, secc_img], axis=1).astype(np.uint8)
         | 
| 447 | 
            +
                        font = cv2.FONT_HERSHEY_SIMPLEX
         | 
| 448 | 
            +
                        out_img2 = np.concatenate([xy_cam3d_img, xz_cam3d_img, cano_lm3d_img], axis=1).astype(np.uint8)
         | 
| 449 | 
            +
                        out_img = np.concatenate([out_img1, out_img2], axis=0)
         | 
| 450 | 
            +
                        writer.append_data(out_img)
         | 
| 451 | 
            +
                    writer.close()
         | 
| 452 | 
            +
                    
         | 
| 453 | 
            +
                # if bad_yaw:
         | 
| 454 | 
            +
                #     print(f"Skip {video_name} due to TOO LARGE YAW")
         | 
| 455 | 
            +
                #     return False
         | 
| 456 | 
            +
             | 
| 457 | 
            +
                if save:
         | 
| 458 | 
            +
                    np.save(out_name, coeff_dict, allow_pickle=True) 
         | 
| 459 | 
            +
                return coeff_dict
         | 
| 460 | 
            +
             | 
| 461 | 
            +
            def out_exist_job(vid_name):
         | 
| 462 | 
            +
                out_name = vid_name.replace("/video/", "/coeff_fit_mp/").replace(".mp4","_coeff_fit_mp.npy") 
         | 
| 463 | 
            +
                lms_name = vid_name.replace("/video/", "/lms_2d/").replace(".mp4","_lms.npy") 
         | 
| 464 | 
            +
                if os.path.exists(out_name) or not os.path.exists(lms_name):
         | 
| 465 | 
            +
                    return None
         | 
| 466 | 
            +
                else:
         | 
| 467 | 
            +
                    return vid_name
         | 
| 468 | 
            +
             | 
| 469 | 
            +
            def get_todo_vid_names(vid_names):
         | 
| 470 | 
            +
                if len(vid_names) == 1: # single video, nerf
         | 
| 471 | 
            +
                    return vid_names
         | 
| 472 | 
            +
                todo_vid_names = []
         | 
| 473 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, vid_names, num_workers=16):
         | 
| 474 | 
            +
                    if res is not None:
         | 
| 475 | 
            +
                        todo_vid_names.append(res)
         | 
| 476 | 
            +
                return todo_vid_names
         | 
| 477 | 
            +
             | 
| 478 | 
            +
             | 
| 479 | 
            +
            if __name__ == '__main__':
         | 
| 480 | 
            +
                import argparse, glob, tqdm
         | 
| 481 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 482 | 
            +
                # parser.add_argument("--vid_dir", default='/home/tiger/datasets/raw/CelebV-HQ/video')
         | 
| 483 | 
            +
                parser.add_argument("--vid_dir", default='data/raw/videos/May_10s.mp4')
         | 
| 484 | 
            +
                parser.add_argument("--ds_name", default='nerf') # 'nerf' | 'CelebV-HQ' | 'TH1KH_512' | etc
         | 
| 485 | 
            +
                parser.add_argument("--seed", default=0, type=int)
         | 
| 486 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 487 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 488 | 
            +
                parser.add_argument("--id_mode", default='global', type=str) # global | finegrained
         | 
| 489 | 
            +
                parser.add_argument("--keypoint_mode", default='mediapipe', type=str)
         | 
| 490 | 
            +
                parser.add_argument("--large_yaw_threshold", default=9999999.9, type=float) # could be 0.7
         | 
| 491 | 
            +
                parser.add_argument("--debug", action='store_true')
         | 
| 492 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 493 | 
            +
                parser.add_argument("--load_names", action="store_true")
         | 
| 494 | 
            +
             | 
| 495 | 
            +
                args = parser.parse_args()
         | 
| 496 | 
            +
                vid_dir = args.vid_dir
         | 
| 497 | 
            +
                ds_name = args.ds_name
         | 
| 498 | 
            +
                load_names = args.load_names
         | 
| 499 | 
            +
                
         | 
| 500 | 
            +
                print(f"args {args}")
         | 
| 501 | 
            +
                
         | 
| 502 | 
            +
                if ds_name.lower() == 'nerf': # 处理单个视频
         | 
| 503 | 
            +
                    vid_names = [vid_dir]
         | 
| 504 | 
            +
                    out_names = [video_name.replace("/raw/", "/processed/").replace(".mp4","_coeff_fit_mp.npy") for video_name in vid_names]
         | 
| 505 | 
            +
                else: # 处理整个数据集
         | 
| 506 | 
            +
                    if ds_name in ['lrs3_trainval']:
         | 
| 507 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 508 | 
            +
                    elif ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 509 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*.mp4")
         | 
| 510 | 
            +
                    elif ds_name in ['lrs2', 'lrs3', 'voxceleb2', 'CMLR']:
         | 
| 511 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 512 | 
            +
                    elif ds_name in ["RAVDESS", 'VFHQ']:
         | 
| 513 | 
            +
                        vid_name_pattern = os.path.join(vid_dir, "*/*/*/*.mp4")
         | 
| 514 | 
            +
                    else:
         | 
| 515 | 
            +
                        raise NotImplementedError()
         | 
| 516 | 
            +
                    
         | 
| 517 | 
            +
                    vid_names_path = os.path.join(vid_dir, "vid_names.pkl")
         | 
| 518 | 
            +
                    if os.path.exists(vid_names_path) and load_names:
         | 
| 519 | 
            +
                        print(f"loading vid names from {vid_names_path}")
         | 
| 520 | 
            +
                        vid_names = load_file(vid_names_path)
         | 
| 521 | 
            +
                    else:
         | 
| 522 | 
            +
                        vid_names = multiprocess_glob(vid_name_pattern)
         | 
| 523 | 
            +
                    vid_names = sorted(vid_names)
         | 
| 524 | 
            +
                    print(f"saving vid names to {vid_names_path}")
         | 
| 525 | 
            +
                    save_file(vid_names_path, vid_names)
         | 
| 526 | 
            +
                    out_names = [video_name.replace("/video/", "/coeff_fit_mp/").replace(".mp4","_coeff_fit_mp.npy") for video_name in vid_names]
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                print(vid_names[:10])
         | 
| 529 | 
            +
                random.seed(args.seed)
         | 
| 530 | 
            +
                random.shuffle(vid_names)
         | 
| 531 | 
            +
             | 
| 532 | 
            +
                face_model = ParametricFaceModel(bfm_folder='deep_3drecon/BFM', 
         | 
| 533 | 
            +
                            camera_distance=10, focal=1015, keypoint_mode=args.keypoint_mode)
         | 
| 534 | 
            +
                face_model.to(torch.device("cuda:0"))
         | 
| 535 | 
            +
                secc_renderer = SECC_Renderer(512)
         | 
| 536 | 
            +
                secc_renderer.to("cuda:0")
         | 
| 537 | 
            +
                
         | 
| 538 | 
            +
                process_id = args.process_id
         | 
| 539 | 
            +
                total_process = args.total_process
         | 
| 540 | 
            +
                if total_process > 1:
         | 
| 541 | 
            +
                    assert process_id <= total_process -1
         | 
| 542 | 
            +
                    num_samples_per_process = len(vid_names) // total_process
         | 
| 543 | 
            +
                    if process_id == total_process:
         | 
| 544 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 545 | 
            +
                    else:
         | 
| 546 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 547 | 
            +
             | 
| 548 | 
            +
                if not args.reset:
         | 
| 549 | 
            +
                    vid_names = get_todo_vid_names(vid_names)
         | 
| 550 | 
            +
             | 
| 551 | 
            +
                failed_img_names = []
         | 
| 552 | 
            +
                for i in tqdm.trange(len(vid_names), desc=f"process {process_id}: fitting 3dmm ..."):
         | 
| 553 | 
            +
                    img_name = vid_names[i]
         | 
| 554 | 
            +
                    try:
         | 
| 555 | 
            +
                        is_person_specific_data = ds_name=='nerf'
         | 
| 556 | 
            +
                        success = fit_3dmm_for_a_video(img_name, is_person_specific_data, args.id_mode, args.debug, large_yaw_threshold=args.large_yaw_threshold)
         | 
| 557 | 
            +
                        if not success:
         | 
| 558 | 
            +
                            failed_img_names.append(img_name)   
         | 
| 559 | 
            +
                    except Exception as e:
         | 
| 560 | 
            +
                        print(img_name, e)
         | 
| 561 | 
            +
                        failed_img_names.append(img_name)
         | 
| 562 | 
            +
                    print(f"finished {i + 1} / {len(vid_names)} = {(i + 1) / len(vid_names):.4f}, failed {len(failed_img_names)} / {i + 1} = {len(failed_img_names) / (i + 1):.4f}")
         | 
| 563 | 
            +
                    sys.stdout.flush()
         | 
| 564 | 
            +
                print(f"all failed image names: {failed_img_names}")
         | 
| 565 | 
            +
                print(f"All finished!")
         | 
    	
        data_gen/utils/process_video/inpaint_torso_imgs.py
    ADDED
    
    | @@ -0,0 +1,193 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import cv2
         | 
| 2 | 
            +
            import os
         | 
| 3 | 
            +
            import numpy as np
         | 
| 4 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 5 | 
            +
            from scipy.ndimage import binary_erosion, binary_dilation
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from tasks.eg3ds.loss_utils.segment_loss.mp_segmenter import MediapipeSegmenter
         | 
| 8 | 
            +
            seg_model = MediapipeSegmenter()
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            def inpaint_torso_job(video_name, idx=None, total=None):
         | 
| 11 | 
            +
                raw_img_dir = video_name.replace(".mp4", "").replace("/video/","/gt_imgs/")
         | 
| 12 | 
            +
                img_names = glob.glob(os.path.join(raw_img_dir, "*.jpg"))
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                for image_path in tqdm.tqdm(img_names):
         | 
| 15 | 
            +
                    # read ori image
         | 
| 16 | 
            +
                    ori_image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) # [H, W, 3]
         | 
| 17 | 
            +
                    segmap = seg_model._cal_seg_map(cv2.cvtColor(ori_image, cv2.COLOR_BGR2RGB))
         | 
| 18 | 
            +
                    head_part = (segmap[1] + segmap[3] + segmap[5]).astype(np.bool)
         | 
| 19 | 
            +
                    torso_part = (segmap[4]).astype(np.bool)
         | 
| 20 | 
            +
                    neck_part = (segmap[2]).astype(np.bool)
         | 
| 21 | 
            +
                    bg_part = segmap[0].astype(np.bool)
         | 
| 22 | 
            +
                    head_image = cv2.imread(image_path.replace("/gt_imgs/", "/head_imgs/"), cv2.IMREAD_UNCHANGED) # [H, W, 3]
         | 
| 23 | 
            +
                    torso_image = cv2.imread(image_path.replace("/gt_imgs/", "/torso_imgs/"), cv2.IMREAD_UNCHANGED) # [H, W, 3]
         | 
| 24 | 
            +
                    bg_image = cv2.imread(image_path.replace("/gt_imgs/", "/bg_imgs/"), cv2.IMREAD_UNCHANGED) # [H, W, 3]
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    # head_part = (head_image[...,0] != 0) & (head_image[...,1] != 0) & (head_image[...,2] != 0)
         | 
| 27 | 
            +
                    # torso_part = (torso_image[...,0] != 0) & (torso_image[...,1] != 0) & (torso_image[...,2] != 0)
         | 
| 28 | 
            +
                    # bg_part = (bg_image[...,0] != 0) & (bg_image[...,1] != 0) & (bg_image[...,2] != 0)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    # get gt image
         | 
| 31 | 
            +
                    gt_image = ori_image.copy()
         | 
| 32 | 
            +
                    gt_image[bg_part] = bg_image[bg_part]
         | 
| 33 | 
            +
                    cv2.imwrite(image_path.replace('ori_imgs', 'gt_imgs'), gt_image)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    # get torso image
         | 
| 36 | 
            +
                    torso_image = gt_image.copy() # rgb
         | 
| 37 | 
            +
                    torso_image[head_part] = 0
         | 
| 38 | 
            +
                    torso_alpha = 255 * np.ones((gt_image.shape[0], gt_image.shape[1], 1), dtype=np.uint8) # alpha
         | 
| 39 | 
            +
                    
         | 
| 40 | 
            +
                    # torso part "vertical" in-painting...
         | 
| 41 | 
            +
                    L = 8 + 1
         | 
| 42 | 
            +
                    torso_coords = np.stack(np.nonzero(torso_part), axis=-1) # [M, 2]
         | 
| 43 | 
            +
                    # lexsort: sort 2D coords first by y then by x, 
         | 
| 44 | 
            +
                    # ref: https://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple-axes
         | 
| 45 | 
            +
                    inds = np.lexsort((torso_coords[:, 0], torso_coords[:, 1]))
         | 
| 46 | 
            +
                    torso_coords = torso_coords[inds]
         | 
| 47 | 
            +
                    # choose the top pixel for each column
         | 
| 48 | 
            +
                    u, uid, ucnt = np.unique(torso_coords[:, 1], return_index=True, return_counts=True)
         | 
| 49 | 
            +
                    top_torso_coords = torso_coords[uid] # [m, 2]
         | 
| 50 | 
            +
                    # only keep top-is-head pixels
         | 
| 51 | 
            +
                    top_torso_coords_up = top_torso_coords.copy() - np.array([1, 0]) # [N, 2]
         | 
| 52 | 
            +
                    mask = head_part[tuple(top_torso_coords_up.T)] 
         | 
| 53 | 
            +
                    if mask.any():
         | 
| 54 | 
            +
                        top_torso_coords = top_torso_coords[mask]
         | 
| 55 | 
            +
                        # get the color
         | 
| 56 | 
            +
                        top_torso_colors = gt_image[tuple(top_torso_coords.T)] # [m, 3]
         | 
| 57 | 
            +
                        # construct inpaint coords (vertically up, or minus in x)
         | 
| 58 | 
            +
                        inpaint_torso_coords = top_torso_coords[None].repeat(L, 0) # [L, m, 2]
         | 
| 59 | 
            +
                        inpaint_offsets = np.stack([-np.arange(L), np.zeros(L, dtype=np.int32)], axis=-1)[:, None] # [L, 1, 2]
         | 
| 60 | 
            +
                        inpaint_torso_coords += inpaint_offsets
         | 
| 61 | 
            +
                        inpaint_torso_coords = inpaint_torso_coords.reshape(-1, 2) # [Lm, 2]
         | 
| 62 | 
            +
                        inpaint_torso_colors = top_torso_colors[None].repeat(L, 0) # [L, m, 3]
         | 
| 63 | 
            +
                        darken_scaler = 0.98 ** np.arange(L).reshape(L, 1, 1) # [L, 1, 1]
         | 
| 64 | 
            +
                        inpaint_torso_colors = (inpaint_torso_colors * darken_scaler).reshape(-1, 3) # [Lm, 3]
         | 
| 65 | 
            +
                        # set color
         | 
| 66 | 
            +
                        torso_image[tuple(inpaint_torso_coords.T)] = inpaint_torso_colors
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                        inpaint_torso_mask = np.zeros_like(torso_image[..., 0]).astype(bool)
         | 
| 69 | 
            +
                        inpaint_torso_mask[tuple(inpaint_torso_coords.T)] = True
         | 
| 70 | 
            +
                    else:
         | 
| 71 | 
            +
                        inpaint_torso_mask = None
         | 
| 72 | 
            +
                        
         | 
| 73 | 
            +
                    # neck part "vertical" in-painting...
         | 
| 74 | 
            +
                    push_down = 4
         | 
| 75 | 
            +
                    L = 48 + push_down + 1
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    neck_part = binary_dilation(neck_part, structure=np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]], dtype=bool), iterations=3)
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    neck_coords = np.stack(np.nonzero(neck_part), axis=-1) # [M, 2]
         | 
| 80 | 
            +
                    # lexsort: sort 2D coords first by y then by x, 
         | 
| 81 | 
            +
                    # ref: https://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple-axes
         | 
| 82 | 
            +
                    inds = np.lexsort((neck_coords[:, 0], neck_coords[:, 1]))
         | 
| 83 | 
            +
                    neck_coords = neck_coords[inds]
         | 
| 84 | 
            +
                    # choose the top pixel for each column
         | 
| 85 | 
            +
                    u, uid, ucnt = np.unique(neck_coords[:, 1], return_index=True, return_counts=True)
         | 
| 86 | 
            +
                    top_neck_coords = neck_coords[uid] # [m, 2]
         | 
| 87 | 
            +
                    # only keep top-is-head pixels
         | 
| 88 | 
            +
                    top_neck_coords_up = top_neck_coords.copy() - np.array([1, 0])
         | 
| 89 | 
            +
                    mask = head_part[tuple(top_neck_coords_up.T)] 
         | 
| 90 | 
            +
                    
         | 
| 91 | 
            +
                    top_neck_coords = top_neck_coords[mask]
         | 
| 92 | 
            +
                    # push these top down for 4 pixels to make the neck inpainting more natural...
         | 
| 93 | 
            +
                    offset_down = np.minimum(ucnt[mask] - 1, push_down)
         | 
| 94 | 
            +
                    top_neck_coords += np.stack([offset_down, np.zeros_like(offset_down)], axis=-1)
         | 
| 95 | 
            +
                    # get the color
         | 
| 96 | 
            +
                    top_neck_colors = gt_image[tuple(top_neck_coords.T)] # [m, 3]
         | 
| 97 | 
            +
                    # construct inpaint coords (vertically up, or minus in x)
         | 
| 98 | 
            +
                    inpaint_neck_coords = top_neck_coords[None].repeat(L, 0) # [L, m, 2]
         | 
| 99 | 
            +
                    inpaint_offsets = np.stack([-np.arange(L), np.zeros(L, dtype=np.int32)], axis=-1)[:, None] # [L, 1, 2]
         | 
| 100 | 
            +
                    inpaint_neck_coords += inpaint_offsets
         | 
| 101 | 
            +
                    inpaint_neck_coords = inpaint_neck_coords.reshape(-1, 2) # [Lm, 2]
         | 
| 102 | 
            +
                    inpaint_neck_colors = top_neck_colors[None].repeat(L, 0) # [L, m, 3]
         | 
| 103 | 
            +
                    darken_scaler = 0.98 ** np.arange(L).reshape(L, 1, 1) # [L, 1, 1]
         | 
| 104 | 
            +
                    inpaint_neck_colors = (inpaint_neck_colors * darken_scaler).reshape(-1, 3) # [Lm, 3]
         | 
| 105 | 
            +
                    # set color
         | 
| 106 | 
            +
                    torso_image[tuple(inpaint_neck_coords.T)] = inpaint_neck_colors
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    # apply blurring to the inpaint area to avoid vertical-line artifects...
         | 
| 109 | 
            +
                    inpaint_mask = np.zeros_like(torso_image[..., 0]).astype(bool)
         | 
| 110 | 
            +
                    inpaint_mask[tuple(inpaint_neck_coords.T)] = True
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    blur_img = torso_image.copy()
         | 
| 113 | 
            +
                    blur_img = cv2.GaussianBlur(blur_img, (5, 5), cv2.BORDER_DEFAULT)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    torso_image[inpaint_mask] = blur_img[inpaint_mask]
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                    # set mask
         | 
| 118 | 
            +
                    mask = (neck_part | torso_part | inpaint_mask)
         | 
| 119 | 
            +
                    if inpaint_torso_mask is not None:
         | 
| 120 | 
            +
                        mask = mask | inpaint_torso_mask
         | 
| 121 | 
            +
                    torso_image[~mask] = 0
         | 
| 122 | 
            +
                    torso_alpha[~mask] = 0
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                    cv2.imwrite("0.png", np.concatenate([torso_image, torso_alpha], axis=-1))
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                print(f'[INFO] ===== extracted torso and gt images =====')
         | 
| 127 | 
            +
             | 
| 128 | 
            +
             | 
| 129 | 
            +
            def out_exist_job(vid_name):
         | 
| 130 | 
            +
                out_dir1 = vid_name.replace("/video/", "/inpaint_torso_imgs/").replace(".mp4","") 
         | 
| 131 | 
            +
                out_dir2 = vid_name.replace("/video/", "/inpaint_torso_with_bg_imgs/").replace(".mp4","") 
         | 
| 132 | 
            +
                out_dir3 = vid_name.replace("/video/", "/torso_imgs/").replace(".mp4","") 
         | 
| 133 | 
            +
                out_dir4 = vid_name.replace("/video/", "/torso_with_bg_imgs/").replace(".mp4","") 
         | 
| 134 | 
            +
                
         | 
| 135 | 
            +
                if os.path.exists(out_dir1) and os.path.exists(out_dir1) and os.path.exists(out_dir2) and os.path.exists(out_dir3) and os.path.exists(out_dir4):
         | 
| 136 | 
            +
                    num_frames = len(os.listdir(out_dir1))
         | 
| 137 | 
            +
                    if len(os.listdir(out_dir1)) == num_frames and len(os.listdir(out_dir2)) == num_frames and len(os.listdir(out_dir3)) == num_frames and len(os.listdir(out_dir4)) == num_frames:
         | 
| 138 | 
            +
                        return None
         | 
| 139 | 
            +
                    else:
         | 
| 140 | 
            +
                        return vid_name
         | 
| 141 | 
            +
                else:
         | 
| 142 | 
            +
                    return vid_name
         | 
| 143 | 
            +
                
         | 
| 144 | 
            +
            def get_todo_vid_names(vid_names):
         | 
| 145 | 
            +
                todo_vid_names = []
         | 
| 146 | 
            +
                for i, res in multiprocess_run_tqdm(out_exist_job, vid_names, num_workers=16):
         | 
| 147 | 
            +
                    if res is not None:
         | 
| 148 | 
            +
                        todo_vid_names.append(res)
         | 
| 149 | 
            +
                return todo_vid_names
         | 
| 150 | 
            +
             | 
| 151 | 
            +
            if __name__ == '__main__':
         | 
| 152 | 
            +
                import argparse, glob, tqdm, random
         | 
| 153 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 154 | 
            +
                parser.add_argument("--vid_dir", default='/home/tiger/datasets/raw/CelebV-HQ/video')
         | 
| 155 | 
            +
                parser.add_argument("--ds_name", default='CelebV-HQ')
         | 
| 156 | 
            +
                parser.add_argument("--num_workers", default=48, type=int)
         | 
| 157 | 
            +
                parser.add_argument("--seed", default=0, type=int)
         | 
| 158 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 159 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 160 | 
            +
                parser.add_argument("--reset", action='store_true')
         | 
| 161 | 
            +
                
         | 
| 162 | 
            +
                inpaint_torso_job('/home/tiger/datasets/raw/CelebV-HQ/video/dgdEr-mXQT4_8.mp4')
         | 
| 163 | 
            +
                # args = parser.parse_args()
         | 
| 164 | 
            +
                # vid_dir = args.vid_dir
         | 
| 165 | 
            +
                # ds_name = args.ds_name
         | 
| 166 | 
            +
                # if ds_name in ['lrs3_trainval']:
         | 
| 167 | 
            +
                #     mp4_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 168 | 
            +
                # if ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 169 | 
            +
                #     vid_names = glob.glob(os.path.join(vid_dir, "*.mp4"))
         | 
| 170 | 
            +
                # elif ds_name in ['lrs2', 'lrs3', 'voxceleb2']:
         | 
| 171 | 
            +
                #     vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 172 | 
            +
                #     vid_names = glob.glob(vid_name_pattern)
         | 
| 173 | 
            +
                # vid_names = sorted(vid_names)
         | 
| 174 | 
            +
                # random.seed(args.seed)
         | 
| 175 | 
            +
                # random.shuffle(vid_names)
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                # process_id = args.process_id
         | 
| 178 | 
            +
                # total_process = args.total_process
         | 
| 179 | 
            +
                # if total_process > 1:
         | 
| 180 | 
            +
                #     assert process_id <= total_process -1
         | 
| 181 | 
            +
                #     num_samples_per_process = len(vid_names) // total_process
         | 
| 182 | 
            +
                #     if process_id == total_process:
         | 
| 183 | 
            +
                #         vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 184 | 
            +
                #     else:
         | 
| 185 | 
            +
                #         vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 186 | 
            +
                
         | 
| 187 | 
            +
                # if not args.reset:
         | 
| 188 | 
            +
                #     vid_names = get_todo_vid_names(vid_names)
         | 
| 189 | 
            +
                # print(f"todo videos number: {len(vid_names)}")
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                # fn_args = [(vid_name,i,len(vid_names)) for i, vid_name in enumerate(vid_names)]
         | 
| 192 | 
            +
                # for vid_name in multiprocess_run_tqdm(inpaint_torso_job ,fn_args, desc=f"Root process {args.process_id}: extracting segment images", num_workers=args.num_workers):
         | 
| 193 | 
            +
                #     pass
         | 
    	
        data_gen/utils/process_video/resample_video_to_25fps_resize_to_512.py
    ADDED
    
    | @@ -0,0 +1,87 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os, glob
         | 
| 2 | 
            +
            import cv2
         | 
| 3 | 
            +
            from utils.commons.os_utils import multiprocess_glob
         | 
| 4 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            def get_video_infos(video_path):
         | 
| 7 | 
            +
                vid_cap = cv2.VideoCapture(video_path)
         | 
| 8 | 
            +
                height = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
         | 
| 9 | 
            +
                width = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
         | 
| 10 | 
            +
                fps = vid_cap.get(cv2.CAP_PROP_FPS)
         | 
| 11 | 
            +
                total_frames = int(vid_cap.get(cv2.CAP_PROP_FRAME_COUNT))
         | 
| 12 | 
            +
                return {'height': height, 'width': width, 'fps': fps, 'total_frames':total_frames}
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            def extract_img_job(video_name:str):
         | 
| 15 | 
            +
                out_path = video_name.replace("/video_raw/","/video/",1)
         | 
| 16 | 
            +
                os.makedirs(os.path.dirname(out_path), exist_ok=True)
         | 
| 17 | 
            +
                ffmpeg_path = "/usr/bin/ffmpeg"
         | 
| 18 | 
            +
                vid_info = get_video_infos(video_name)
         | 
| 19 | 
            +
                assert vid_info['width'] == vid_info['height']
         | 
| 20 | 
            +
                cmd = f'{ffmpeg_path} -i {video_name} -vf fps={25},scale=w=512:h=512 -q:v 1 -c:v libx264 -pix_fmt yuv420p -b:v 2000k -v quiet -y {out_path}'
         | 
| 21 | 
            +
                os.system(cmd)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            def extract_img_job_crop(video_name:str):
         | 
| 24 | 
            +
                out_path = video_name.replace("/video_raw/","/video/",1)
         | 
| 25 | 
            +
                os.makedirs(os.path.dirname(out_path), exist_ok=True)
         | 
| 26 | 
            +
                ffmpeg_path = "/usr/bin/ffmpeg"
         | 
| 27 | 
            +
                vid_info = get_video_infos(video_name)
         | 
| 28 | 
            +
                wh = min(vid_info['width'], vid_info['height'])
         | 
| 29 | 
            +
                cmd = f'{ffmpeg_path} -i {video_name} -vf fps={25},crop={wh}:{wh},scale=w=512:h=512 -q:v 1 -c:v libx264 -pix_fmt yuv420p -b:v 2000k -v quiet -y {out_path}'
         | 
| 30 | 
            +
                os.system(cmd)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            def extract_img_job_crop_ravdess(video_name:str):
         | 
| 33 | 
            +
                out_path = video_name.replace("/video_raw/","/video/",1)
         | 
| 34 | 
            +
                os.makedirs(os.path.dirname(out_path), exist_ok=True)
         | 
| 35 | 
            +
                ffmpeg_path = "/usr/bin/ffmpeg"
         | 
| 36 | 
            +
                cmd = f'{ffmpeg_path} -i {video_name} -vf fps={25},crop=720:720,scale=w=512:h=512 -q:v 1 -c:v libx264 -pix_fmt yuv420p -b:v 2000k -v quiet -y {out_path}'
         | 
| 37 | 
            +
                os.system(cmd)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            if __name__ == '__main__':
         | 
| 40 | 
            +
                import argparse, glob, tqdm, random
         | 
| 41 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 42 | 
            +
                parser.add_argument("--vid_dir", default='/home/tiger/datasets/raw/CelebV-HQ/video_raw/')
         | 
| 43 | 
            +
                parser.add_argument("--ds_name", default='CelebV-HQ')
         | 
| 44 | 
            +
                parser.add_argument("--num_workers", default=32, type=int)
         | 
| 45 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 46 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 47 | 
            +
                args = parser.parse_args()
         | 
| 48 | 
            +
                print(f"args {args}")
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                vid_dir = args.vid_dir
         | 
| 51 | 
            +
                ds_name = args.ds_name
         | 
| 52 | 
            +
                if ds_name in ['lrs3_trainval']:
         | 
| 53 | 
            +
                    mp4_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 54 | 
            +
                elif ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 55 | 
            +
                    vid_names = multiprocess_glob(os.path.join(vid_dir, "*.mp4"))
         | 
| 56 | 
            +
                elif ds_name in ['lrs2', 'lrs3', 'voxceleb2', 'CMLR']:
         | 
| 57 | 
            +
                    vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 58 | 
            +
                    vid_names = multiprocess_glob(vid_name_pattern)
         | 
| 59 | 
            +
                elif ds_name in ["RAVDESS", 'VFHQ']:
         | 
| 60 | 
            +
                    vid_name_pattern = os.path.join(vid_dir, "*/*/*/*.mp4")
         | 
| 61 | 
            +
                    vid_names = multiprocess_glob(vid_name_pattern)
         | 
| 62 | 
            +
                else:
         | 
| 63 | 
            +
                    raise NotImplementedError()
         | 
| 64 | 
            +
                vid_names = sorted(vid_names)
         | 
| 65 | 
            +
                print(f"total video number : {len(vid_names)}")
         | 
| 66 | 
            +
                print(f"first {vid_names[0]} last {vid_names[-1]}")
         | 
| 67 | 
            +
                # exit()
         | 
| 68 | 
            +
                process_id = args.process_id
         | 
| 69 | 
            +
                total_process = args.total_process
         | 
| 70 | 
            +
                if total_process > 1:
         | 
| 71 | 
            +
                    assert process_id <= total_process -1
         | 
| 72 | 
            +
                    num_samples_per_process = len(vid_names) // total_process
         | 
| 73 | 
            +
                    if process_id == total_process:
         | 
| 74 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 75 | 
            +
                    else:
         | 
| 76 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 77 | 
            +
                
         | 
| 78 | 
            +
                if ds_name == "RAVDESS":
         | 
| 79 | 
            +
                    for i, res in multiprocess_run_tqdm(extract_img_job_crop_ravdess, vid_names, num_workers=args.num_workers, desc="resampling videos"):
         | 
| 80 | 
            +
                        pass
         | 
| 81 | 
            +
                elif ds_name == "CMLR":
         | 
| 82 | 
            +
                    for i, res in multiprocess_run_tqdm(extract_img_job_crop, vid_names, num_workers=args.num_workers, desc="resampling videos"):
         | 
| 83 | 
            +
                        pass
         | 
| 84 | 
            +
                else:
         | 
| 85 | 
            +
                    for i, res in multiprocess_run_tqdm(extract_img_job, vid_names, num_workers=args.num_workers, desc="resampling videos"):
         | 
| 86 | 
            +
                        pass
         | 
| 87 | 
            +
             | 
    	
        data_gen/utils/process_video/split_video_to_imgs.py
    ADDED
    
    | @@ -0,0 +1,53 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os, glob
         | 
| 2 | 
            +
            from utils.commons.multiprocess_utils import multiprocess_run_tqdm
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            from data_gen.utils.path_converter import PathConverter, pc
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # mp4_names = glob.glob("/home/tiger/datasets/raw/CelebV-HQ/video/*.mp4")
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            def extract_img_job(video_name, raw_img_dir=None):
         | 
| 9 | 
            +
                if raw_img_dir is not None:
         | 
| 10 | 
            +
                    out_path = raw_img_dir
         | 
| 11 | 
            +
                else:
         | 
| 12 | 
            +
                    out_path = pc.to(video_name.replace(".mp4", ""), "vid", "gt")
         | 
| 13 | 
            +
                os.makedirs(out_path, exist_ok=True)
         | 
| 14 | 
            +
                ffmpeg_path = "/usr/bin/ffmpeg"
         | 
| 15 | 
            +
                cmd = f'{ffmpeg_path} -i {video_name} -vf fps={25},scale=w=512:h=512 -qmin 1 -q:v 1 -start_number 0 -v quiet {os.path.join(out_path, "%8d.jpg")}'
         | 
| 16 | 
            +
                os.system(cmd)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            if __name__ == '__main__':
         | 
| 19 | 
            +
                import argparse, glob, tqdm, random
         | 
| 20 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 21 | 
            +
                parser.add_argument("--vid_dir", default='/home/tiger/datasets/raw/CelebV-HQ/video')
         | 
| 22 | 
            +
                parser.add_argument("--ds_name", default='CelebV-HQ')
         | 
| 23 | 
            +
                parser.add_argument("--num_workers", default=64, type=int)
         | 
| 24 | 
            +
                parser.add_argument("--process_id", default=0, type=int)
         | 
| 25 | 
            +
                parser.add_argument("--total_process", default=1, type=int)
         | 
| 26 | 
            +
                args = parser.parse_args()
         | 
| 27 | 
            +
                vid_dir = args.vid_dir
         | 
| 28 | 
            +
                ds_name = args.ds_name
         | 
| 29 | 
            +
                if ds_name in ['lrs3_trainval']:
         | 
| 30 | 
            +
                    mp4_name_pattern = os.path.join(vid_dir, "*/*.mp4")
         | 
| 31 | 
            +
                elif ds_name in ['TH1KH_512', 'CelebV-HQ']:
         | 
| 32 | 
            +
                    vid_names = glob.glob(os.path.join(vid_dir, "*.mp4"))
         | 
| 33 | 
            +
                elif ds_name in ['lrs2', 'lrs3', 'voxceleb2']:
         | 
| 34 | 
            +
                    vid_name_pattern = os.path.join(vid_dir, "*/*/*.mp4")
         | 
| 35 | 
            +
                    vid_names = glob.glob(vid_name_pattern)
         | 
| 36 | 
            +
                elif ds_name in ["RAVDESS", 'VFHQ']:
         | 
| 37 | 
            +
                    vid_name_pattern = os.path.join(vid_dir, "*/*/*/*.mp4")
         | 
| 38 | 
            +
                    vid_names = glob.glob(vid_name_pattern)
         | 
| 39 | 
            +
                vid_names = sorted(vid_names)
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                process_id = args.process_id
         | 
| 42 | 
            +
                total_process = args.total_process
         | 
| 43 | 
            +
                if total_process > 1:
         | 
| 44 | 
            +
                    assert process_id <= total_process -1
         | 
| 45 | 
            +
                    num_samples_per_process = len(vid_names) // total_process
         | 
| 46 | 
            +
                    if process_id == total_process:
         | 
| 47 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : ]
         | 
| 48 | 
            +
                    else:
         | 
| 49 | 
            +
                        vid_names = vid_names[process_id * num_samples_per_process : (process_id+1) * num_samples_per_process]
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                for i, res in multiprocess_run_tqdm(extract_img_job, vid_names, num_workers=args.num_workers, desc="extracting images"):
         | 
| 52 | 
            +
                    pass
         | 
| 53 | 
            +
             | 
    	
        data_util/face3d_helper.py
    ADDED
    
    | @@ -0,0 +1,309 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import os
         | 
| 2 | 
            +
            import numpy as np
         | 
| 3 | 
            +
            import torch
         | 
| 4 | 
            +
            import torch.nn as nn
         | 
| 5 | 
            +
            from scipy.io import loadmat
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from deep_3drecon.deep_3drecon_models.bfm import perspective_projection
         | 
| 8 | 
            +
             | 
| 9 | 
            +
             | 
| 10 | 
            +
            class Face3DHelper(nn.Module):
         | 
| 11 | 
            +
                def __init__(self, bfm_dir='deep_3drecon/BFM', keypoint_mode='lm68', use_gpu=True):
         | 
| 12 | 
            +
                    super().__init__()
         | 
| 13 | 
            +
                    self.keypoint_mode = keypoint_mode # lm68 | mediapipe
         | 
| 14 | 
            +
                    self.bfm_dir = bfm_dir
         | 
| 15 | 
            +
                    self.load_3dmm()
         | 
| 16 | 
            +
                    if use_gpu: self.to("cuda")
         | 
| 17 | 
            +
                        
         | 
| 18 | 
            +
                def load_3dmm(self):
         | 
| 19 | 
            +
                    model = loadmat(os.path.join(self.bfm_dir, "BFM_model_front.mat"))
         | 
| 20 | 
            +
                    self.register_buffer('mean_shape',torch.from_numpy(model['meanshape'].transpose()).float()) # mean face shape. [3*N, 1], N=35709, xyz=3, ==> 3*N=107127
         | 
| 21 | 
            +
                    mean_shape = self.mean_shape.reshape([-1, 3])
         | 
| 22 | 
            +
                    # re-center
         | 
| 23 | 
            +
                    mean_shape = mean_shape - torch.mean(mean_shape, dim=0, keepdims=True)
         | 
| 24 | 
            +
                    self.mean_shape = mean_shape.reshape([-1, 1])
         | 
| 25 | 
            +
                    self.register_buffer('id_base',torch.from_numpy(model['idBase']).float()) # identity basis. [3*N,80], we have 80 eigen faces for identity
         | 
| 26 | 
            +
                    self.register_buffer('exp_base',torch.from_numpy(model['exBase']).float()) # expression basis. [3*N,64], we have 64 eigen faces for expression
         | 
| 27 | 
            +
                    
         | 
| 28 | 
            +
                    self.register_buffer('mean_texure',torch.from_numpy(model['meantex'].transpose()).float()) # mean face texture. [3*N,1] (0-255)
         | 
| 29 | 
            +
                    self.register_buffer('tex_base',torch.from_numpy(model['texBase']).float()) # texture basis. [3*N,80], rgb=3
         | 
| 30 | 
            +
                    
         | 
| 31 | 
            +
                    self.register_buffer('point_buf',torch.from_numpy(model['point_buf']).float()) # triangle indices for each vertex that lies in. starts from 1. [N,8] (1-F)
         | 
| 32 | 
            +
                    self.register_buffer('face_buf',torch.from_numpy(model['tri']).float()) # vertex indices in each triangle. starts from 1. [F,3] (1-N)
         | 
| 33 | 
            +
                    if self.keypoint_mode == 'mediapipe':
         | 
| 34 | 
            +
                        self.register_buffer('key_points', torch.from_numpy(np.load("deep_3drecon/BFM/index_mp468_from_mesh35709.npy").astype(np.int64)))
         | 
| 35 | 
            +
                        unmatch_mask = self.key_points < 0
         | 
| 36 | 
            +
                        self.key_points[unmatch_mask] = 0
         | 
| 37 | 
            +
                    else:
         | 
| 38 | 
            +
                        self.register_buffer('key_points',torch.from_numpy(model['keypoints'].squeeze().astype(np.int_)).long()) # vertex indices of 68 facial landmarks. starts from 1. [68,1]
         | 
| 39 | 
            +
                    
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    self.register_buffer('key_mean_shape',self.mean_shape.reshape([-1,3])[self.key_points,:])
         | 
| 42 | 
            +
                    self.register_buffer('key_id_base', self.id_base.reshape([-1,3,80])[self.key_points, :, :].reshape([-1,80])) 
         | 
| 43 | 
            +
                    self.register_buffer('key_exp_base', self.exp_base.reshape([-1,3,64])[self.key_points, :, :].reshape([-1,64])) 
         | 
| 44 | 
            +
                    self.key_id_base_np = self.key_id_base.cpu().numpy()
         | 
| 45 | 
            +
                    self.key_exp_base_np = self.key_exp_base.cpu().numpy()
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    self.register_buffer('persc_proj', torch.tensor(perspective_projection(focal=1015, center=112))) 
         | 
| 48 | 
            +
                def split_coeff(self, coeff):
         | 
| 49 | 
            +
                    """
         | 
| 50 | 
            +
                    coeff: Tensor[B, T, c=257] or [T, c=257]
         | 
| 51 | 
            +
                    """
         | 
| 52 | 
            +
                    ret_dict = {
         | 
| 53 | 
            +
                        'identity': coeff[..., :80],  # identity, [b, t, c=80] 
         | 
| 54 | 
            +
                        'expression': coeff[..., 80:144],  # expression, [b, t, c=80]
         | 
| 55 | 
            +
                        'texture': coeff[..., 144:224],  # texture, [b, t, c=80]
         | 
| 56 | 
            +
                        'euler': coeff[..., 224:227],  # euler euler for pose, [b, t, c=3]
         | 
| 57 | 
            +
                        'translation':  coeff[..., 254:257], # translation, [b, t, c=3]
         | 
| 58 | 
            +
                        'gamma': coeff[..., 227:254] # lighting, [b, t, c=27]
         | 
| 59 | 
            +
                    }
         | 
| 60 | 
            +
                    return ret_dict
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def reconstruct_face_mesh(self, id_coeff, exp_coeff):
         | 
| 63 | 
            +
                    """
         | 
| 64 | 
            +
                    Generate a pose-independent 3D face mesh!
         | 
| 65 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 66 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 67 | 
            +
                    """
         | 
| 68 | 
            +
                    id_coeff = id_coeff.to(self.key_id_base.device)
         | 
| 69 | 
            +
                    exp_coeff = exp_coeff.to(self.key_id_base.device)
         | 
| 70 | 
            +
                    mean_face = self.mean_shape.squeeze().reshape([1, -1]) # [3N, 1] ==> [1, 3N]
         | 
| 71 | 
            +
                    id_base, exp_base = self.id_base, self.exp_base # [3*N, C]
         | 
| 72 | 
            +
                    identity_diff_face = torch.matmul(id_coeff, id_base.transpose(0,1)) # [t,c],[c,3N] ==> [t,3N]
         | 
| 73 | 
            +
                    expression_diff_face = torch.matmul(exp_coeff, exp_base.transpose(0,1)) # [t,c],[c,3N] ==> [t,3N]
         | 
| 74 | 
            +
                    
         | 
| 75 | 
            +
                    face = mean_face + identity_diff_face + expression_diff_face # [t,3N]
         | 
| 76 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 77 | 
            +
                    # re-centering the face with mean_xyz, so the face will be in [-1, 1]
         | 
| 78 | 
            +
                    # mean_xyz = self.mean_shape.squeeze().reshape([-1,3]).mean(dim=0) # [1, 3]
         | 
| 79 | 
            +
                    # face_mesh = face - mean_xyz.unsqueeze(0) # [t,N,3]
         | 
| 80 | 
            +
                    return face
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def reconstruct_cano_lm3d(self, id_coeff, exp_coeff):
         | 
| 83 | 
            +
                    """
         | 
| 84 | 
            +
                    Generate 3D landmark with keypoint base!
         | 
| 85 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 86 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 87 | 
            +
                    """
         | 
| 88 | 
            +
                    id_coeff = id_coeff.to(self.key_id_base.device)
         | 
| 89 | 
            +
                    exp_coeff = exp_coeff.to(self.key_id_base.device)
         | 
| 90 | 
            +
                    mean_face = self.key_mean_shape.squeeze().reshape([1, -1]) # [3*68, 1] ==> [1, 3*68]
         | 
| 91 | 
            +
                    id_base, exp_base = self.key_id_base, self.key_exp_base # [3*68, C]
         | 
| 92 | 
            +
                    identity_diff_face = torch.matmul(id_coeff, id_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 93 | 
            +
                    expression_diff_face = torch.matmul(exp_coeff, exp_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 94 | 
            +
                    
         | 
| 95 | 
            +
                    face = mean_face + identity_diff_face + expression_diff_face # [t,3N]
         | 
| 96 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 97 | 
            +
                    # re-centering the face with mean_xyz, so the face will be in [-1, 1]
         | 
| 98 | 
            +
                    # mean_xyz = self.key_mean_shape.squeeze().reshape([-1,3]).mean(dim=0) # [1, 3]
         | 
| 99 | 
            +
                    # lm3d = face - mean_xyz.unsqueeze(0) # [t,N,3]
         | 
| 100 | 
            +
                    return face
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                def reconstruct_lm3d(self, id_coeff, exp_coeff, euler, trans, to_camera=True):
         | 
| 103 | 
            +
                    """
         | 
| 104 | 
            +
                    Generate 3D landmark with keypoint base!
         | 
| 105 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 106 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 107 | 
            +
                    """
         | 
| 108 | 
            +
                    id_coeff = id_coeff.to(self.key_id_base.device)
         | 
| 109 | 
            +
                    exp_coeff = exp_coeff.to(self.key_id_base.device)
         | 
| 110 | 
            +
                    mean_face = self.key_mean_shape.squeeze().reshape([1, -1]) # [3*68, 1] ==> [1, 3*68]
         | 
| 111 | 
            +
                    id_base, exp_base = self.key_id_base, self.key_exp_base # [3*68, C]
         | 
| 112 | 
            +
                    identity_diff_face = torch.matmul(id_coeff, id_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 113 | 
            +
                    expression_diff_face = torch.matmul(exp_coeff, exp_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 114 | 
            +
                    
         | 
| 115 | 
            +
                    face = mean_face + identity_diff_face + expression_diff_face # [t,3N]
         | 
| 116 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 117 | 
            +
                    # re-centering the face with mean_xyz, so the face will be in [-1, 1]
         | 
| 118 | 
            +
                    rot = self.compute_rotation(euler)
         | 
| 119 | 
            +
                    # transform
         | 
| 120 | 
            +
                    lm3d = face @ rot + trans.unsqueeze(1) # [t, N, 3]
         | 
| 121 | 
            +
                    # to camera
         | 
| 122 | 
            +
                    if to_camera:
         | 
| 123 | 
            +
                        lm3d[...,-1] = 10 - lm3d[...,-1] 
         | 
| 124 | 
            +
                    return lm3d
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                def reconstruct_lm2d_nerf(self, id_coeff, exp_coeff, euler, trans):
         | 
| 127 | 
            +
                    lm2d = self.reconstruct_lm2d(id_coeff, exp_coeff, euler, trans, to_camera=False)
         | 
| 128 | 
            +
                    lm2d[..., 0] = 1 - lm2d[..., 0]
         | 
| 129 | 
            +
                    lm2d[..., 1] = 1 - lm2d[..., 1]
         | 
| 130 | 
            +
                    return lm2d
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                def reconstruct_lm2d(self, id_coeff, exp_coeff, euler, trans, to_camera=True):
         | 
| 133 | 
            +
                    """
         | 
| 134 | 
            +
                    Generate 3D landmark with keypoint base!
         | 
| 135 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 136 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 137 | 
            +
                    """
         | 
| 138 | 
            +
                    is_btc_flag = True if id_coeff.ndim == 3 else False
         | 
| 139 | 
            +
                    if is_btc_flag:
         | 
| 140 | 
            +
                        b,t,_ = id_coeff.shape
         | 
| 141 | 
            +
                        id_coeff = id_coeff.reshape([b*t,-1])
         | 
| 142 | 
            +
                        exp_coeff = exp_coeff.reshape([b*t,-1])
         | 
| 143 | 
            +
                        euler = euler.reshape([b*t,-1])
         | 
| 144 | 
            +
                        trans = trans.reshape([b*t,-1])
         | 
| 145 | 
            +
                    id_coeff = id_coeff.to(self.key_id_base.device)
         | 
| 146 | 
            +
                    exp_coeff = exp_coeff.to(self.key_id_base.device)
         | 
| 147 | 
            +
                    mean_face = self.key_mean_shape.squeeze().reshape([1, -1]) # [3*68, 1] ==> [1, 3*68]
         | 
| 148 | 
            +
                    id_base, exp_base = self.key_id_base, self.key_exp_base # [3*68, C]
         | 
| 149 | 
            +
                    identity_diff_face = torch.matmul(id_coeff, id_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 150 | 
            +
                    expression_diff_face = torch.matmul(exp_coeff, exp_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 151 | 
            +
                    
         | 
| 152 | 
            +
                    face = mean_face + identity_diff_face + expression_diff_face # [t,3N]
         | 
| 153 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 154 | 
            +
                    # re-centering the face with mean_xyz, so the face will be in [-1, 1]
         | 
| 155 | 
            +
                    rot = self.compute_rotation(euler)
         | 
| 156 | 
            +
                    # transform
         | 
| 157 | 
            +
                    lm3d = face @ rot + trans.unsqueeze(1) # [t, N, 3]
         | 
| 158 | 
            +
                    # to camera
         | 
| 159 | 
            +
                    if to_camera:
         | 
| 160 | 
            +
                        lm3d[...,-1] = 10 - lm3d[...,-1] 
         | 
| 161 | 
            +
                    # to image_plane
         | 
| 162 | 
            +
                    lm3d = lm3d @ self.persc_proj
         | 
| 163 | 
            +
                    lm2d = lm3d[..., :2] / lm3d[..., 2:]
         | 
| 164 | 
            +
                    # flip
         | 
| 165 | 
            +
                    lm2d[..., 1] = 224 - lm2d[..., 1]
         | 
| 166 | 
            +
                    lm2d /= 224
         | 
| 167 | 
            +
                    if is_btc_flag:
         | 
| 168 | 
            +
                        return lm2d.reshape([b,t,-1,2])
         | 
| 169 | 
            +
                    return lm2d
         | 
| 170 | 
            +
                
         | 
| 171 | 
            +
                def compute_rotation(self, euler):
         | 
| 172 | 
            +
                    """
         | 
| 173 | 
            +
                    Return:
         | 
| 174 | 
            +
                        rot              -- torch.tensor, size (B, 3, 3) pts @ trans_mat
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                    Parameters:
         | 
| 177 | 
            +
                        euler           -- torch.tensor, size (B, 3), radian
         | 
| 178 | 
            +
                    """
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                    batch_size = euler.shape[0]
         | 
| 181 | 
            +
                    euler = euler.to(self.key_id_base.device)
         | 
| 182 | 
            +
                    ones = torch.ones([batch_size, 1]).to(self.key_id_base.device)
         | 
| 183 | 
            +
                    zeros = torch.zeros([batch_size, 1]).to(self.key_id_base.device)
         | 
| 184 | 
            +
                    x, y, z = euler[:, :1], euler[:, 1:2], euler[:, 2:],
         | 
| 185 | 
            +
                    
         | 
| 186 | 
            +
                    rot_x = torch.cat([
         | 
| 187 | 
            +
                        ones, zeros, zeros,
         | 
| 188 | 
            +
                        zeros, torch.cos(x), -torch.sin(x), 
         | 
| 189 | 
            +
                        zeros, torch.sin(x), torch.cos(x)
         | 
| 190 | 
            +
                    ], dim=1).reshape([batch_size, 3, 3])
         | 
| 191 | 
            +
                    
         | 
| 192 | 
            +
                    rot_y = torch.cat([
         | 
| 193 | 
            +
                        torch.cos(y), zeros, torch.sin(y),
         | 
| 194 | 
            +
                        zeros, ones, zeros,
         | 
| 195 | 
            +
                        -torch.sin(y), zeros, torch.cos(y)
         | 
| 196 | 
            +
                    ], dim=1).reshape([batch_size, 3, 3])
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                    rot_z = torch.cat([
         | 
| 199 | 
            +
                        torch.cos(z), -torch.sin(z), zeros,
         | 
| 200 | 
            +
                        torch.sin(z), torch.cos(z), zeros,
         | 
| 201 | 
            +
                        zeros, zeros, ones
         | 
| 202 | 
            +
                    ], dim=1).reshape([batch_size, 3, 3])
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    rot = rot_z @ rot_y @ rot_x
         | 
| 205 | 
            +
                    return rot.permute(0, 2, 1)
         | 
| 206 | 
            +
                
         | 
| 207 | 
            +
                def reconstruct_idexp_lm3d(self, id_coeff, exp_coeff):
         | 
| 208 | 
            +
                    """
         | 
| 209 | 
            +
                    Generate 3D landmark with keypoint base!
         | 
| 210 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 211 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 212 | 
            +
                    """
         | 
| 213 | 
            +
                    id_coeff = id_coeff.to(self.key_id_base.device)
         | 
| 214 | 
            +
                    exp_coeff = exp_coeff.to(self.key_id_base.device)
         | 
| 215 | 
            +
                    id_base, exp_base = self.key_id_base, self.key_exp_base # [3*68, C]
         | 
| 216 | 
            +
                    identity_diff_face = torch.matmul(id_coeff, id_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 217 | 
            +
                    expression_diff_face = torch.matmul(exp_coeff, exp_base.transpose(0,1)) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 218 | 
            +
                    
         | 
| 219 | 
            +
                    face = identity_diff_face + expression_diff_face # [t,3N]
         | 
| 220 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 221 | 
            +
                    lm3d = face * 10
         | 
| 222 | 
            +
                    return lm3d
         | 
| 223 | 
            +
                
         | 
| 224 | 
            +
                def reconstruct_idexp_lm3d_np(self, id_coeff, exp_coeff):
         | 
| 225 | 
            +
                    """
         | 
| 226 | 
            +
                    Generate 3D landmark with keypoint base!
         | 
| 227 | 
            +
                    id_coeff: Tensor[T, c=80]
         | 
| 228 | 
            +
                    exp_coeff: Tensor[T, c=64]
         | 
| 229 | 
            +
                    """
         | 
| 230 | 
            +
                    id_base, exp_base = self.key_id_base_np, self.key_exp_base_np # [3*68, C]
         | 
| 231 | 
            +
                    identity_diff_face = np.dot(id_coeff, id_base.T) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 232 | 
            +
                    expression_diff_face = np.dot(exp_coeff, exp_base.T) # [t,c],[c,3*68] ==> [t,3*68]
         | 
| 233 | 
            +
                    
         | 
| 234 | 
            +
                    face = identity_diff_face + expression_diff_face # [t,3N]
         | 
| 235 | 
            +
                    face = face.reshape([face.shape[0], -1, 3]) # [t,N,3]
         | 
| 236 | 
            +
                    lm3d = face * 10
         | 
| 237 | 
            +
                    return lm3d
         | 
| 238 | 
            +
                
         | 
| 239 | 
            +
                def get_eye_mouth_lm_from_lm3d(self, lm3d):
         | 
| 240 | 
            +
                    eye_lm = lm3d[:, 17:48] # [T, 31, 3]
         | 
| 241 | 
            +
                    mouth_lm = lm3d[:, 48:68] # [T, 20, 3]
         | 
| 242 | 
            +
                    return eye_lm, mouth_lm
         | 
| 243 | 
            +
                
         | 
| 244 | 
            +
                def get_eye_mouth_lm_from_lm3d_batch(self, lm3d):
         | 
| 245 | 
            +
                    eye_lm = lm3d[:, :, 17:48] # [T, 31, 3]
         | 
| 246 | 
            +
                    mouth_lm = lm3d[:, :, 48:68] # [T, 20, 3]
         | 
| 247 | 
            +
                    return eye_lm, mouth_lm
         | 
| 248 | 
            +
                
         | 
| 249 | 
            +
                def close_mouth_for_idexp_lm3d(self, idexp_lm3d, freeze_as_first_frame=True):
         | 
| 250 | 
            +
                    idexp_lm3d = idexp_lm3d.reshape([-1, 68,3])
         | 
| 251 | 
            +
                    num_frames = idexp_lm3d.shape[0]
         | 
| 252 | 
            +
                    eps = 0.0
         | 
| 253 | 
            +
                    # [n_landmarks=68,xyz=3], x 代表左右,y代表上下,z代表深度
         | 
| 254 | 
            +
                    idexp_lm3d[:,49:54, 1] = (idexp_lm3d[:,49:54, 1] + idexp_lm3d[:,range(59,54,-1), 1])/2 + eps * 2
         | 
| 255 | 
            +
                    idexp_lm3d[:,range(59,54,-1), 1] = (idexp_lm3d[:,49:54, 1] + idexp_lm3d[:,range(59,54,-1), 1])/2 - eps * 2
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                    idexp_lm3d[:,61:64, 1] = (idexp_lm3d[:,61:64, 1] + idexp_lm3d[:,range(67,64,-1), 1])/2 + eps
         | 
| 258 | 
            +
                    idexp_lm3d[:,range(67,64,-1), 1] = (idexp_lm3d[:,61:64, 1] + idexp_lm3d[:,range(67,64,-1), 1])/2 - eps
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                    idexp_lm3d[:,49:54, 1] += (0.03 - idexp_lm3d[:,49:54, 1].mean(dim=1) + idexp_lm3d[:,61:64, 1].mean(dim=1)).unsqueeze(1).repeat([1,5])
         | 
| 261 | 
            +
                    idexp_lm3d[:,range(59,54,-1), 1] += (-0.03 - idexp_lm3d[:,range(59,54,-1), 1].mean(dim=1) + idexp_lm3d[:,range(67,64,-1), 1].mean(dim=1)).unsqueeze(1).repeat([1,5])
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                    if freeze_as_first_frame:
         | 
| 264 | 
            +
                        idexp_lm3d[:, 48:68,] = idexp_lm3d[0, 48:68].unsqueeze(0).clone().repeat([num_frames, 1,1])*0
         | 
| 265 | 
            +
                    return idexp_lm3d.cpu()
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                def close_eyes_for_idexp_lm3d(self, idexp_lm3d):
         | 
| 268 | 
            +
                    idexp_lm3d = idexp_lm3d.reshape([-1, 68,3])
         | 
| 269 | 
            +
                    eps = 0.003
         | 
| 270 | 
            +
                    idexp_lm3d[:,37:39, 1] = (idexp_lm3d[:,37:39, 1] + idexp_lm3d[:,range(41,39,-1), 1])/2 + eps
         | 
| 271 | 
            +
                    idexp_lm3d[:,range(41,39,-1), 1] = (idexp_lm3d[:,37:39, 1] + idexp_lm3d[:,range(41,39,-1), 1])/2 - eps
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                    idexp_lm3d[:,43:45, 1] = (idexp_lm3d[:,43:45, 1] + idexp_lm3d[:,range(47,45,-1), 1])/2 + eps
         | 
| 274 | 
            +
                    idexp_lm3d[:,range(47,45,-1), 1] = (idexp_lm3d[:,43:45, 1] + idexp_lm3d[:,range(47,45,-1), 1])/2 - eps
         | 
| 275 | 
            +
                    
         | 
| 276 | 
            +
                    return idexp_lm3d
         | 
| 277 | 
            +
             | 
| 278 | 
            +
            if __name__ == '__main__':
         | 
| 279 | 
            +
                import cv2
         | 
| 280 | 
            +
                
         | 
| 281 | 
            +
                font = cv2.FONT_HERSHEY_SIMPLEX
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                face_mesh_helper = Face3DHelper('deep_3drecon/BFM')
         | 
| 284 | 
            +
                coeff_npy = 'data/coeff_fit_mp/crop_nana_003_coeff_fit_mp.npy'
         | 
| 285 | 
            +
                coeff_dict = np.load(coeff_npy, allow_pickle=True).tolist()
         | 
| 286 | 
            +
                lm3d = face_mesh_helper.reconstruct_lm2d(torch.tensor(coeff_dict['id']).cuda(), torch.tensor(coeff_dict['exp']).cuda(), torch.tensor(coeff_dict['euler']).cuda(), torch.tensor(coeff_dict['trans']).cuda() )
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                WH = 512
         | 
| 289 | 
            +
                lm3d = (lm3d * WH).cpu().int().numpy()
         | 
| 290 | 
            +
                eye_idx = list(range(36,48))
         | 
| 291 | 
            +
                mouth_idx = list(range(48,68))
         | 
| 292 | 
            +
                import imageio
         | 
| 293 | 
            +
                debug_name = 'debug_lm3d.mp4'
         | 
| 294 | 
            +
                writer = imageio.get_writer(debug_name, fps=25)
         | 
| 295 | 
            +
                for i_img in range(len(lm3d)):
         | 
| 296 | 
            +
                    lm2d = lm3d[i_img ,:, :2] # [68, 2]
         | 
| 297 | 
            +
                    img = np.ones([WH, WH, 3], dtype=np.uint8) * 255
         | 
| 298 | 
            +
                    for i in range(len(lm2d)):
         | 
| 299 | 
            +
                        x, y = lm2d[i]
         | 
| 300 | 
            +
                        if i in eye_idx:
         | 
| 301 | 
            +
                            color = (0,0,255)
         | 
| 302 | 
            +
                        elif i in mouth_idx:
         | 
| 303 | 
            +
                            color = (0,255,0)
         | 
| 304 | 
            +
                        else:
         | 
| 305 | 
            +
                            color = (255,0,0)
         | 
| 306 | 
            +
                        img = cv2.circle(img, center=(x,y), radius=3, color=color, thickness=-1)
         | 
| 307 | 
            +
                        img = cv2.putText(img, f"{i}", org=(x,y), fontFace=font, fontScale=0.3, color=(255,0,0))
         | 
| 308 | 
            +
                    writer.append_data(img)
         | 
| 309 | 
            +
                writer.close()
         | 
    	
        deep_3drecon/BFM/.gitkeep
    ADDED
    
    | 
            File without changes
         | 
    	
        deep_3drecon/BFM/basel_53201.txt
    ADDED
    
    | The diff for this file is too large to render. 
		See raw diff | 
|  | 
    	
        deep_3drecon/BFM/index_mp468_from_mesh35709_v1.npy
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:0d238a90df0c55075c9cea43dab76348421379a75c204931e34dbd2c11fb4b65
         | 
| 3 | 
            +
            size 3872
         | 
