├── .clang-format
├── .gitattributes
├── .github
├── FUNDING.yml
└── workflows
│ ├── build_wheels.yml
│ ├── cibuildwheel.yml
│ ├── cmake.yml
│ └── msvc.yml
├── .gitignore
├── .gitmodules
├── .natvis
└── eos.natvis
├── CITATION.cff
├── CMakeLists.txt
├── LICENSE
├── MANIFEST.in
├── README.md
├── doc
├── CMakeLists.txt
├── Doxyfile.in
└── namespaces.doxygen
├── examples
├── CMakeLists.txt
├── data
│ ├── image_0010.png
│ ├── image_0010.pts
│ └── notes.txt
├── fit-model-ceres.cpp
├── fit-model-multi.cpp
├── fit-model-simple.cpp
├── fit-model.cpp
└── generate-obj.cpp
├── include
└── eos
│ ├── core
│ ├── Image.hpp
│ ├── Landmark.hpp
│ ├── LandmarkMapper.hpp
│ ├── Mesh.hpp
│ ├── Rect.hpp
│ ├── image
│ │ ├── Pixel.hpp
│ │ ├── PixelTraits.hpp
│ │ ├── opencv_interop.hpp
│ │ ├── resize.hpp
│ │ └── utils.hpp
│ ├── math.hpp
│ ├── read_obj.hpp
│ ├── read_pts_landmarks.hpp
│ └── write_obj.hpp
│ ├── cpp17
│ ├── clamp.hpp
│ ├── detail
│ │ ├── akrzemi1_optional.hpp
│ │ ├── akrzemi1_optional_serialization.hpp
│ │ ├── mpark_variant.hpp
│ │ └── mpark_variant_serialization.hpp
│ ├── optional.hpp
│ ├── optional_serialization.hpp
│ ├── variant.hpp
│ └── variant_serialization.hpp
│ ├── fitting
│ ├── FittingResult.hpp
│ ├── RenderingParameters.hpp
│ ├── blendshape_fitting.hpp
│ ├── ceres_nonlinear.hpp
│ ├── closest_edge_fitting.hpp
│ ├── contour_correspondence.hpp
│ ├── detail
│ │ ├── eigen_quaternion_cerealisation.hpp
│ │ └── nonlinear_camera_estimation_detail.hpp
│ ├── fitting.hpp
│ ├── linear_shape_fitting.hpp
│ ├── multi_image_fitting.hpp
│ ├── nonlinear_camera_estimation.hpp
│ ├── orthographic_camera_estimation_linear.hpp
│ └── rotation_angles.hpp
│ ├── morphablemodel
│ ├── Blendshape.hpp
│ ├── EdgeTopology.hpp
│ ├── ExpressionModel.hpp
│ ├── MorphableModel.hpp
│ ├── PcaModel.hpp
│ ├── coefficients.hpp
│ └── io
│ │ ├── cvssp.hpp
│ │ ├── eigen_cerealisation.hpp
│ │ └── mat_cerealisation.hpp
│ ├── pca
│ └── pca.hpp
│ ├── render
│ ├── FragmentShader.hpp
│ ├── ProjectionType.hpp
│ ├── Rasterizer.hpp
│ ├── SoftwareRenderer.hpp
│ ├── Texture.hpp
│ ├── VertexShader.hpp
│ ├── detail
│ │ ├── RayDirection.hpp
│ │ ├── TriangleToRasterize.hpp
│ │ ├── Vertex.hpp
│ │ ├── plane.hpp
│ │ ├── texturing.hpp
│ │ └── utils.hpp
│ ├── draw_utils.hpp
│ ├── matrix_projection.hpp
│ ├── normals.hpp
│ ├── opencv
│ │ └── draw_utils.hpp
│ ├── ray_triangle_intersect.hpp
│ ├── render.hpp
│ ├── texture_extraction.hpp
│ ├── transforms.hpp
│ └── vertex_visibility.hpp
│ └── video
│ ├── Keyframe.hpp
│ └── keyframe_merging.hpp
├── initial_cache.cmake.template
├── matlab
├── +eos
│ ├── +fitting
│ │ ├── fit_shape_and_pose.m
│ │ └── private
│ │ │ └── fitting.cpp
│ └── +render
│ │ ├── extract_texture.m
│ │ ├── private
│ │ └── render.cpp
│ │ └── render.m
├── CMakeLists.txt
├── demo.m
└── include
│ ├── mexplus_eigen.hpp
│ ├── mexplus_eos_types.hpp
│ └── mexplus_opencv.hpp
├── python
├── CMakeLists.txt
├── demo.py
├── generate-python-bindings.cpp
├── pybind11_Image.hpp
├── pybind11_optional.hpp
└── pybind11_variant.hpp
├── setup.py
├── share
├── bfm2009_model_contours.json
├── bfm2017-1_bfm_nomouth_model_contours.json
├── expression_blendshapes_3448.bin
├── ibug_to_bfm2009.txt
├── ibug_to_bfm2017-1_bfm_nomouth.txt
├── ibug_to_sfm.txt
├── readme.txt
├── scripts
│ ├── compute_edgestruct.m
│ ├── convert-bfm2009-to-eos.py
│ ├── convert-bfm2017-to-eos.py
│ ├── generate-edgestruct.py
│ └── load_lyhm.py
├── sfm_3448_edge_topology.json
├── sfm_model_contours.json
├── sfm_reference.obj
├── sfm_reference_annotated.obj
├── sfm_reference_symmetry.txt
└── sfm_shape_3448.bin
├── tests
└── test_load_model.py
├── utils
├── CMakeLists.txt
└── scm-to-cereal.cpp
├── vcpkg-configuration.json
└── vcpkg.json
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: LLVM
3 | AccessModifierOffset: '-4'
4 | AlwaysBreakTemplateDeclarations: 'true'
5 | BreakBeforeBraces: Custom
6 | BraceWrapping:
7 | AfterClass: true
8 | AfterControlStatement: true
9 | AfterEnum: false
10 | AfterFunction: true
11 | AfterNamespace: false
12 | AfterObjCDeclaration: false
13 | AfterStruct: true
14 | AfterUnion: false
15 | BeforeCatch: false
16 | BeforeElse: false
17 | IndentBraces: false
18 | ColumnLimit: '110'
19 | Cpp11BracedListStyle: 'true'
20 | PointerAlignment: Left
21 | AllowShortFunctionsOnASingleLine: Empty
22 | IndentWidth: '4'
23 | Language: Cpp
24 | NamespaceIndentation: None
25 | SortIncludes: false
26 | Standard: Cpp11
27 | UseTab: Never
28 | # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
29 |
30 | ...
31 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Explicitly declare text files we want to always be normalized and converted
5 | # to native line endings on checkout.
6 | *.c text
7 | *.cpp text
8 | *.h text
9 | *.hxx text
10 | *.hpp text
11 |
12 | # Denote all files that are truly binary and should not be modified.
13 | *.png binary
14 | *.jpg binary
15 |
16 | # Standard to msysgit
17 | *.doc diff=astextplain
18 | *.DOC diff=astextplain
19 | *.docx diff=astextplain
20 | *.DOCX diff=astextplain
21 | *.dot diff=astextplain
22 | *.DOT diff=astextplain
23 | *.pdf diff=astextplain
24 | *.PDF diff=astextplain
25 | *.rtf diff=astextplain
26 | *.RTF diff=astextplain
27 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [patrikhuber]
2 |
--------------------------------------------------------------------------------
/.github/workflows/build_wheels.yml:
--------------------------------------------------------------------------------
1 | name: Build Python wheels
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build_wheels:
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | os: [windows-latest, ubuntu-24.04, ubuntu-latest, ubuntu-20.04, macos-latest, macos-13]
15 | python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
16 |
17 | name: ${{matrix.os}}, python-${{matrix.python-version}}
18 |
19 | runs-on: ${{matrix.os}}
20 |
21 | steps:
22 | - uses: actions/checkout@v3
23 | with:
24 | submodules: true
25 |
26 | - name: Set up Python ${{ matrix.python-version }}
27 | uses: actions/setup-python@v4
28 | with:
29 | python-version: ${{ matrix.python-version }}
30 |
31 | - name: Install dependencies
32 | run: |
33 | python -m pip install --upgrade pip
34 | pip install setuptools wheel
35 | - name: Build Wheel
36 | run: |
37 | python setup.py bdist_wheel
38 | - name: Upload artifact
39 | uses: actions/upload-artifact@v4
40 | with:
41 | name: ${{ matrix.os }}-python${{ matrix.python-version }}-whl
42 | path: dist/*.whl
43 |
44 | build_sdist:
45 | name: sdist
46 | runs-on: ubuntu-latest
47 |
48 | steps:
49 | - uses: actions/checkout@v3
50 | with:
51 | submodules: true
52 |
53 | - name: Install dependencies
54 | run: |
55 | python -m pip install --upgrade pip
56 | pip install setuptools wheel
57 | - name: Build sdist
58 | run: |
59 | python setup.py sdist
60 | - name: Upload artifact
61 | uses: actions/upload-artifact@v4
62 | with:
63 | name: Source distribution (sdist)
64 | path: dist/*.*
65 |
--------------------------------------------------------------------------------
/.github/workflows/cibuildwheel.yml:
--------------------------------------------------------------------------------
1 | name: cibuildwheel build
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - master
8 | release:
9 | types:
10 | - published
11 |
12 | jobs:
13 | make_sdist:
14 | name: Make SDist
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 | with:
19 | submodules: recursive
20 |
21 | - name: Install dependencies
22 | run: |
23 | python -m pip install --upgrade pip
24 | pip install setuptools wheel
25 |
26 | - name: Build sdist
27 | run: |
28 | python setup.py sdist
29 |
30 | - name: Upload artifact
31 | uses: actions/upload-artifact@v4
32 | with:
33 | path: dist/*.*
34 |
35 | build_wheels:
36 | name: Build wheels on ${{ matrix.os }}
37 | runs-on: ${{ matrix.os }}
38 | strategy:
39 | fail-fast: false
40 | matrix:
41 | os: [ubuntu-22.04, windows-2022, macos-13]
42 |
43 | steps:
44 | - uses: actions/checkout@v3
45 | with:
46 | submodules: recursive
47 |
48 | # Used to host cibuildwheel
49 | - uses: actions/setup-python@v3
50 |
51 | - name: Use cmake
52 | run: cmake --version
53 |
54 | - name: Install cibuildwheel
55 | run: python -m pip install cibuildwheel==2.15.0
56 |
57 | - name: Build wheels
58 | run: python -m cibuildwheel --output-dir wheelhouse
59 | # to supply options, put them in 'env', like:
60 | env:
61 | MACOSX_DEPLOYMENT_TARGET: 10.15
62 | CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
63 | CIBW_SKIP: pp* *i686 cp36-*
64 | CIBW_TEST_REQUIRES: pytest numpy
65 | CIBW_TEST_COMMAND: pytest {package}/tests
66 | CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64"
67 |
68 | - uses: actions/upload-artifact@v4
69 | with:
70 | path: ./wheelhouse/*.whl
71 |
72 | upload_all:
73 | needs: [build_wheels, make_sdist]
74 | environment: pypi
75 | permissions:
76 | id-token: write
77 | runs-on: ubuntu-latest
78 | if: github.event_name == 'release' && github.event.action == 'published'
79 | steps:
80 | - uses: actions/download-artifact@v4
81 | with:
82 | name: artifact
83 | path: dist
84 |
85 | - uses: pypa/gh-action-pypi-publish@release/v1
--------------------------------------------------------------------------------
/.github/workflows/cmake.yml:
--------------------------------------------------------------------------------
1 | name: C++ build
2 |
3 | on:
4 | push:
5 | branches: [ "master", "devel" ]
6 | pull_request:
7 | branches: [ "master", "devel" ]
8 |
9 | env:
10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
11 | BUILD_TYPE: Release
12 |
13 | jobs:
14 | build:
15 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
16 | # You can convert this to a matrix build if you need cross-platform coverage.
17 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
18 | strategy:
19 | fail-fast: false
20 | matrix:
21 | os: [windows-latest, windows-2019, ubuntu-24.04, ubuntu-latest, ubuntu-20.04, macos-latest, macos-13]
22 |
23 | name: ${{matrix.os}}
24 |
25 | runs-on: ${{matrix.os}}
26 |
27 | env:
28 | # Set cache_path to the vcpkg default Windows directory if the OS is Windows, otherwise set it to the default Linux / macOS directory:
29 | cache_path: ${{ startsWith(matrix.os, 'windows') && 'C:/Users/runneradmin/AppData/Local/vcpkg/archives/' || '~/.cache/vcpkg/archives/' }}
30 |
31 | steps:
32 | - uses: actions/checkout@v3
33 | with:
34 | submodules: true
35 |
36 | - name: Install vcpkg on macOS if not pre-installed
37 | if: runner.os == 'macOS' && (matrix.os == 'macos-13' || matrix.os == 'macos-latest')
38 | run: |
39 | git clone https://github.com/microsoft/vcpkg.git
40 | ./vcpkg/bootstrap-vcpkg.sh
41 | shell: bash
42 |
43 | - name: Set VCPKG_ROOT environment variable
44 | shell: bash
45 | run: |
46 | if [[ "$RUNNER_OS" == "macOS" ]]; then
47 | echo "VCPKG_ROOT=$GITHUB_WORKSPACE/vcpkg" >> $GITHUB_ENV
48 | else
49 | echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
50 | fi
51 |
52 | - name: Cache/restore vcpkg dependencies
53 | uses: actions/cache@v3
54 | with:
55 | path: ${{env.cache_path}}
56 | key: ${{matrix.os}}-vcpkg-cache-${{ hashFiles('vcpkg.json', '.github/workflows/cmake.yml') }}
57 | restore-keys: |
58 | ${{matrix.os}}-vcpkg-cache-
59 |
60 | - name: Configure CMake
61 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
62 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
63 | run: >
64 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
65 | -DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake
66 | -DVCPKG_MANIFEST_FEATURES="ceres"
67 | -DEOS_BUILD_CERES_EXAMPLE=ON -DEOS_BUILD_UTILS=ON -DEOS_GENERATE_PYTHON_BINDINGS=ON
68 |
69 | - name: Build
70 | # Build your program with the given configuration
71 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
72 |
73 | - name: Test
74 | working-directory: ${{github.workspace}}/build
75 | # Execute tests defined by the CMake configuration.
76 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
77 | run: ctest -C ${{env.BUILD_TYPE}}
78 |
--------------------------------------------------------------------------------
/.github/workflows/msvc.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | #
6 | # Find more information at:
7 | # https://github.com/microsoft/msvc-code-analysis-action
8 |
9 | name: Microsoft C++ Code Analysis
10 |
11 | on:
12 | push:
13 | branches: [ "master", devel ]
14 | pull_request:
15 | branches: [ "master", devel ]
16 | schedule:
17 | - cron: '38 1 * * 0'
18 |
19 | env:
20 | # Path to the CMake build directory.
21 | build: '${{ github.workspace }}/build'
22 | BUILD_TYPE: Debug
23 |
24 | permissions:
25 | contents: read
26 |
27 | jobs:
28 | analyze:
29 | permissions:
30 | contents: read # for actions/checkout to fetch code
31 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
32 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
33 | name: Analyze
34 | runs-on: windows-latest
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v3
39 | with:
40 | submodules: true
41 |
42 | - name: "Set VCPKG_ROOT environment variable"
43 | shell: bash
44 | run: |
45 | echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV
46 |
47 | - name: Cache/restore vcpkg dependencies
48 | uses: actions/cache@v3
49 | with:
50 | path: C:/Users/runneradmin/AppData/Local/vcpkg/archives/
51 | key: ${{runner.OS}}-vcpkg-cache-${{ hashFiles('vcpkg.json', '.github/workflows/cmake.yml') }}
52 | restore-keys: |
53 | ${{runner.OS}}-vcpkg-cache-
54 |
55 | - name: Configure CMake
56 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
57 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
58 | run: >
59 | cmake -B ${{env.build}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
60 | -DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake
61 | -DVCPKG_MANIFEST_FEATURES="ceres"
62 | -DEOS_BUILD_CERES_EXAMPLE=ON -DEOS_BUILD_UTILS=ON -DEOS_GENERATE_PYTHON_BINDINGS=ON
63 | # Build is not required unless generated source files are used
64 | # - name: Build CMake
65 | # run: cmake --build ${{ env.build }}
66 |
67 | - name: Run MSVC Code Analysis
68 | uses: microsoft/msvc-code-analysis-action@96315324a485db21449515180214ecb78c16a1c5
69 | # Provide a unique ID to access the sarif output path
70 | id: run-analysis
71 | with:
72 | cmakeBuildDirectory: ${{ env.build }}
73 | buildConfiguration: ${{ env.BUILD_TYPE }}
74 | # Ruleset file that will determine what checks will be run
75 | ruleset: NativeRecommendedRules.ruleset
76 | # Paths to ignore analysis of CMake targets and includes
77 | # ignoredPaths: ${{ github.workspace }}/dependencies;${{ github.workspace }}/test
78 | ignoredPaths: ${{ github.workspace }}/3rdparty/eigen/
79 |
80 | # Upload SARIF file to GitHub Code Scanning Alerts
81 | - name: Upload SARIF to GitHub
82 | uses: github/codeql-action/upload-sarif@v2
83 | with:
84 | sarif_file: ${{ steps.run-analysis.outputs.sarif }}
85 |
86 | # Upload SARIF file as an Artifact to download and view
87 | - name: Upload SARIF as an Artifact
88 | uses: actions/upload-artifact@v4
89 | with:
90 | name: sarif-file
91 | path: ${{ steps.run-analysis.outputs.sarif }}
92 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore files generated by Visual Studio's CMake:
2 | .vs/
3 | out/build/
4 | CMakePresets.json
5 |
6 | # Ignore (optional) configuration files with user-specific paths:
7 | initial_cache.cmake
8 | setup.cfg
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "3rdparty/pybind11"]
2 | path = 3rdparty/pybind11
3 | url = https://github.com/pybind/pybind11.git
4 | [submodule "3rdparty/nanoflann"]
5 | path = 3rdparty/nanoflann
6 | url = https://github.com/jlblancoc/nanoflann.git
7 | [submodule "3rdparty/eigen3-nnls"]
8 | path = 3rdparty/eigen3-nnls
9 | url = https://github.com/hmatuschek/eigen3-nnls.git
10 | [submodule "3rdparty/mexplus"]
11 | path = 3rdparty/mexplus
12 | url = https://github.com/kyamagu/mexplus.git
13 | [submodule "3rdparty/cereal"]
14 | path = 3rdparty/cereal
15 | url = https://github.com/USCiLab/cereal.git
16 | [submodule "3rdparty/toml11"]
17 | path = 3rdparty/toml11
18 | url = https://github.com/ToruNiina/toml11.git
19 | [submodule "3rdparty/eigen"]
20 | path = 3rdparty/eigen
21 | url = https://gitlab.com/libeigen/eigen.git
22 |
--------------------------------------------------------------------------------
/.natvis/eos.natvis:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | UINT8
17 |
18 |
19 | INT32
20 |
21 |
22 | FLOAT32
23 |
24 |
25 | FLOAT64
26 |
27 |
28 |
29 | 1
30 |
31 |
32 | - width_
33 | - height_
34 |
35 | - ($T1*)(&data_[0])
36 |
37 | - row_stride
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | UINT8
46 |
47 |
48 | INT32
49 |
50 |
51 | FLOAT32
52 |
53 |
54 | FLOAT64
55 |
56 |
57 |
58 | RGB
59 |
60 |
61 | RGBA
62 |
63 |
64 |
65 | - width_
66 | - height_
67 |
68 | - ($T1*)(&data_[0])
69 |
70 | - row_stride
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: "Huber"
5 | given-names: "Patrik"
6 | orcid: "https://orcid.org/0000-0002-1474-1040"
7 | title: "eos: A lightweight 3D Morphable Face Model library in modern C++"
8 | version: 1.5.0
9 | date-released: 2024-12-10
10 | url: "https://github.com/patrikhuber/eos"
11 | license: Apache-2.0
12 | preferred-citation:
13 | type: conference-paper
14 | title: "A Multiresolution 3D Morphable Face Model and Fitting Framework"
15 | authors:
16 | - family-names: "Huber"
17 | given-names: "Patrik"
18 | orcid: "https://orcid.org/0000-0002-1474-1040"
19 | - family-names: "Hu"
20 | given-names: "Guosheng"
21 | - family-names: "Tena"
22 | given-names: "Jose Rafael"
23 | - family-names: "Mortazavian"
24 | given-names: "Pouria"
25 | - family-names: "Koppen"
26 | given-names: "Willen P."
27 | - family-names: "Christmas"
28 | given-names: "William J."
29 | - family-names: "Raetsch"
30 | given-names: "Matthias"
31 | - family-names: "Kittler"
32 | given-names: "Josef"
33 | orcid: "https://orcid.org/0000-0002-8110-9205"
34 | doi: "10.5220/0005669500790086"
35 | conference:
36 | name: "11th Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP 2016)"
37 | volume-title: "Proceedings of the 11th Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP 2016)"
38 | start: 79 # First page number
39 | end: 86 # Last page number
40 | volume: 4
41 | year: 2016
42 | month: 2
43 | publisher:
44 | name: "SciTePress"
45 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md LICENSE
2 | global-include CMakeLists.txt *.cmake
3 | exclude initial_cache.cmake
4 | recursive-exclude out *
5 | recursive-include 3rdparty/cereal/include *
6 | recursive-include 3rdparty/eigen/Eigen *
7 | recursive-include 3rdparty/eigen3-nnls/src *.h
8 | recursive-include 3rdparty/nanoflann/include *
9 | recursive-include 3rdparty/toml11 *.hpp
10 | recursive-include 3rdparty/pybind11 *
11 | recursive-include include *
12 | recursive-include python *
13 |
--------------------------------------------------------------------------------
/doc/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | find_package(Doxygen REQUIRED)
2 |
3 | set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
4 | set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
5 |
6 | configure_file(${doxyfile_in} ${doxyfile} @ONLY)
7 |
8 | add_custom_target(doc
9 | COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
10 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
11 | COMMENT "Generating API documentation with Doxygen"
12 | VERBATIM
13 | )
14 |
15 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION doc)
16 |
--------------------------------------------------------------------------------
/doc/Doxyfile.in:
--------------------------------------------------------------------------------
1 | PROJECT_NAME = "@CMAKE_PROJECT_NAME@"
2 | PROJECT_NUMBER = @eos_VERSION_MAJOR@.@eos_VERSION_MINOR@.@eos_VERSION_PATCH@
3 | STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@
4 | INPUT = @PROJECT_SOURCE_DIR@/README.md \
5 | @PROJECT_SOURCE_DIR@/doc/namespaces.doxygen \
6 | @PROJECT_SOURCE_DIR@/include
7 | RECURSIVE = YES
8 | EXCLUDE_PATTERNS = */detail/*
9 |
10 | USE_MDFILE_AS_MAINPAGE = README.md
11 |
12 | USE_MATHJAX = YES
13 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML
14 |
--------------------------------------------------------------------------------
/doc/namespaces.doxygen:
--------------------------------------------------------------------------------
1 | /**
2 | * @namespace eos
3 | * @brief Namespace containing all of eos's 3D model fitting functionality.
4 | */
5 |
6 | /**
7 | * @namespace eos::core
8 | * @brief Essential functions and classes to work with 3D face models, meshes and landmarks.
9 | */
10 |
11 | /**
12 | * @namespace eos::fitting
13 | * @brief Pose and shape fitting of a 3D Morphable Model.
14 | */
15 |
16 | /**
17 | * @namespace eos::morphablemodel
18 | * @brief Functionality to represent a Morphable Model, its PCA models, and functions to load models and blendshapes.
19 | */
20 |
21 | /**
22 | * @namespace eos::pca
23 | * @brief PCA and functionality to build statistical models.
24 | */
25 |
26 | /**
27 | * @namespace eos::render
28 | * @brief Software rendering and texture extraction functionality.
29 | */
30 |
31 | /**
32 | * @namespace eos::video
33 | * @brief Video keyframe extraction and fusion.
34 | */
35 |
36 | /**
37 | * @namespace eos::cpp17
38 | * @brief Replacement types and functions for C++17 standard library functionality for compilers who don't have them (for example AppleClang).
39 | */
40 |
--------------------------------------------------------------------------------
/examples/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # The examples need a few additional dependencies (e.g. boost filesystem, program_options, and OpenCV highgui):
2 |
3 | # Check installed version in order to include the correct OpenCV libraries:
4 | # First call find_package without a version to find any OpenCV. OpenCV_VERSION_MAJOR is then defined.
5 | find_package(OpenCV REQUIRED core)
6 | if("${OpenCV_VERSION_MAJOR}$" EQUAL 2)
7 | message(STATUS "OpenCV 2.x detected")
8 | find_package(OpenCV 2.4.3 REQUIRED core imgproc highgui)
9 | elseif("${OpenCV_VERSION_MAJOR}$" EQUAL 3)
10 | message(STATUS "OpenCV 3.x detected")
11 | find_package(OpenCV 3 REQUIRED core imgproc imgcodecs)
12 | elseif("${OpenCV_VERSION_MAJOR}$" EQUAL 4)
13 | message(STATUS "OpenCV 4.x detected")
14 | find_package(OpenCV 4 REQUIRED core imgproc imgcodecs)
15 | endif()
16 | # This allows us to compile in RelWithDebInfo. It'll use the Release-version of OpenCV:
17 | set_target_properties(${OpenCV_LIBS} PROPERTIES MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)
18 |
19 | set(Boost_NO_WARN_NEW_VERSIONS ON) # Supress "New Boost version may have incorrect dependencies or import targets" warning
20 | find_package(Boost 1.71.0 REQUIRED COMPONENTS filesystem program_options)
21 |
22 | # Simple model fitting (orthographic camera & shape to landmarks) example:
23 | add_executable(fit-model-simple fit-model-simple.cpp)
24 | target_link_libraries(fit-model-simple PRIVATE eos ${OpenCV_LIBS} Boost::filesystem Boost::program_options)
25 | target_link_libraries(fit-model-simple PRIVATE "$<$:-pthread>$<$:-pthreads>")
26 | target_compile_options(fit-model-simple PRIVATE "$<$:/bigobj>")
27 | target_include_directories(fit-model-simple PRIVATE ${OpenCV_INCLUDE_DIRS})
28 |
29 | # Model fitting example that fits orthographic camera, shape, blendshapes, and contours:
30 | add_executable(fit-model fit-model.cpp)
31 | target_link_libraries(fit-model PRIVATE eos ${OpenCV_LIBS} Boost::filesystem Boost::program_options)
32 | target_link_libraries(fit-model PRIVATE "$<$:-pthread>$<$:-pthreads>")
33 | target_compile_options(fit-model PRIVATE "$<$:/bigobj>")
34 | target_include_directories(fit-model PRIVATE ${OpenCV_INCLUDE_DIRS})
35 |
36 | # Model fitting example that fits orthographic camera, shape, blendshapes, and contours to multiple images:
37 | add_executable(fit-model-multi fit-model-multi.cpp)
38 | target_link_libraries(fit-model-multi PRIVATE eos ${OpenCV_LIBS} Boost::filesystem Boost::program_options)
39 | target_link_libraries(fit-model-multi PRIVATE "$<$:-pthread>$<$:-pthreads>")
40 | target_compile_options(fit-model-multi PRIVATE "$<$:/bigobj>")
41 | target_include_directories(fit-model-multi PRIVATE ${OpenCV_INCLUDE_DIRS})
42 |
43 | # Generate random samples from the model:
44 | add_executable(generate-obj generate-obj.cpp)
45 | target_link_libraries(generate-obj PRIVATE eos ${OpenCV_LIBS} Boost::filesystem Boost::program_options)
46 | target_include_directories(generate-obj PRIVATE ${OpenCV_INCLUDE_DIRS})
47 |
48 | # Install these targets:
49 | install(TARGETS fit-model-simple DESTINATION bin)
50 | install(TARGETS fit-model DESTINATION bin)
51 | install(TARGETS fit-model-multi DESTINATION bin)
52 | install(TARGETS generate-obj DESTINATION bin)
53 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data DESTINATION bin)
54 |
55 |
56 | if(EOS_BUILD_CERES_EXAMPLE)
57 | # Find Ceres, for the fit-model-ceres app:
58 | find_package(Ceres REQUIRED)
59 |
60 | # Single and multi-image non-linear model fitting with Ceres example:
61 | add_executable(fit-model-ceres fit-model-ceres.cpp)
62 | target_link_libraries(fit-model-ceres PRIVATE eos Ceres::ceres ${OpenCV_LIBS} Boost::filesystem Boost::program_options)
63 | target_compile_options(fit-model-ceres PRIVATE "$<$:/bigobj>")
64 | target_include_directories(fit-model-ceres PRIVATE ${OpenCV_INCLUDE_DIRS})
65 | install(TARGETS fit-model-ceres DESTINATION bin)
66 | endif()
67 |
--------------------------------------------------------------------------------
/examples/data/image_0010.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patrikhuber/eos/ce984207a51c2edd2e7568a64fec9b98ef61aeed/examples/data/image_0010.png
--------------------------------------------------------------------------------
/examples/data/image_0010.pts:
--------------------------------------------------------------------------------
1 | version: 1
2 | n_points: 68
3 | {
4 | 611.284152 272.773913
5 | 607.899810 304.319120
6 | 613.094672 339.255590
7 | 622.808910 372.005502
8 | 632.669412 404.678824
9 | 643.511765 432.387059
10 | 651.944706 460.095294
11 | 665.273062 490.435795
12 | 695.836418 505.268304
13 | 732.882854 507.601124
14 | 771.140919 496.682178
15 | 814.580000 468.528235
16 | 852.378512 442.776782
17 | 879.780380 411.071469
18 | 894.313442 365.675605
19 | 905.385571 315.920470
20 | 912.766990 265.622269
21 | 608.920127 214.000560
22 | 624.612439 205.921886
23 | 641.092550 213.028614
24 | 656.643518 218.496370
25 | 675.118172 229.895972
26 | 714.507903 232.709448
27 | 746.296501 221.279247
28 | 780.463683 216.098001
29 | 814.843700 219.577695
30 | 843.144930 231.216340
31 | 691.116694 258.293884
32 | 686.687460 284.649159
33 | 678.837382 314.952208
34 | 671.575170 341.518858
35 | 662.787059 357.695294
36 | 672.577890 363.872007
37 | 684.099935 368.436761
38 | 701.177972 366.977129
39 | 716.657204 364.432781
40 | 629.308705 253.419965
41 | 641.102353 239.634118
42 | 656.763529 242.043529
43 | 675.896682 261.234513
44 | 657.320778 266.311140
45 | 639.427321 264.662791
46 | 746.963287 268.769913
47 | 763.151112 249.645230
48 | 792.895294 251.681176
49 | 810.965882 264.932941
50 | 793.647370 274.870034
51 | 770.089168 277.392535
52 | 650.466760 402.919129
53 | 662.802218 396.521655
54 | 674.655327 393.178631
55 | 685.548727 399.199281
56 | 699.727862 394.238444
57 | 720.617079 403.327949
58 | 762.033016 412.238881
59 | 727.622851 431.747041
60 | 706.539636 437.383098
61 | 691.346572 438.212545
62 | 679.045609 436.837854
63 | 665.204535 428.934293
64 | 657.444159 406.740225
65 | 677.532790 409.255983
66 | 688.027122 410.142694
67 | 701.031914 411.571227
68 | 750.088005 413.800864
69 | 701.031914 411.571227
70 | 688.027122 410.142694
71 | 677.532790 409.255983
72 | }
--------------------------------------------------------------------------------
/examples/data/notes.txt:
--------------------------------------------------------------------------------
1 | The data in this folder was downloaded from http://ibug.doc.ic.ac.uk/resources/300-W/ on 15 December 2014.
2 |
--------------------------------------------------------------------------------
/examples/generate-obj.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: examples/generate-obj.cpp
5 | *
6 | * Copyright 2016, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #include "eos/core/Image.hpp"
21 | #include "eos/core/image/opencv_interop.hpp"
22 | #include "eos/core/write_obj.hpp"
23 | #include "eos/core/math.hpp"
24 | #include "eos/morphablemodel/MorphableModel.hpp"
25 | #include "eos/render/render.hpp"
26 | #include "eos/render/matrix_projection.hpp"
27 | #include "eos/cpp17/optional.hpp"
28 |
29 | #include "boost/filesystem.hpp"
30 | #include "boost/program_options.hpp"
31 |
32 | #include "opencv2/core/core.hpp"
33 | #include "opencv2/imgcodecs/imgcodecs.hpp"
34 |
35 | #include
36 |
37 | using namespace eos;
38 | namespace po = boost::program_options;
39 | namespace fs = boost::filesystem;
40 | using std::cout;
41 | using std::endl;
42 | using std::string;
43 | using std::vector;
44 |
45 | /**
46 | * This app generates random samples from the model and stores them as obj file
47 | * as well as outputs a frontal rendering of the sample.
48 | *
49 | * A list of shape and/or colour coefficients can be specified. Any coefficient
50 | * not specified will be set to zero.
51 | */
52 | int main(int argc, char* argv[])
53 | {
54 | string model_file, output_file;
55 | vector shape_coefficients, color_coefficients;
56 |
57 | try
58 | {
59 | po::options_description desc("Allowed options");
60 | // clang-format off
61 | desc.add_options()
62 | ("help", "produce help message")
63 | ("model", po::value(&model_file)->required(), "an eos .bin Morphable Model file")
64 | ("shape-coeffs", po::value>(&shape_coefficients)->multitoken(),
65 | "optional parameter list of shape coefficients. All not specified will be set to zero. E.g.: "
66 | "'--shape-coeffs 0.0 1.5'. If omitted, the mean is used.")
67 | ("color-coeffs", po::value>(&color_coefficients)->multitoken(),
68 | "optional parameter list of colour coefficients. All not specified will be set to zero. E.g.: "
69 | "'--colour-coeffs 0.0 1.5'. If omitted, the mean is used.")
70 | ("output", po::value(&output_file)->default_value("output.obj"),
71 | "name of the output obj file (including .obj). Can be a full path.");
72 | // clang-format on
73 | po::variables_map vm;
74 | // disabling short options to allow negative values for the coefficients, e.g. '--shape-coeffs 0.0 -1.5'
75 | po::store(
76 | po::parse_command_line(argc, argv, desc,
77 | po::command_line_style::unix_style ^ po::command_line_style::allow_short),
78 | vm);
79 | if (vm.count("help"))
80 | {
81 | cout << "Usage: generate-obj [options]" << endl;
82 | cout << desc;
83 | return EXIT_SUCCESS;
84 | }
85 | po::notify(vm);
86 | } catch (const po::error& e)
87 | {
88 | cout << "Error while parsing command-line arguments: " << e.what() << endl;
89 | cout << "Use --help to display a list of options." << endl;
90 | return EXIT_FAILURE;
91 | }
92 |
93 | morphablemodel::MorphableModel morphable_model = morphablemodel::load_model(model_file);
94 |
95 | if (shape_coefficients.size() < morphable_model.get_shape_model().get_num_principal_components())
96 | {
97 | shape_coefficients.resize(morphable_model.get_shape_model().get_num_principal_components());
98 | }
99 |
100 | if (color_coefficients.size() < morphable_model.get_color_model().get_num_principal_components())
101 | {
102 | color_coefficients.resize(morphable_model.get_color_model().get_num_principal_components());
103 | }
104 |
105 | const core::Mesh sample_mesh = morphable_model.draw_sample(
106 | shape_coefficients, color_coefficients); // if one of the two vectors is empty, it uses get_mean()
107 |
108 | core::write_obj(sample_mesh, output_file);
109 |
110 | const auto perspective = render::perspective(core::radians(60.0f), 512.0f / 512.0f, 0.1f, 500.0f);
111 | // Could use orthographic projection accordingly:
112 | // const auto ortho = render::ortho(-130.0f, 130.0f, -130.0f, 130.0f);
113 | // (and set enable_near_clipping and enable_far_clipping to false, or use the ortho() overload with
114 | // appropriate near/far values.)
115 | Eigen::Matrix4f model_view = Eigen::Matrix4f::Identity();
116 | model_view(2, 3) = -200.0f; // move the model 200 units back along the z-axis
117 |
118 | const core::Image4u rendering =
119 | render::render(sample_mesh, model_view, perspective, 512, 512, true, true, true);
120 | fs::path filename_rendering(output_file);
121 | filename_rendering.replace_extension(".png");
122 | cv::imwrite(filename_rendering.string(), core::to_mat(rendering));
123 |
124 | cout << "Wrote the generated obj and a rendering to files with basename " << output_file << "." << endl;
125 |
126 | return EXIT_SUCCESS;
127 | }
128 |
--------------------------------------------------------------------------------
/include/eos/core/Image.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/Image.hpp
5 | *
6 | * Copyright 2017, 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_IMAGE_HPP
23 | #define EOS_IMAGE_HPP
24 |
25 | #include "eos/core/image/Pixel.hpp"
26 | #include "eos/core/image/PixelTraits.hpp"
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | namespace eos {
33 | namespace core {
34 |
35 | /**
36 | * @brief Class to represent images.
37 | *
38 | * The class currently uses row-major storage order.
39 | *
40 | * Some of the code is inspired by the Selene library (https://github.com/kmhofmann/selene, MIT license).
41 | */
42 | template
43 | class Image
44 | {
45 | public:
46 | using pixel_type = PixelType;
47 |
48 | Image() = default;
49 |
50 | // Initialises with all zeros. This is a bit of an overhead. We probably have to use unique_ptr or a raw
51 | // pointer to get rid of this, as a vector can't have "uninitialised" (yet existing) elements.
52 | Image(int height, int width)
53 | : height_(height), width_(width), row_stride(PixelTraits::num_bytes * width)
54 | {
55 | // data_.reserve(row_stride * height); // just reserves, doesn't put any elements into the vector
56 | data_.resize(row_stride * height);
57 | };
58 |
59 | int height() const noexcept
60 | {
61 | return height_;
62 | };
63 |
64 | int width() const noexcept
65 | {
66 | return width_;
67 | };
68 |
69 | PixelType& operator()(int y, int x) noexcept
70 | {
71 | assert(data_.size() > 0); // byte_ptr() checks this but let's put the assert here too, because this
72 | // function is public-facing.
73 | assert(y >= 0 && y < height_);
74 | assert(x >= 0 && x < width_);
75 | return *data(y, x);
76 | };
77 | const PixelType& operator()(int y, int x) const noexcept
78 | {
79 | assert(data_.size() > 0); // byte_ptr() checks this but let's put the assert here too, because this
80 | // function is public-facing.
81 | assert(y >= 0 && y < height_);
82 | assert(x >= 0 && x < width_);
83 | return *data(y, x);
84 | };
85 |
86 | private:
87 | int height_ = 0;
88 | int width_ = 0;
89 |
90 | int row_stride = 0; // In bytes. >1 means it's a row-major image, 1 would mean a col-major image.
91 |
92 | std::vector data_; // Storage for the image data as bytes
93 |
94 | // Return a std::ptr_diff?
95 | int compute_data_offset(int y, int x) const noexcept
96 | {
97 | return row_stride * y + PixelTraits::num_bytes * x;
98 | };
99 |
100 | std::uint8_t* byte_ptr(int y, int x) noexcept
101 | {
102 | assert(data_.size() > 0);
103 | return &data_[0] + compute_data_offset(y, x);
104 | };
105 | const std::uint8_t* byte_ptr(int y, int x) const noexcept
106 | {
107 | assert(data_.size() > 0);
108 | return &data_[0] + compute_data_offset(y, x);
109 | };
110 |
111 | PixelType* data(int y, int x) noexcept
112 | {
113 | return reinterpret_cast(byte_ptr(y, x));
114 | };
115 | const PixelType* data(int y, int x) const noexcept
116 | {
117 | return reinterpret_cast(byte_ptr(y, x));
118 | };
119 | };
120 |
121 | // Define type aliases for the most commonly used image types:
122 | using Image1u = Image;
123 | using Image3u = Image>;
124 | using Image4u = Image>;
125 | using Image1f = Image;
126 | using Image3f = Image>;
127 | using Image1d = Image;
128 |
129 | } /* namespace core */
130 | } /* namespace eos */
131 |
132 | #endif /* EOS_IMAGE_HPP */
133 |
--------------------------------------------------------------------------------
/include/eos/core/Landmark.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/Landmark.hpp
5 | *
6 | * Copyright 2014, 2015 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_LANDMARK_HPP
23 | #define EOS_LANDMARK_HPP
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | namespace eos {
31 | namespace core {
32 |
33 | /**
34 | * @brief Representation of a landmark, consisting of a landmark name and
35 | * coordinates of the given type. Usually, the type would be \c Eigen::Vector2f.
36 | */
37 | template
38 | struct Landmark
39 | {
40 | std::string name; ///< Name of the landmark, often used as identifier.
41 | LandmarkType coordinates; ///< The position or coordinates of the landmark.
42 | };
43 |
44 | /**
45 | * @brief A trivial collection of landmarks that belong together.
46 | */
47 | template
48 | using LandmarkCollection = std::vector>;
49 |
50 | /**
51 | * @brief Shorthand for a 2D floating point landmark type.
52 | */
53 | // using Landmark2f = Landmark>;
54 |
55 | /**
56 | * @brief Alias for the 2D landmark point type.
57 | */
58 | // using Point2f = Eigen::Vector2f;
59 | // using Point2f = std::array;
60 |
61 | /**
62 | * @brief Filters the given LandmarkCollection and returns a new LandmarkCollection
63 | * containing all landmarks whose name matches the one given by \p filter.
64 | *
65 | * @param[in] landmarks The input LandmarkCollection to be filtered.
66 | * @param[in] filter A list of landmark names (identifiers) by which the given LandmarkCollection is filtered.
67 | * @return A new, filtered LandmarkCollection.
68 | */
69 | template
70 | LandmarkCollection filter(const LandmarkCollection& landmarks, const std::vector& filter)
71 | {
72 | LandmarkCollection filtered_landmarks;
73 | using std::begin;
74 | using std::end;
75 | std::copy_if(
76 | begin(landmarks), end(landmarks), std::back_inserter(filtered_landmarks),
77 | [&](const Landmark& lm) { return std::find(begin(filter), end(filter), lm.name) != end(filter); });
78 | return filtered_landmarks;
79 | };
80 |
81 | } /* namespace core */
82 | } /* namespace eos */
83 |
84 | #endif /* EOS_LANDMARK_HPP */
85 |
--------------------------------------------------------------------------------
/include/eos/core/Mesh.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/Mesh.hpp
5 | *
6 | * Copyright 2014, 2015 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_MESH_HPP
23 | #define EOS_MESH_HPP
24 |
25 | #include "Eigen/Core"
26 |
27 | #include
28 | #include
29 |
30 | namespace eos {
31 | namespace core {
32 |
33 | /**
34 | * @brief This class represents a 3D mesh consisting of vertices, vertex colour
35 | * information and texture coordinates.
36 | *
37 | * Additionally it stores the indices that specify which vertices
38 | * to use to generate the triangle mesh out of the vertices.
39 | *
40 | * \c texcoords should either be the same size as \c vertices (i.e. one set of texture coordinates per
41 | * vertex), or alternatively \c tti can be set, then a separate triangulation for the texture coordinates can
42 | * be used (e.g. for texture maps that contain seams).
43 | */
44 | struct Mesh
45 | {
46 | std::vector vertices; ///< 3D vertex positions.
47 | std::vector colors; ///< Colour information for each vertex. Expected to be in RGB order.
48 | std::vector texcoords; ///< Texture coordinates.
49 |
50 | std::vector> tvi; ///< Triangle vertex indices
51 | std::vector> tci; ///< Triangle color indices (usually the same as tvi)
52 | std::vector> tti; ///< Triangle texture indices
53 | };
54 |
55 | } /* namespace core */
56 | } /* namespace eos */
57 |
58 | #endif /* EOS_MESH_HPP */
59 |
--------------------------------------------------------------------------------
/include/eos/core/Rect.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/Rect.hpp
5 | *
6 | * Copyright 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RECT_HPP
23 | #define EOS_RECT_HPP
24 |
25 | namespace eos {
26 | namespace core {
27 |
28 | /**
29 | * @brief A simple type representing a rectangle.
30 | */
31 | template
32 | struct Rect
33 | {
34 | T x, y; ///< Top-left corner x and y position
35 | T width, height;
36 | };
37 |
38 | } /* namespace core */
39 | } /* namespace eos */
40 |
41 | #endif /* EOS_RECT_HPP */
42 |
--------------------------------------------------------------------------------
/include/eos/core/image/Pixel.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/image/Pixel.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_IMAGE_PIXEL_HPP
23 | #define EOS_IMAGE_PIXEL_HPP
24 |
25 | #include
26 | #include
27 |
28 | namespace eos {
29 | namespace core {
30 |
31 | /**
32 | * @brief Represents a pixel with given type and number of channels.
33 | */
34 | template
35 | class Pixel
36 | {
37 | public:
38 | template >
39 | constexpr Pixel(Args... args) noexcept : data_{{static_cast(args)...}} {};
40 |
41 | constexpr explicit Pixel(const std::array& arr) noexcept : data_(arr){};
42 |
43 | constexpr ElementType& operator[](int i) noexcept
44 | {
45 | return data_[i];
46 | };
47 | constexpr const ElementType& operator[](int i) const noexcept
48 | {
49 | return data_[i];
50 | };
51 |
52 | const std::array& data() const noexcept
53 | {
54 | return data_;
55 | };
56 |
57 | private:
58 | std::array data_;
59 | };
60 |
61 | template
62 | constexpr bool operator==(const Pixel& lhs,
63 | const Pixel& rhs) noexcept
64 | {
65 | return lhs.data() == rhs.data();
66 | };
67 |
68 | } /* namespace core */
69 | } /* namespace eos */
70 |
71 | #endif /* EOS_IMAGE_PIXEL_HPP */
72 |
--------------------------------------------------------------------------------
/include/eos/core/image/PixelTraits.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/image/PixelTraits.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_IMAGE_PIXELTRAITS_HPP
23 | #define EOS_IMAGE_PIXELTRAITS_HPP
24 |
25 | #include "eos/core/image/Pixel.hpp"
26 |
27 | #include
28 |
29 | namespace eos {
30 | namespace core {
31 |
32 | /**
33 | * @brief Todo.
34 | */
35 | template
36 | struct PixelTraits
37 | {
38 | static constexpr std::uint16_t num_bytes = sizeof(ElementType);
39 |
40 | static constexpr ElementType zero_element = ElementType{0};
41 | };
42 |
43 | /**
44 | * @brief Todo.
45 | */
46 | template
47 | struct PixelTraits>
48 | {
49 | static constexpr std::uint16_t num_bytes = sizeof(Pixel);
50 |
51 | static constexpr Pixel zero_element =
52 | Pixel(std::array());
53 | };
54 |
55 | } /* namespace core */
56 | } /* namespace eos */
57 |
58 | #endif /* EOS_IMAGE_PIXELTRAITS_HPP */
59 |
--------------------------------------------------------------------------------
/include/eos/core/image/opencv_interop.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/image/opencv_interop.hpp
5 | *
6 | * Copyright 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_IMAGE_OPENCV_INTEROP_HPP
23 | #define EOS_IMAGE_OPENCV_INTEROP_HPP
24 |
25 | #include "eos/core/Image.hpp"
26 |
27 | #include "opencv2/core/core.hpp"
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | namespace eos {
34 | namespace core {
35 |
36 | // We can support different types by making this a template and constexpr if? :-)
37 | inline cv::Mat to_mat(const Image4u& image)
38 | {
39 | cv::Mat opencv_matrix(static_cast(image.height()), static_cast(image.width()), CV_8UC4);
40 | for (int c = 0; c < image.width(); ++c)
41 | { // size_t
42 | for (int r = 0; r < image.height(); ++r)
43 | {
44 | // auto vals = image(r, c);
45 | opencv_matrix.at(r, c) =
46 | cv::Vec4b(image(r, c)[0], image(r, c)[1], image(r, c)[2], image(r, c)[3]);
47 | }
48 | }
49 | return opencv_matrix;
50 | };
51 |
52 | inline cv::Mat to_mat(const Image3u& image)
53 | {
54 | cv::Mat opencv_matrix(image.height(), image.width(), CV_8UC3);
55 | for (int c = 0; c < image.width(); ++c)
56 | { // size_t
57 | for (int r = 0; r < image.height(); ++r)
58 | {
59 | // auto vals = image(r, c);
60 | opencv_matrix.at(r, c) = cv::Vec3b(image(r, c)[0], image(r, c)[1], image(r, c)[2]);
61 | }
62 | }
63 | return opencv_matrix;
64 | };
65 |
66 | inline cv::Mat to_mat(const Image1d& image)
67 | {
68 | cv::Mat opencv_matrix(static_cast(image.height()), static_cast(image.width()), CV_64FC1);
69 | for (int c = 0; c < image.width(); ++c)
70 | { // size_t
71 | for (int r = 0; r < image.height(); ++r)
72 | {
73 | // auto vals = image(r, c);
74 | opencv_matrix.at(r, c) = image(r, c);
75 | }
76 | }
77 | return opencv_matrix;
78 | };
79 |
80 | inline cv::Mat to_mat(const Image1u& image)
81 | {
82 | cv::Mat opencv_matrix(static_cast(image.height()), static_cast(image.width()), CV_8UC1);
83 | for (int c = 0; c < image.width(); ++c)
84 | { // size_t
85 | for (int r = 0; r < image.height(); ++r)
86 | {
87 | // auto vals = image(r, c);
88 | opencv_matrix.at(r, c) = image(r, c);
89 | }
90 | }
91 | return opencv_matrix;
92 | };
93 |
94 | /**
95 | * Returns an Image3u from a given cv::Mat with type CV_8UC3. The channel order is not changed, i.e. if the
96 | * cv::Mat is BGR, the output Image3u will have BGR channel ordering too.
97 | */
98 | inline Image3u from_mat(const cv::Mat& image)
99 | {
100 | if (image.type() != CV_8UC3)
101 | {
102 | throw std::runtime_error("Can only convert a CV_8UC3 cv::Mat to an eos::core::Image3u.");
103 | }
104 |
105 | Image3u converted(image.rows, image.cols);
106 | for (int r = 0; r < image.rows; ++r)
107 | {
108 | for (int c = 0; c < image.cols; ++c)
109 | {
110 | converted(r, c) = {image.at(r, c)[0], image.at(r, c)[1],
111 | image.at(r, c)[2]};
112 | }
113 | }
114 | return converted;
115 | };
116 |
117 | /**
118 | * Supports both CV_8UC3 and CV_8UC4 cv::Mat as input images. If a CV_8UC3 images is given, then all pixels of
119 | * the alpha channel of the returned image are set to 255.
120 | */
121 | inline Image4u from_mat_with_alpha(const cv::Mat& image)
122 | {
123 | if (image.type() != CV_8UC3 && image.type() != CV_8UC4)
124 | {
125 | throw std::runtime_error("Can only convert a CV_8UC3 or CV_8UC4 cv::Mat to an eos::core::Image4u.");
126 | }
127 |
128 | Image4u converted(image.rows, image.cols);
129 | if (image.type() == CV_8UC3)
130 | {
131 | for (int r = 0; r < image.rows; ++r)
132 | {
133 | for (int c = 0; c < image.cols; ++c)
134 | {
135 | converted(r, c) = {image.at(r, c)[0], image.at(r, c)[1],
136 | image.at(r, c)[2], 255};
137 | }
138 | }
139 | } else if (image.type() == CV_8UC4)
140 | {
141 | for (int r = 0; r < image.rows; ++r)
142 | {
143 | for (int c = 0; c < image.cols; ++c)
144 | {
145 | converted(r, c) = {image.at(r, c)[0], image.at(r, c)[1],
146 | image.at(r, c)[2], image.at(r, c)[3]};
147 | }
148 | }
149 | }
150 | return converted;
151 | };
152 |
153 | } /* namespace core */
154 | } /* namespace eos */
155 |
156 | #endif /* EOS_IMAGE_OPENCV_INTEROP_HPP */
157 |
--------------------------------------------------------------------------------
/include/eos/core/image/utils.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/image/utils.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_IMAGE_UTILS_HPP
23 | #define EOS_IMAGE_UTILS_HPP
24 |
25 | #include "eos/core/image/Pixel.hpp"
26 |
27 | #include
28 |
29 | namespace eos {
30 | namespace core {
31 | namespace image {
32 |
33 | /**
34 | * @brief Creates an image of given type, height and width, with all zeros.
35 | */
36 | template
37 | Image zeros(int height, int width) noexcept
38 | {
39 | Image image(height, width);
40 | for (int y = 0; y < height; ++y)
41 | {
42 | for (int x = 0; x < width; ++x)
43 | {
44 | image(y, x) = PixelTraits::zero_element;
45 | }
46 | }
47 | return image;
48 | };
49 |
50 | /**
51 | * @brief Creates an image of given type, height and width, with a constant value for all pixels.
52 | */
53 | template
54 | Image constant(int height, int width, PixelType value) noexcept
55 | {
56 | Image image(height, width);
57 | for (int y = 0; y < height; ++y)
58 | {
59 | for (int x = 0; x < width; ++x)
60 | {
61 | image(y, x) = value;
62 | }
63 | }
64 | return image;
65 | };
66 |
67 | } // namespace image
68 | } // namespace core
69 | } // namespace eos
70 |
71 | #endif /* EOS_IMAGE_UTILS_HPP */
72 |
--------------------------------------------------------------------------------
/include/eos/core/math.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/math.hpp
5 | *
6 | * Copyright 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_MATH_HPP
23 | #define EOS_MATH_HPP
24 |
25 | #include
26 | #include
27 |
28 | namespace eos {
29 | namespace core {
30 |
31 | /**
32 | * @brief Compile-time constant for pi (19 digits).
33 | */
34 | template
35 | constexpr T pi = T(3.1415926535897932385L);
36 |
37 | /**
38 | * @brief Convert given degrees to radians.
39 | */
40 | template
41 | T radians(T degrees)
42 | {
43 | // Note: We may want to remove this assert, to allow ceres::Jet as type.
44 | static_assert(std::numeric_limits::is_iec559, "radians() only accepts floating-point inputs.");
45 | return degrees * static_cast(0.01745329251994329576923690768489);
46 | };
47 |
48 | /**
49 | * @brief Convert given radians to degree.
50 | */
51 | template
52 | T degrees(T radians)
53 | {
54 | // Note: We may want to remove this assert, to allow ceres::Jet as type.
55 | static_assert(std::numeric_limits::is_iec559, "radians() only accepts floating-point inputs.");
56 | return radians * static_cast(57.295779513082320876798154814105);
57 | };
58 |
59 | /**
60 | * @brief Returns the sign of the given number (-1, 0 or +1).
61 | *
62 | * According to StackOverflow, the < 0 part of the check triggers GCC's -Wtype-limits warning when
63 | * instantiated for an unsigned type. Thus we use two overloads, for signed and unsigned types.
64 | */
65 | template
66 | typename std::enable_if::value, int>::type inline constexpr sign(T const x)
67 | {
68 | return T(0) < x;
69 | };
70 |
71 | /**
72 | * @brief Returns the sign of the given number (-1, 0 or +1).
73 | *
74 | * According to StackOverflow, the < 0 part of the check triggers GCC's -Wtype-limits warning when
75 | * instantiated for an unsigned type. Thus we use two overloads, for signed and unsigned types.
76 | */
77 | template
78 | typename std::enable_if::value, int>::type inline constexpr sign(T const x)
79 | {
80 | return (T(0) < x) - (x < T(0));
81 | };
82 |
83 | } /* namespace core */
84 | } /* namespace eos */
85 |
86 | #endif /* EOS_MATH_HPP */
87 |
--------------------------------------------------------------------------------
/include/eos/core/read_pts_landmarks.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/core/read_pts_landmarks.hpp
5 | *
6 | * Copyright 2014, 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_READ_PTS_LANDMARKS_HPP
23 | #define EOS_READ_PTS_LANDMARKS_HPP
24 |
25 | #include "eos/core/Landmark.hpp"
26 |
27 | #include "Eigen/Core"
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | namespace eos {
35 | namespace core {
36 |
37 | /**
38 | * Reads an ibug .pts landmark file and returns an ordered vector with
39 | * the 68 2D landmark coordinates.
40 | *
41 | * @param[in] filename Path to a .pts file.
42 | * @return An ordered vector with the 68 ibug landmarks.
43 | */
44 | inline LandmarkCollection read_pts_landmarks(std::string filename)
45 | {
46 | using Eigen::Vector2f;
47 | using std::getline;
48 | using std::string;
49 | LandmarkCollection landmarks;
50 | landmarks.reserve(68);
51 |
52 | std::ifstream file(filename);
53 | if (!file)
54 | {
55 | throw std::runtime_error(string("Could not open landmark file: " + filename));
56 | }
57 |
58 | string line;
59 | // Skip the first 3 lines, they're header lines:
60 | getline(file, line); // 'version: 1'
61 | getline(file, line); // 'n_points : 68'
62 | getline(file, line); // '{'
63 |
64 | int ibugId = 1;
65 | while (getline(file, line))
66 | {
67 | if (line == "}")
68 | { // end of the file
69 | break;
70 | }
71 | std::stringstream lineStream(line);
72 |
73 | Landmark landmark;
74 | landmark.name = std::to_string(ibugId);
75 | if (!(lineStream >> landmark.coordinates[0] >> landmark.coordinates[1]))
76 | {
77 | throw std::runtime_error(string("Landmark format error while parsing the line: " + line));
78 | }
79 | // From the iBug website:
80 | // "Please note that the re-annotated data for this challenge are saved in the Matlab convention of 1
81 | // being the first index, i.e. the coordinates of the top left pixel in an image are x=1, y=1."
82 | // ==> So we shift every point by 1:
83 | landmark.coordinates[0] -= 1.0f;
84 | landmark.coordinates[1] -= 1.0f;
85 | landmarks.emplace_back(landmark);
86 | ++ibugId;
87 | }
88 | return landmarks;
89 | };
90 |
91 | } /* namespace core */
92 | } /* namespace eos */
93 |
94 | #endif /* EOS_READ_PTS_LANDMARKS_HPP */
95 |
--------------------------------------------------------------------------------
/include/eos/cpp17/clamp.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/clamp.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_CLAMP_HPP_
23 | #define EOS_CLAMP_HPP_
24 |
25 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
26 | #include
27 | namespace eos {
28 | namespace cpp17 {
29 | using ::std::clamp;
30 | }
31 | }
32 | #else
33 | namespace eos {
34 | namespace cpp17 {
35 | // Returns val constrained to [min, max]
36 | template
37 | constexpr const T& clamp(const T& val, const T& min, const T& max)
38 | {
39 | // this is the implementation that uses:
40 | return ((max < val) ? max : (val < min) ? min : val);
41 | }
42 | }
43 | }
44 | #endif
45 |
46 | #endif /* EOS_CLAMP_HPP_ */
47 |
--------------------------------------------------------------------------------
/include/eos/cpp17/detail/akrzemi1_optional_serialization.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/detail/akrzemi1_optional_serialization.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_AKRZEMI1_OPTIONAL_SERIALIZATION_HPP_
23 | #define EOS_AKRZEMI1_OPTIONAL_SERIALIZATION_HPP_
24 |
25 | #include "eos/cpp17/detail/akrzemi1_optional.hpp"
26 |
27 | #include "cereal/cereal.hpp"
28 |
29 | namespace cereal {
30 |
31 | //! Saving for akrzemi1::optional
32 | template
33 | inline void CEREAL_SAVE_FUNCTION_NAME(Archive& ar, const akrzemi1::optional& optional)
34 | {
35 | if (!optional)
36 | {
37 | ar(CEREAL_NVP_("nullopt", true));
38 | } else
39 | {
40 | ar(CEREAL_NVP_("nullopt", false), CEREAL_NVP_("data", *optional));
41 | }
42 | }
43 |
44 | //! Loading for akrzemi1::optional
45 | template
46 | inline void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, akrzemi1::optional& optional)
47 | {
48 | bool nullopt;
49 | ar(CEREAL_NVP_("nullopt", nullopt));
50 |
51 | if (nullopt)
52 | {
53 | optional = akrzemi1::nullopt;
54 | } else
55 | {
56 | T value;
57 | ar(CEREAL_NVP_("data", value));
58 | optional = std::move(value);
59 | }
60 | }
61 |
62 | } // namespace cereal
63 |
64 | #endif /* EOS_AKRZEMI1_OPTIONAL_SERIALIZATION_HPP_ */
65 |
--------------------------------------------------------------------------------
/include/eos/cpp17/detail/mpark_variant_serialization.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/detail/mpark_variant_serialization.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_MPARK_VARIANT_SERIALIZATION_HPP_
23 | #define EOS_MPARK_VARIANT_SERIALIZATION_HPP_
24 |
25 | #include "eos/cpp17/detail/mpark_variant.hpp"
26 |
27 | #include "cereal/cereal.hpp"
28 |
29 | #include
30 | #include
31 |
32 | namespace cereal {
33 | namespace variant_detail {
34 |
35 | //! @internal
36 | template
37 | struct variant_save_visitor
38 | {
39 | variant_save_visitor(Archive& ar_) : ar(ar_) {}
40 |
41 | template
42 | void operator()(T const& value) const
43 | {
44 | ar(CEREAL_NVP_("data", value));
45 | }
46 |
47 | Archive& ar;
48 | };
49 |
50 | //! @internal
51 | template
52 | typename std::enable_if, void>::type
53 | load_variant(Archive& /*ar*/, int /*target*/, Variant& /*variant*/)
54 | {
55 | throw ::cereal::Exception("Error traversing variant during load");
56 | }
57 |
58 | //! @internal
59 | template
60 | typename std::enable_if <
61 | N, void>::type load_variant(Archive& ar, int target, Variant& variant)
62 | {
63 | if (N == target)
64 | {
65 | H value;
66 | ar(CEREAL_NVP_("data", value));
67 | variant = std::move(value);
68 | } else
69 | load_variant(ar, target, variant);
70 | }
71 |
72 | } // namespace variant_detail
73 |
74 | //! Saving for mpark::variant
75 | template
76 | inline void CEREAL_SAVE_FUNCTION_NAME(Archive& ar,
77 | mpark::variant const& variant)
78 | {
79 | std::int32_t index = static_cast(variant.index());
80 | ar(CEREAL_NVP_("index", index));
81 | variant_detail::variant_save_visitor visitor(ar);
82 | mpark::visit(visitor, variant);
83 | }
84 |
85 | //! Loading for mpark::variant
86 | template
87 | inline void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, mpark::variant& variant)
88 | {
89 | using variant_t = typename mpark::variant;
90 |
91 | std::int32_t index;
92 | ar(CEREAL_NVP_("index", index));
93 | if (index >= static_cast(mpark::variant_size_v))
94 | throw Exception("Invalid 'index' selector when deserializing mpark::variant");
95 |
96 | variant_detail::load_variant<0, variant_t, VariantTypes...>(ar, index, variant);
97 | }
98 |
99 | } // namespace cereal
100 |
101 | #endif /* EOS_MPARK_VARIANT_SERIALIZATION_HPP_ */
102 |
--------------------------------------------------------------------------------
/include/eos/cpp17/optional.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/optional.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_OPTIONAL_HPP_
23 | #define EOS_OPTIONAL_HPP_
24 |
25 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
26 | #include
27 | namespace eos {
28 | namespace cpp17 {
29 | using ::std::optional;
30 | using ::std::nullopt;
31 | }
32 | }
33 | #else
34 | #include "eos/cpp17/detail/akrzemi1_optional.hpp"
35 | namespace eos {
36 | namespace cpp17 {
37 | using ::akrzemi1::optional;
38 | using ::akrzemi1::nullopt;
39 | }
40 | }
41 | #endif
42 |
43 | #endif /* EOS_OPTIONAL_HPP_ */
44 |
--------------------------------------------------------------------------------
/include/eos/cpp17/optional_serialization.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/optional_serialization.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_OPTIONAL_SERIALIZATION_HPP_
23 | #define EOS_OPTIONAL_SERIALIZATION_HPP_
24 |
25 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
26 | #include "cereal/types/optional.hpp"
27 | #else
28 | #include "eos/cpp17/detail/akrzemi1_optional_serialization.hpp"
29 | #endif
30 |
31 | #endif /* EOS_OPTIONAL_SERIALIZATION_HPP_ */
32 |
--------------------------------------------------------------------------------
/include/eos/cpp17/variant.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/variant.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_VARIANT_HPP_
23 | #define EOS_VARIANT_HPP_
24 |
25 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
26 | #include
27 | namespace eos {
28 | namespace cpp17 {
29 | using ::std::variant;
30 | using ::std::holds_alternative;
31 | using ::std::get;
32 | }
33 | }
34 | #else
35 | #include "eos/cpp17/detail/mpark_variant.hpp"
36 | namespace eos {
37 | namespace cpp17 {
38 | using ::mpark::variant;
39 | using ::mpark::holds_alternative;
40 | using ::mpark::get;
41 | }
42 | }
43 | #endif
44 |
45 | #endif /* EOS_VARIANT_HPP_ */
46 |
--------------------------------------------------------------------------------
/include/eos/cpp17/variant_serialization.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/cpp17/variant_serialization.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_VARIANT_SERIALIZATION_HPP_
23 | #define EOS_VARIANT_SERIALIZATION_HPP_
24 |
25 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
26 | #include "cereal/types/variant.hpp"
27 | #else
28 | #include "eos/cpp17/detail/mpark_variant_serialization.hpp"
29 | #endif
30 |
31 | #endif /* EOS_VARIANT_SERIALIZATION_HPP_ */
32 |
--------------------------------------------------------------------------------
/include/eos/fitting/FittingResult.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/fitting/FittingResult.hpp
5 | *
6 | * Copyright 2016 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_FITTINGRESULT_HPP
23 | #define EOS_FITTINGRESULT_HPP
24 |
25 | #include "eos/fitting/RenderingParameters.hpp"
26 |
27 | #include
28 |
29 | namespace eos {
30 | namespace fitting {
31 |
32 | /**
33 | * @brief A struct holding the result from a fitting.
34 | *
35 | * Holds the parameters to store and reproduce a shape fitting result:
36 | * Rendering parameters, PCA shape and expression coefficients.
37 | */
38 | struct FittingResult
39 | {
40 | RenderingParameters rendering_parameters;
41 | std::vector pca_shape_coefficients;
42 | std::vector expression_coefficients;
43 | };
44 |
45 | } /* namespace fitting */
46 | } /* namespace eos */
47 |
48 | #endif /* EOS_FITTINGRESULT_HPP */
49 |
--------------------------------------------------------------------------------
/include/eos/fitting/contour_correspondence.hpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patrikhuber/eos/ce984207a51c2edd2e7568a64fec9b98ef61aeed/include/eos/fitting/contour_correspondence.hpp
--------------------------------------------------------------------------------
/include/eos/fitting/detail/eigen_quaternion_cerealisation.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/fitting/detail/eigen_quaternion_cerealisation.hpp
5 | *
6 | * Copyright 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_EIGEN_QUATERNION_CEREALISATION_HPP
23 | #define EOS_EIGEN_QUATERNION_CEREALISATION_HPP
24 |
25 | #include "cereal/cereal.hpp"
26 |
27 | #include "Eigen/Core"
28 |
29 | /**
30 | * @brief Serialisation of Eigen's \c Eigen::Quaternion for the serialisation library cereal
31 | * (http://uscilab.github.io/cereal/index.html).
32 | *
33 | * Contains serialisation for \c Eigen::Quaternion.
34 | */
35 | namespace Eigen {
36 |
37 | /**
38 | * @brief Serialisation of a Eigen::Quaternion using cereal.
39 | *
40 | * Valid ScalarType's are float and double (Quaternionf and Quaterniond).
41 | *
42 | * @param[in] ar The archive to (de)serialise.
43 | * @param[in] q The quaternion to (de)serialise.
44 | */
45 | template
46 | void serialize(Archive& ar, Eigen::Quaternion& q)
47 | {
48 | ar(q.w(), q.x(), q.y(), q.z());
49 | };
50 |
51 | } /* namespace Eigen */
52 |
53 | #endif /* EOS_EIGEN_QUATERNION_CEREALISATION_HPP */
54 |
--------------------------------------------------------------------------------
/include/eos/fitting/nonlinear_camera_estimation.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/fitting/nonlinear_camera_estimation.hpp
5 | *
6 | * Copyright 2015, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_NONLINEAR_CAMERA_ESTIMATION_HPP
23 | #define EOS_NONLINEAR_CAMERA_ESTIMATION_HPP
24 |
25 | #include "eos/fitting/detail/nonlinear_camera_estimation_detail.hpp"
26 | #include "eos/fitting/RenderingParameters.hpp"
27 |
28 | #include "Eigen/Geometry"
29 | #include "unsupported/Eigen/NonLinearOptimization"
30 |
31 | #include
32 | #include
33 |
34 | namespace eos {
35 | namespace fitting {
36 |
37 | /**
38 | * @brief This algorithm estimates the rotation angles and translation of the model, as
39 | * well as the viewing frustum of the camera, given a set of corresponding 2D-3D points.
40 | *
41 | * It assumes an orthographic camera and estimates 6 parameters,
42 | * [r_x, r_y, r_z, t_x, t_y, frustum_scale], where the first five describe how to transform
43 | * the model, and the last one describes the cameras viewing frustum (see CameraParameters).
44 | * This 2D-3D correspondence problem is solved using Eigen's LevenbergMarquardt algorithm.
45 | *
46 | * The method is slightly inspired by "Computer Vision: Models Learning and Inference",
47 | * Simon J.D. Prince, 2012, but different in a lot of respects.
48 | *
49 | * Eigen's LM implementation requires at least 6 data points, so we require >= 6 corresponding points.
50 | *
51 | * Notes/improvements:
52 | * The algorithm works reliable as it is, however, it could be improved with the following:
53 | * - A better initial guess (see e.g. Prince)
54 | * - We could add a parameter to pass an initial guess
55 | * - Using the analytic derivatives instead of Eigen::NumericalDiff - they're easy to calculate.
56 | *
57 | * @param[in] image_points A list of 2D image points.
58 | * @param[in] model_points Corresponding points of a 3D model.
59 | * @param[in] width Width of the image (or viewport).
60 | * @param[in] height Height of the image (or viewport).
61 | * @return The estimated model and camera parameters.
62 | */
63 | inline RenderingParameters estimate_orthographic_camera(std::vector image_points,
64 | std::vector model_points, int width,
65 | int height)
66 | {
67 | assert(image_points.size() == model_points.size());
68 | assert(image_points.size() >= 6); // Number of correspondence points given needs to be equal to or larger than 6
69 |
70 | const float aspect = static_cast(width) / height;
71 |
72 | // Set up the initial parameter vector and the cost function:
73 | int num_params = 6;
74 | Eigen::VectorXd parameters; // [rot_x_pitch, rot_y_yaw, rot_z_roll, t_x, t_y, frustum_scale]
75 | parameters.setConstant(num_params, 0.0); // Set all 6 values to zero (except frustum_scale, see next line)
76 | parameters[5] = 110.0; // This is just a rough hand-chosen scaling estimate - we could do a lot better. But it works.
77 | detail::OrthographicParameterProjection cost_function(image_points, model_points, width, height);
78 |
79 | // Note: we have analytical derivatives, so we should use them!
80 | Eigen::NumericalDiff cost_function_with_derivative(cost_function,
81 | 0.0001);
82 | // I had to change the default value of epsfcn, it works well around 0.0001. It couldn't produce the
83 | // derivative with the default, I guess the changes in the gradient were too small.
84 |
85 | Eigen::LevenbergMarquardt> lm(
86 | cost_function_with_derivative);
87 | const auto info = lm.minimize(parameters); // we could or should use the return value
88 | // 'parameters' contains the solution now.
89 |
90 | Frustum camera_frustum{
91 | -1.0f * aspect * static_cast(parameters[5]), 1.0f * aspect * static_cast(parameters[5]),
92 | -1.0f * static_cast(parameters[5]), 1.0f * static_cast(parameters[5])};
93 | return RenderingParameters(CameraType::Orthographic, camera_frustum, static_cast(parameters[0]),
94 | static_cast(parameters[1]), static_cast(parameters[2]),
95 | static_cast(parameters[3]), static_cast(parameters[4]), width,
96 | height);
97 | };
98 |
99 | } /* namespace fitting */
100 | } /* namespace eos */
101 |
102 | #endif /* EOS_NONLINEAR_CAMERA_ESTIMATION_HPP */
103 |
--------------------------------------------------------------------------------
/include/eos/fitting/rotation_angles.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/fitting/rotation_angles.hpp
5 | *
6 | * Copyright 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_FITTING_ROTATION_ANGLES_HPP
23 | #define EOS_FITTING_ROTATION_ANGLES_HPP
24 |
25 | #include "eos/core/math.hpp"
26 |
27 | #include "Eigen/Core"
28 |
29 | #include
30 |
31 | namespace eos {
32 | namespace fitting {
33 |
34 | /**
35 | * @brief Computes Tait-Bryan angles (in radians) from the given rotation matrix and axes order.
36 | *
37 | * Calls Eigen::Matrix3::eulerAngles(), but then swap the solution for the one where the middle (pitch) axis
38 | * is constrained to -PI/2 to PI/2.
39 | */
40 | template
41 | inline Eigen::Matrix tait_bryan_angles(Eigen::Matrix rotation_matrix, Eigen::Index axis_0,
42 | Eigen::Index axis_1, Eigen::Index axis_2)
43 | {
44 | Eigen::Matrix euler_angles = rotation_matrix.eulerAngles(axis_0, axis_1, axis_2);
45 | // Eigen::Matrix3X.eulerAngles() returns the solution where the first axis is constrained from 0 to PI.
46 | // This is not what we usually want in robotics; we want the other solution (there are two in the general
47 | // case) where the middle (pitch) axis is constrained to -PI/2 to PI/2. See
48 | // https://gitlab.com/libeigen/eigen/-/issues/2617#note_1298729055
49 | if (std::abs(euler_angles(1)) > T(core::pi / 2.0))
50 | {
51 | euler_angles.array() -= T(core::pi) * euler_angles.array().sign();
52 | euler_angles(1) = -euler_angles(1);
53 | }
54 | return euler_angles;
55 | };
56 |
57 | } /* namespace fitting */
58 | } /* namespace eos */
59 |
60 | #endif /* EOS_FITTING_ROTATION_ANGLES_HPP */
61 |
--------------------------------------------------------------------------------
/include/eos/morphablemodel/Blendshape.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/morphablemodel/Blendshape.hpp
5 | *
6 | * Copyright 2015 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_BLENDSHAPE_HPP
23 | #define EOS_BLENDSHAPE_HPP
24 |
25 | #include "cereal/archives/binary.hpp"
26 | #include "cereal/types/string.hpp"
27 | #include "eos/morphablemodel/io/eigen_cerealisation.hpp"
28 |
29 | #include "Eigen/Core"
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | namespace eos {
37 | namespace morphablemodel {
38 |
39 | /**
40 | * @brief A class representing a 3D blendshape.
41 | *
42 | * A blendshape is a vector of offsets that transform the vertices of
43 | * a given mesh or shape instance. Usually, a blendshape is associated
44 | * with a deformation like a particular facial expression or a phoneme.
45 | */
46 | struct Blendshape
47 | {
48 | std::string name; ///< Name of the blendshape.
49 | Eigen::VectorXf deformation; ///< A 3m x 1 col-vector (xyzxyz...)', where m is the number of
50 | ///< model-vertices. Has the same format as PcaModel::mean.
51 |
52 | friend class cereal::access;
53 | /**
54 | * Serialises this class using cereal.
55 | *
56 | * @param[in] archive The archive to serialise to (or to serialise from).
57 | */
58 | template
59 | void serialize(Archive& archive)
60 | {
61 | archive(CEREAL_NVP(name), CEREAL_NVP(deformation));
62 | };
63 | };
64 |
65 | /**
66 | * Shorthand notation for an std::vector.
67 | */
68 | using Blendshapes = std::vector;
69 |
70 | /**
71 | * Helper method to load a file with blendshapes from
72 | * a cereal::BinaryInputArchive from the harddisk.
73 | *
74 | * @param[in] filename Filename to a blendshapes-file.
75 | * @return The loaded blendshapes.
76 | * @throw std::runtime_error When the file given in \c filename fails to be opened (most likely because the
77 | * file doesn't exist).
78 | */
79 | inline std::vector load_blendshapes(std::string filename)
80 | {
81 | std::vector blendshapes;
82 |
83 | std::ifstream file(filename, std::ios::binary);
84 | if (!file)
85 | {
86 | throw std::runtime_error("Error opening given file: " + filename);
87 | }
88 | cereal::BinaryInputArchive input_archive(file);
89 | input_archive(blendshapes);
90 |
91 | return blendshapes;
92 | };
93 |
94 | /**
95 | * Helper method to save a set of blendshapes to the
96 | * harddisk as a cereal::BinaryOutputArchive.
97 | *
98 | * @param[in] blendshapes The blendshapes to be saved.
99 | * @param[in] filename Filename for the blendshapes.
100 | */
101 | inline void save_blendshapes(const std::vector& blendshapes, std::string filename)
102 | {
103 | std::ofstream file(filename, std::ios::binary);
104 | if (!file)
105 | {
106 | throw std::runtime_error("Error creating given file: " + filename);
107 | }
108 | cereal::BinaryOutputArchive output_archive(file);
109 | output_archive(blendshapes);
110 | };
111 |
112 | /**
113 | * @brief Copies the blendshapes into a matrix, with each column being a blendshape.
114 | *
115 | * @param[in] blendshapes Vector of blendshapes.
116 | * @return The resulting matrix.
117 | */
118 | inline Eigen::MatrixXf to_matrix(const std::vector& blendshapes)
119 | {
120 | assert(blendshapes.size() > 0);
121 | // Todo: Assert all blendshapes have to have the same number of rows, and one col
122 |
123 | Eigen::MatrixXf blendshapes_as_basis(blendshapes[0].deformation.rows(), blendshapes.size());
124 | for (int i = 0; i < blendshapes.size(); ++i)
125 | {
126 | blendshapes_as_basis.col(i) = blendshapes[i].deformation;
127 | }
128 | return blendshapes_as_basis;
129 | };
130 |
131 | /**
132 | * @brief Maps an std::vector of coefficients with Eigen::Map, so it can be multiplied
133 | * with a blendshapes matrix.
134 | *
135 | * Note that the resulting Eigen::Map only lives as long as the data given lives and is in scope.
136 | *
137 | * @param[in] coefficients Vector of blendshape coefficients.
138 | * @return An Eigen::Map pointing to the given coefficients data.
139 | */
140 | inline Eigen::Map to_vector(const std::vector& coefficients)
141 | {
142 | return Eigen::Map(coefficients.data(), coefficients.size());
143 | };
144 |
145 | } /* namespace morphablemodel */
146 | } /* namespace eos */
147 |
148 | #endif /* EOS_BLENDSHAPE_HPP */
149 |
--------------------------------------------------------------------------------
/include/eos/morphablemodel/EdgeTopology.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/morphablemodel/EdgeTopology.hpp
5 | *
6 | * Copyright 2016 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_EDGETOPOLOGY_HPP
23 | #define EOS_EDGETOPOLOGY_HPP
24 |
25 | #include "cereal/cereal.hpp"
26 | #include "cereal/types/array.hpp"
27 | #include "cereal/types/vector.hpp"
28 | #include "cereal/archives/json.hpp"
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | namespace eos {
35 | namespace morphablemodel {
36 |
37 | /**
38 | * @brief A struct containing a 3D shape model's edge topology.
39 | *
40 | * This struct contains all edges of a 3D mesh, and for each edge, it
41 | * contains the two faces and the two vertices that are adjacent to that
42 | * edge. This is used in the iterated closest edge fitting (ICEF).
43 | *
44 | * Note: The indices are 1-based, so 1 needs to be subtracted before using
45 | * them as mesh indices. An index of 0 as first array element means that
46 | * it's an edge that lies on the mesh boundary, i.e. they are only
47 | * adjacent to one face.
48 | * We should explore a less error-prone way to store this data, but that's
49 | * how it is done in Matlab by the original code.
50 | *
51 | * adjacent_faces.size() is equal to adjacent_vertices.size().
52 | */
53 | struct EdgeTopology
54 | {
55 | std::vector>
56 | adjacent_faces; ///< num_edges x 2 matrix storing faces adjacent to each edge
57 | std::vector>
58 | adjacent_vertices; ///< num_edges x 2 matrix storing vertices adjacent to each edge
59 |
60 | friend class cereal::access;
61 | /**
62 | * Serialises this class using cereal.
63 | *
64 | * @param[in] archive The archive to serialise to (or to serialise from).
65 | */
66 | template
67 | void serialize(Archive& archive)
68 | {
69 | archive(CEREAL_NVP(adjacent_faces), CEREAL_NVP(adjacent_vertices));
70 | };
71 | };
72 |
73 | /**
74 | * Saves a 3DMM edge topology file to a json file.
75 | *
76 | * @param[in] edge_topology A model's edge topology.
77 | * @param[in] filename The file to write.
78 | * @throws std::runtime_error if unable to open the given file for writing.
79 | */
80 | inline void save_edge_topology(EdgeTopology edge_topology, std::string filename)
81 | {
82 | std::ofstream file(filename);
83 | if (!file)
84 | {
85 | throw std::runtime_error("Error creating given file: " + filename);
86 | }
87 | cereal::JSONOutputArchive output_archive(file);
88 | output_archive(cereal::make_nvp("edge_topology", edge_topology));
89 | };
90 |
91 | /**
92 | * Load a 3DMM edge topology file from a json file.
93 | *
94 | * @param[in] filename The file to load the edge topology from.
95 | * @return A struct containing the edge topology.
96 | * @throws std::runtime_error if unable to open the given file for writing.
97 | */
98 | inline EdgeTopology load_edge_topology(std::string filename)
99 | {
100 | EdgeTopology edge_topology;
101 | std::ifstream file(filename);
102 | if (!file)
103 | {
104 | throw std::runtime_error("Error opening file for reading: " + filename);
105 | }
106 | cereal::JSONInputArchive output_archive(file);
107 | output_archive(cereal::make_nvp("edge_topology", edge_topology));
108 |
109 | return edge_topology;
110 | };
111 |
112 | } /* namespace morphablemodel */
113 | } /* namespace eos */
114 |
115 | #endif /* EOS_EDGETOPOLOGY_HPP */
116 |
--------------------------------------------------------------------------------
/include/eos/morphablemodel/ExpressionModel.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/morphablemodel/ExpressionModel.hpp
5 | *
6 | * Copyright 2018 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_EXPRESSION_MODEL_HPP
23 | #define EOS_EXPRESSION_MODEL_HPP
24 |
25 | #include "eos/morphablemodel/PcaModel.hpp"
26 | #include "eos/morphablemodel/Blendshape.hpp"
27 | #include "eos/cpp17/variant.hpp"
28 |
29 | #include "Eigen/Core"
30 |
31 | #include
32 | #include
33 | #include
34 |
35 | namespace eos {
36 | namespace morphablemodel {
37 |
38 | /**
39 | * @brief Type alias to represent an expression model, which can either consist of blendshapes or a PCA model.
40 | *
41 | * Defining a type alias so that we don't have to spell out the type everywhere.
42 | */
43 | using ExpressionModel = cpp17::variant;
44 |
45 | /**
46 | * Returns a sample from an expression model with the given expression coefficients.
47 | *
48 | * The underlying expression model can be both a PcaModel as well as a Blendshapes model.
49 | * If a partial coefficient vector is given, it is filled with zeros up to the end.
50 | *
51 | * @param[in] expression_model The expression model to draw a sample from.
52 | * @param[in] expression_coefficients The coefficients used to generate the expression sample.
53 | * @return A model instance with given coefficients.
54 | */
55 | inline Eigen::VectorXf draw_sample(const ExpressionModel& expression_model,
56 | std::vector expression_coefficients)
57 | {
58 | Eigen::VectorXf expression_sample;
59 | // Get a sample of the expression model, depending on whether it's a PcaModel or Blendshapes:
60 | if (cpp17::holds_alternative(expression_model))
61 | {
62 | const auto& pca_expression_model = cpp17::get(expression_model);
63 | if (expression_coefficients.empty())
64 | {
65 | expression_sample = pca_expression_model.get_mean();
66 | } else
67 | {
68 | expression_sample = pca_expression_model.draw_sample(expression_coefficients);
69 | }
70 | } else if (cpp17::holds_alternative(expression_model))
71 | {
72 | const auto& expression_blendshapes = cpp17::get(expression_model);
73 | assert(expression_blendshapes.size() > 0);
74 | if (expression_coefficients.empty())
75 | {
76 | expression_sample.setZero(expression_blendshapes[0].deformation.rows());
77 | } else
78 | {
79 | expression_sample = to_matrix(expression_blendshapes) *
80 | Eigen::Map(expression_coefficients.data(),
81 | expression_coefficients.size());
82 | }
83 | } else
84 | {
85 | throw std::runtime_error("The given ExpressionModel doesn't contain an expression model in the form "
86 | "of a PcaModel or Blendshapes.");
87 | }
88 | return expression_sample;
89 | };
90 |
91 | } /* namespace morphablemodel */
92 | } /* namespace eos */
93 |
94 | #endif /* EOS_EXPRESSION_MODEL_HPP */
95 |
--------------------------------------------------------------------------------
/include/eos/morphablemodel/coefficients.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/morphablemodel/coefficients.hpp
5 | *
6 | * Copyright 2016 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_COEFFICIENTS_HPP
23 | #define EOS_COEFFICIENTS_HPP
24 |
25 | #include "cereal/cereal.hpp"
26 | #include "cereal/archives/json.hpp"
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | namespace eos {
33 | namespace morphablemodel {
34 |
35 | /**
36 | * Saves coefficients (for example PCA shape coefficients) to a json file.
37 | *
38 | * @param[in] coefficients A vector of coefficients.
39 | * @param[in] filename The file to write.
40 | * @throws std::runtime_error if unable to open the given file for writing.
41 | */
42 | inline void save_coefficients(std::vector coefficients, std::string filename)
43 | {
44 | std::ofstream file(filename);
45 | if (!file)
46 | {
47 | throw std::runtime_error("Error opening file for writing: " + filename);
48 | }
49 | cereal::JSONOutputArchive output_archive(file);
50 | output_archive(cereal::make_nvp("shape_coefficients", coefficients));
51 | };
52 |
53 | /**
54 | * Loads coefficients (for example PCA shape coefficients) from a json file.
55 | *
56 | * @param[in] filename The file to read.
57 | * @return Returns vector of floats.
58 | * @throws std::runtime_error if unable to open the given file for reading.
59 | */
60 | inline std::vector load_coefficients(std::string filename)
61 | {
62 | std::vector coefficients;
63 | std::ifstream file(filename);
64 | if (!file)
65 | {
66 | throw std::runtime_error("Error opening file for reading: " + filename);
67 | }
68 | cereal::JSONInputArchive input_archive(file);
69 | input_archive(cereal::make_nvp("shape_coefficients", coefficients));
70 | return coefficients;
71 | };
72 |
73 | } /* namespace morphablemodel */
74 | } /* namespace eos */
75 |
76 | #endif /* EOS_COEFFICIENTS_HPP */
77 |
--------------------------------------------------------------------------------
/include/eos/morphablemodel/io/eigen_cerealisation.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/morphablemodel/io/eigen_cerealisation.hpp
5 | *
6 | * Copyright 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_EIGEN_MATRIX_BINARY_CEREALISATION_HPP
23 | #define EOS_EIGEN_MATRIX_BINARY_CEREALISATION_HPP
24 |
25 | #include "cereal/cereal.hpp"
26 |
27 | #include "Eigen/Core"
28 |
29 | #include
30 |
31 | /**
32 | * @brief Serialisation of Eigen matrices for the serialisation
33 | * library cereal (http://uscilab.github.io/cereal/index.html).
34 | *
35 | * Contains serialisation for Eigen matrices to binary archives, i.e. matrices like
36 | * \c Eigen::MatrixXf, \c Eigen::Matrix4d, or \c Eigen::Vector3f.
37 | *
38 | * Todo: Add serialisation to and from JSON. Need to find out how to combine the two
39 | * variants of SFINAE that are used.
40 | */
41 | namespace cereal {
42 |
43 | /**
44 | * @brief Serialise an Eigen::Matrix using cereal.
45 | *
46 | * Note: Writes the binary data from Matrix::data(), so not sure what happens if a matrix ever has
47 | * non-contiguous data (if that can ever happen with Eigen).
48 | *
49 | * @param[in] ar The archive to serialise to.
50 | * @param[in] matrix The matrix to serialise.
51 | */
52 | template
53 | inline
54 | typename std::enable_if, Archive>::value, void>::type
55 | save(Archive& ar, const Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& matrix)
56 | {
57 | const std::int32_t rows = static_cast(matrix.rows());
58 | const std::int32_t cols = static_cast(matrix.cols());
59 | ar(rows);
60 | ar(cols);
61 | ar(binary_data(matrix.data(), rows * cols * sizeof(_Scalar)));
62 | };
63 |
64 | /**
65 | * @brief De-serialise an Eigen::Matrix using cereal.
66 | *
67 | * Reads the block of binary data back from a cereal archive into the Eigen::Matrix.
68 | *
69 | * @param[in] ar The archive to deserialise from.
70 | * @param[in] matrix The matrix to deserialise into.
71 | */
72 | template
73 | inline
74 | typename std::enable_if, Archive>::value, void>::type
75 | load(Archive& ar, Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>& matrix)
76 | {
77 | std::int32_t rows;
78 | std::int32_t cols;
79 | ar(rows);
80 | ar(cols);
81 |
82 | matrix.resize(rows, cols);
83 |
84 | ar(binary_data(matrix.data(), static_cast(rows * cols * sizeof(_Scalar))));
85 | };
86 |
87 | } /* namespace cereal */
88 |
89 | #endif /* EOS_EIGEN_MATRIX_BINARY_CEREALISATION_HPP */
90 |
--------------------------------------------------------------------------------
/include/eos/render/ProjectionType.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/ProjectionType.hpp
5 | *
6 | * Copyright 2019, 2020 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RENDER_PROJECTION_TYPE_HPP
23 | #define EOS_RENDER_PROJECTION_TYPE_HPP
24 |
25 | namespace eos {
26 | namespace render {
27 |
28 | /**
29 | * Specifies whether orthographic or perspective projection shall be used.
30 | */
31 | enum class ProjectionType { Orthographic, Perspective };
32 |
33 | } // namespace render
34 | } // namespace eos
35 |
36 | #endif /* EOS_RENDER_PROJECTION_TYPE_HPP */
37 |
--------------------------------------------------------------------------------
/include/eos/render/Texture.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/Texture.hpp
5 | *
6 | * Copyright 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_TEXTURE_HPP
23 | #define EOS_TEXTURE_HPP
24 |
25 | #include "eos/core/Image.hpp"
26 | #include "eos/core/image/resize.hpp"
27 |
28 | #include
29 | #include
30 |
31 | namespace eos {
32 | namespace render {
33 |
34 | // TODO: Should go to detail:: namespace, or texturing/utils or whatever.
35 | inline unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
36 | {
37 | unsigned int mipmapsNum = 1;
38 | unsigned int size = std::max(width, height);
39 |
40 | if (size == 1)
41 | return 1;
42 |
43 | do
44 | {
45 | size >>= 1;
46 | mipmapsNum++;
47 | } while (size != 1);
48 |
49 | return mipmapsNum;
50 | };
51 |
52 | inline bool is_power_of_two(int x)
53 | {
54 | return !(x & (x - 1));
55 | };
56 |
57 | /**
58 | * @brief Represents a texture for rendering.
59 | *
60 | * Represents a texture and mipmap levels for use in the renderer.
61 | * Todo: This whole class needs a major overhaul and documentation.
62 | */
63 | class Texture
64 | {
65 | public:
66 | std::vector
67 | mipmaps; // make Texture a friend class of renderer, then move this to private?
68 | unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level
69 |
70 | // private:
71 | // std::string filename;
72 | unsigned int mipmaps_num;
73 | };
74 |
75 | // throws: ocv exc, runtime_ex
76 | inline Texture create_mipmapped_texture(const eos::core::Image4u& image, unsigned int mipmapsNum = 0)
77 | {
78 | Texture texture;
79 |
80 | texture.mipmaps_num =
81 | (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.width(), image.height()) : mipmapsNum);
82 | /*if (mipmapsNum == 0)
83 | {
84 | uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
85 | this->mipmapsNum = mmn;
86 | } else
87 | {
88 | this->mipmapsNum = mipmapsNum;
89 | }*/
90 |
91 | if (texture.mipmaps_num > 1)
92 | {
93 | if (!is_power_of_two(image.width()) || !is_power_of_two(image.height()))
94 | {
95 | throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
96 | }
97 | }
98 |
99 | int currWidth = image.width();
100 | int currHeight = image.height();
101 | std::vector mipmaps;
102 | for (unsigned int i = 0; i < texture.mipmaps_num; i++)
103 | {
104 | if (i == 0)
105 | {
106 | mipmaps.push_back(image);
107 | } else
108 | {
109 | const eos::core::Image4u currMipMap =
110 | eos::core::image::resize(mipmaps[i - 1], currWidth, currHeight);
111 | mipmaps.push_back(currMipMap);
112 | }
113 |
114 | if (currWidth > 1)
115 | currWidth >>= 1;
116 | if (currHeight > 1)
117 | currHeight >>= 1;
118 | }
119 | texture.mipmaps = mipmaps;
120 | constexpr double ln2 = 0.69314718056;
121 | texture.widthLog = (unsigned char)(std::log(mipmaps[0].width()) / ln2 +
122 | 0.0001f); // std::epsilon or something? or why 0.0001f here?
123 | texture.heightLog = (unsigned char)(std::log(mipmaps[0].height()) / ln2 +
124 | 0.0001f); // Changed std::logf to std::log because it doesnt compile
125 | // in linux (gcc 4.8). CHECK THAT
126 | return texture;
127 | };
128 |
129 | } /* namespace render */
130 | } /* namespace eos */
131 |
132 | #endif /* EOS_TEXTURE_HPP */
133 |
--------------------------------------------------------------------------------
/include/eos/render/VertexShader.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/VertexShader.hpp
5 | *
6 | * Copyright 2017, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_VERTEX_SHADER_HPP
23 | #define EOS_VERTEX_SHADER_HPP
24 |
25 | #include "Eigen/Core"
26 |
27 | namespace eos {
28 | namespace render {
29 |
30 | /**
31 | * @brief A simple vertex shader that projects the vertex and returns the vertex in clip-space coordinates.
32 | */
33 | class VertexShader
34 | {
35 | public:
36 | /**
37 | * @brief Projects the given vertex into clip-space and returns it.
38 | *
39 | * @param[in] vertex The vertex to project.
40 | * @param[in] model_view_matrix The model-view matrix.
41 | * @param[in] projection_matrix The projection matrix.
42 | * @tparam VertexType Vertex type.
43 | * @tparam MatrixType Matrix type.
44 | * @return Vertex projected to clip space.
45 | */
46 | template
47 | Eigen::Vector4 operator()(const Eigen::Vector4& vertex,
48 | const Eigen::Matrix4& model_view_matrix,
49 | const Eigen::Matrix4& projection_matrix)
50 | {
51 | return projection_matrix * model_view_matrix * vertex;
52 | };
53 | };
54 |
55 | } /* namespace render */
56 | } /* namespace eos */
57 |
58 | #endif /* EOS_VERTEX_SHADER_HPP */
59 |
--------------------------------------------------------------------------------
/include/eos/render/detail/RayDirection.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/detail/RayDirection.hpp
5 | *
6 | * Copyright 2019, 2020 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RENDER_DETAIL_RAY_DIRECTION_HPP
23 | #define EOS_RENDER_DETAIL_RAY_DIRECTION_HPP
24 |
25 | namespace eos {
26 | namespace render {
27 | namespace detail {
28 |
29 | /**
30 | * Specifies whether to cast rays parallel or towards the origin while computing vertex/mesh self-occlusion.
31 | *
32 | * Note: This is best as an internal-only type I think. But it's needed in the public interface of the
33 | * functions in vertex_visibility.hpp - so perhaps think about that.
34 | */
35 | enum class RayDirection { Parallel, TowardsOrigin };
36 |
37 | } // namespace detail
38 | } // namespace render
39 | } // namespace eos
40 |
41 | #endif /* EOS_RENDER_DETAIL_RAY_DIRECTION_HPP */
42 |
--------------------------------------------------------------------------------
/include/eos/render/detail/TriangleToRasterize.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/detail/TriangleToRasterize.hpp
5 | *
6 | * Copyright 2017 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_TRIANGLE_TO_RASTERIZE_HPP
23 | #define EOS_TRIANGLE_TO_RASTERIZE_HPP
24 |
25 | #include "eos/render/detail/Vertex.hpp"
26 | #include "eos/render/detail/plane.hpp"
27 |
28 | /**
29 | * The detail namespace contains implementations of internal functions, not part of the API we expose and not
30 | * meant to be used by a user.
31 | */
32 | namespace eos {
33 | namespace render {
34 | namespace detail {
35 |
36 | /**
37 | * A representation for a triangle that is to be rasterised.
38 | * Stores the enclosing bounding box of the triangle that is
39 | * calculated during rendering and used during rasterisation.
40 | *
41 | * Used in render_affine and render.
42 | */
43 | struct TriangleToRasterize
44 | {
45 | Vertex v0, v1, v2;
46 | int min_x;
47 | int max_x;
48 | int min_y;
49 | int max_y;
50 | // Everything below is only used in the "normal" renderer, but not
51 | // in render_affine.
52 | double one_over_z0;
53 | double one_over_z1;
54 | double one_over_z2;
55 | // double one_over_v0ToLine12;
56 | // double one_over_v1ToLine20;
57 | // double one_over_v2ToLine01;
58 | plane alphaPlane;
59 | plane betaPlane;
60 | plane gammaPlane;
61 | double one_over_alpha_c; // those are only used for texturing -> float
62 | double one_over_beta_c;
63 | double one_over_gamma_c;
64 | float alpha_ffx;
65 | float beta_ffx;
66 | float gamma_ffx;
67 | float alpha_ffy;
68 | float beta_ffy;
69 | float gamma_ffy;
70 | };
71 |
72 | } /* namespace detail */
73 | } /* namespace render */
74 | } /* namespace eos */
75 |
76 | #endif /* EOS_TRIANGLE_TO_RASTERIZE_HPP */
77 |
--------------------------------------------------------------------------------
/include/eos/render/detail/Vertex.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/detail/Vertex.hpp
5 | *
6 | * Copyright 2017, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_VERTEX_HPP
23 | #define EOS_VERTEX_HPP
24 |
25 | #include "Eigen/Core"
26 |
27 | /**
28 | * The detail namespace contains implementations of internal functions, not part of the API we expose and not
29 | * meant to be used by a user.
30 | */
31 | namespace eos {
32 | namespace render {
33 | namespace detail {
34 |
35 | /**
36 | * @brief A representation for a vertex during rendering, used internally.
37 | *
38 | * It's used to build the vertices that will be rendered, and new vertices that are generated by the renderer
39 | * (during clipping).
40 | * I should check at some point that no unnecessary copies of the vertex data is created in some places, but I
41 | * think it's pretty much fine.
42 | *
43 | * FragmentShader and SoftwareRenderer use this.
44 | *
45 | * This is the same as the one in the current render_detail.hpp, except that this is fully templated.
46 | *
47 | */
48 | template
49 | struct Vertex
50 | {
51 | Eigen::Vector4 position; // XYZW
52 | Eigen::Vector3 color; // RGB order
53 | Eigen::Vector2 texcoords; // UV
54 | };
55 |
56 | } /* namespace detail */
57 | } /* namespace render */
58 | } /* namespace eos */
59 |
60 | #endif /* EOS_VERTEX_HPP */
61 |
--------------------------------------------------------------------------------
/include/eos/render/detail/plane.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/detail/plane.hpp
5 | *
6 | * Copyright 2017, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RENDER_DETAIL_PLANE_HPP
23 | #define EOS_RENDER_DETAIL_PLANE_HPP
24 |
25 | #include "Eigen/Core"
26 |
27 | #include
28 |
29 | /**
30 | * The detail namespace contains implementations of internal functions, not part of the API we expose and not
31 | * meant to be used by a user.
32 | */
33 | namespace eos {
34 | namespace render {
35 | namespace detail {
36 |
37 | class plane
38 | {
39 | public:
40 | plane() {}
41 |
42 | plane(float a, float b, float c, float d)
43 | {
44 | this->a = a;
45 | this->b = b;
46 | this->c = c;
47 | this->d = d;
48 | }
49 |
50 | plane(const Eigen::Vector3f& normal, float d = 0.0f)
51 | {
52 | this->a = normal[0];
53 | this->b = normal[1];
54 | this->c = normal[2];
55 | this->d = d;
56 | }
57 |
58 | plane(const Eigen::Vector3f& point, const Eigen::Vector3f& normal)
59 | {
60 | a = normal[0];
61 | b = normal[1];
62 | c = normal[2];
63 | d = -point.dot(normal);
64 | }
65 |
66 | template
67 | plane(const Eigen::Vector3& point1, const Eigen::Vector3& point2, const Eigen::Vector3& point3)
68 | {
69 | const Eigen::Vector3 v1 = point2 - point1;
70 | const Eigen::Vector3 v2 = point3 - point1;
71 | Eigen::Vector3 normal = v1.cross(v2);
72 |
73 | normal = normal.normalized();
74 |
75 | a = normal[0];
76 | b = normal[1];
77 | c = normal[2];
78 | d = -point1.dot(normal);
79 | }
80 |
81 | void normalize()
82 | {
83 | const float length = std::sqrt(a * a + b * b + c * c);
84 |
85 | a /= length;
86 | b /= length;
87 | c /= length;
88 | }
89 |
90 | float getSignedDistanceFromPoint(const Eigen::Vector3f& point) const
91 | {
92 | return a * point[0] + b * point[1] + c * point[2] + d;
93 | }
94 |
95 | float getSignedDistanceFromPoint(const Eigen::Vector4f& point) const
96 | {
97 | return a * point[0] + b * point[1] + c * point[2] + d;
98 | }
99 |
100 | public:
101 | float a, b, c;
102 | float d;
103 | };
104 |
105 | } /* namespace detail */
106 | } /* namespace render */
107 | } /* namespace eos */
108 |
109 | #endif /* EOS_RENDER_DETAIL_PLANE_HPP */
110 |
--------------------------------------------------------------------------------
/include/eos/render/draw_utils.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/draw_utils.hpp
5 | *
6 | * Copyright 2017-2019, 2023 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RENDER_DRAW_UTILS_HPP
23 | #define EOS_RENDER_DRAW_UTILS_HPP
24 |
25 | #include "eos/core/Mesh.hpp"
26 | #include "eos/render/matrix_projection.hpp"
27 | #include "eos/render/detail/utils.hpp"
28 |
29 | #include "Eigen/Core"
30 |
31 | namespace eos {
32 | namespace render {
33 |
34 | /**
35 | * Draws a line using the Bresenham algorithm.
36 | *
37 | * From: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
38 | * I also tried this: https://www.thecrazyprogrammer.com/2017/01/bresenhams-line-drawing-algorithm-c-c.html
39 | * which looks awesome, but it drew weird lines.
40 | *
41 | * @param[in] image An image to draw into.
42 | * @param[in] x0 X coordinate of the start point.
43 | * @param[in] y0 Y coordinate of the start point.
44 | * @param[in] x1 X coordinate of the start point.
45 | * @param[in] y1 Y coordinate of the end point.
46 | * @param[in] color RGB colour of the line to be drawn.
47 | */
48 |
49 | inline void draw_line(core::Image3u& image, float x0, float y0, float x1, float y1, Eigen::Vector3f color)
50 | {
51 | auto plot_line_low = [&image, &color](float x0, float y0, float x1, float y1) {
52 | float dx = x1 - x0;
53 | float dy = y1 - y0;
54 | int yi = 1;
55 | if (dy < 0)
56 | {
57 | yi = -1;
58 | dy = -dy;
59 | }
60 |
61 | float D = 2 * dy - dx;
62 | float y = y0;
63 |
64 | for (int x = x0; x <= x1; ++x) // for x from x0 to x1
65 | {
66 | image(y, x) = {color[0], color[1], color[2]}; // plot(x, y);
67 | if (D > 0)
68 | {
69 | y = y + yi;
70 | D = D - 2 * dx;
71 | }
72 | D = D + 2 * dy;
73 | }
74 | };
75 |
76 | auto plot_line_high = [&image, &color](float x0, float y0, float x1, float y1) {
77 | float dx = x1 - x0;
78 | float dy = y1 - y0;
79 | int xi = 1;
80 | if (dx < 0)
81 | {
82 | xi = -1;
83 | dx = -dx;
84 | }
85 |
86 | float D = 2 * dx - dy;
87 | float x = x0;
88 |
89 | for (int y = y0; y <= y1; ++y) // for y from y0 to y1
90 | {
91 | image(y, x) = {color[0], color[1], color[2]}; // plot(x, y);
92 | if (D > 0)
93 | {
94 | x = x + xi;
95 | D = D - 2 * dy;
96 | }
97 | D = D + 2 * dx;
98 | }
99 | };
100 |
101 | if (abs(y1 - y0) < abs(x1 - x0))
102 | {
103 | if (x0 > x1)
104 | {
105 | plot_line_low(x1, y1, x0, y0);
106 | } else
107 | {
108 | plot_line_low(x0, y0, x1, y1);
109 | }
110 | } else
111 | {
112 | if (y0 > y1)
113 | {
114 | plot_line_high(x1, y1, x0, y0);
115 | } else
116 | {
117 | plot_line_high(x0, y0, x1, y1);
118 | }
119 | }
120 | };
121 |
122 | /**
123 | * Draws the given mesh as wireframe into the image.
124 | *
125 | * It does backface culling, i.e. draws only vertices in CCW order.
126 | *
127 | * @param[in] image An image to draw into.
128 | * @param[in] mesh The mesh to draw.
129 | * @param[in] modelview Model-view matrix to draw the mesh.
130 | * @param[in] projection Projection matrix to draw the mesh.
131 | * @param[in] viewport Viewport to draw the mesh.
132 | * @param[in] color Colour of the mesh to be drawn, in RGB.
133 | */
134 | inline void draw_wireframe(core::Image3u& image, const core::Mesh& mesh, Eigen::Matrix4f modelview,
135 | Eigen::Matrix4f projection, Eigen::Vector4f viewport,
136 | Eigen::Vector3f color = Eigen::Vector3f(0, 255, 0))
137 | {
138 | for (const auto& triangle : mesh.tvi)
139 | {
140 | const auto p1 = project(mesh.vertices[triangle[0]], modelview, projection, viewport);
141 | const auto p2 = project(mesh.vertices[triangle[1]], modelview, projection, viewport);
142 | const auto p3 = project(mesh.vertices[triangle[2]], modelview, projection, viewport);
143 | if (render::detail::are_vertices_ccw_in_screen_space(p1.head<2>(), p2.head<2>(), p3.head<2>()))
144 | {
145 | draw_line(image, p1.x(), p1.y(), p2.x(), p2.y(), color);
146 | draw_line(image, p2.x(), p2.y(), p3.x(), p3.y(), color);
147 | draw_line(image, p3.x(), p3.y(), p1.x(), p1.y(), color);
148 | }
149 | }
150 | };
151 |
152 | } /* namespace render */
153 | } /* namespace eos */
154 |
155 | #endif /* EOS_RENDER_DRAW_UTILS_HPP */
156 |
--------------------------------------------------------------------------------
/include/eos/render/normals.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * eos - A 3D Morphable Model fitting library written in modern C++11/14.
3 | *
4 | * File: include/eos/render/normals.hpp
5 | *
6 | * Copyright 2014-2019 Patrik Huber
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | #pragma once
21 |
22 | #ifndef EOS_RENDER_NORMALS_HPP
23 | #define EOS_RENDER_NORMALS_HPP
24 |
25 | #include "Eigen/Core"
26 |
27 | #include
28 |
29 | namespace eos {
30 | namespace render {
31 |
32 | /**
33 | * Computes the normal of a face (triangle), i.e. the per-face normal. Returned normal will be unit length.
34 | *
35 | * Assumes the triangle is given in CCW order, i.e. vertices in counterclockwise order on the screen are
36 | * front-facing.
37 | *
38 | * @param[in] v0 First vertex.
39 | * @param[in] v1 Second vertex.
40 | * @param[in] v2 Third vertex.
41 | * @return The unit-length normal of the given triangle.
42 | */
43 | inline Eigen::Vector3f compute_face_normal(const Eigen::Vector3f& v0, const Eigen::Vector3f& v1,
44 | const Eigen::Vector3f& v2)
45 | {
46 | Eigen::Vector3f n = (v1 - v0).cross(v2 - v0); // v0-to-v1 x v0-to-v2
47 | return n.normalized();
48 | };
49 |
50 | /**
51 | * Computes the normal of a face (triangle), i.e. the per-face normal. Returned normal will be unit length.
52 | *
53 | * Assumes the triangle is given in CCW order, i.e. vertices in counterclockwise order on the screen are
54 | * front-facing.
55 | *
56 | * @param[in] v0 First vertex.
57 | * @param[in] v1 Second vertex.
58 | * @param[in] v2 Third vertex.
59 | * @return The unit-length normal of the given triangle.
60 | */
61 | inline Eigen::Vector3f compute_face_normal(const Eigen::Vector4f& v0, const Eigen::Vector4f& v1,
62 | const Eigen::Vector4f& v2)
63 | {
64 | Eigen::Vector4f n = (v1 - v0).cross3(v2 - v0); // v0-to-v1 x v0-to-v2
65 | return n.head<3>().normalized();
66 | };
67 |
68 | /**
69 | * Computes the per-face (per-triangle) normals of all triangles of the given mesh. Returned normals will be unit length.
70 | *
71 | * Assumes triangles are given in CCW order, i.e. vertices in counterclockwise order on the screen are front-facing.
72 | *
73 | * @param[in] vertices A list of vertices.
74 | * @param[in] triangle_vertex_indices Triangle list for the given vertices.
75 | * @return The unit-length per-face normals.
76 | */
77 | inline std::vector
78 | compute_face_normals(const std::vector& vertices,
79 | const std::vector>& triangle_vertex_indices)
80 | {
81 | std::vector face_normals;
82 | for (const auto& tvi : triangle_vertex_indices)
83 | {
84 | const auto face_normal = compute_face_normal(vertices[tvi[0]], vertices[tvi[1]], vertices[tvi[2]]);
85 | face_normals.push_back(face_normal);
86 | }
87 | return face_normals;
88 | };
89 |
90 | /**
91 | * Computes the per-vertex normals of all vertices of the given mesh. Returned normals will be unit length.
92 | *
93 | * Assumes triangles are given in CCW order, i.e. vertices in counterclockwise order on the screen are
94 | * front-facing.
95 | *
96 | * @param[in] vertices A list of vertices.
97 | * @param[in] triangle_vertex_indices Triangle list for the given vertices.
98 | * @param[in] face_normals Per-face normals for all triangles.
99 | * @return The unit-length per-vertex normals.
100 | */
101 | inline std::vector
102 | compute_vertex_normals(const std::vector& vertices,
103 | const std::vector