├── .gitmodules ├── 1_new.obj ├── 2_new.obj ├── CMakeLists.txt ├── LICENSE ├── README.md ├── get_dr.cpp ├── test.py ├── util_3drotation_log_exp.cpp └── util_3drotation_log_exp.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pybind11"] 2 | path = pybind11 3 | url = https://github.com/pybind/pybind11.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | project(my_project) 3 | 4 | # force a specific python version 5 | # set(PYTHON_LIBRARIES "/usr/lib/x86_64-linux-gnu/libpython2.7.a") 6 | # set(PYTHON_INCLUDE_DIR "/usr/include/python2.7") 7 | 8 | find_package(PythonInterp REQUIRED) 9 | find_package(PythonLibs REQUIRED) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -w -shared -std=c++11") 12 | 13 | add_subdirectory(pybind11) 14 | 15 | pybind11_add_module(get_dr get_dr.cpp util_3drotation_log_exp.h util_3drotation_log_exp.cpp) 16 | 17 | 18 | INCLUDE_DIRECTORIES("/usr/include/eigen3") 19 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}) 20 | 21 | link_directories("/usr/local/lib") 22 | 23 | target_link_libraries(get_dr PRIVATE -lOpenMeshCore -lOpenMeshTools) 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Wooqy 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # get_dr_py_API 2 | This package is available for using pybind11 to create get_dr python API. 3 | 4 | Deformation Representation Feature (DR Feature) is a kind of fundamental and stable tool in geometry learning area. For more background knowledges and properties of DR feature, we suggest these papers in **Citation** section for further reading. 5 | 6 | # Dependencies 7 | This package depends on OpenMesh and Eigen libraries. To run the dr computation code, please make sure you have Eigen and OpenMesh precompiled on your computer and modificate the include path in CMakeList.txt file. 8 | 9 | # Usage 10 | We recommend to use cmake to compile this package and a python API will be automatically created to compute DR features. 11 | ``` 12 | git clone --recursive https://github.com/QianyiWu/get_dr_py.git 13 | cd get_dr_py 14 | ``` 15 | 16 | After obtaining this repository, run the following code in the repository path: 17 | ``` 18 | mkdir build 19 | cd build 20 | cmake .. 21 | make -j4 22 | ``` 23 | You will then get a .so file. 24 | The test.py with *1_new.obj* and *2_new.obj* could be used for testing. 25 | 26 | # Environment Tests 27 | Currently we have fully tested this package on Ubuntu 16.04 LTS environment. Windows and MacOS are not ensured working. 28 | 29 | # Citation 30 | Please cite the following papers if it helps your research: 31 | 32 | Disentangled Representation Learning for 3D Face Shape 33 | 34 | @inproceedings{Jiang2019Disentangled 35 | title={Disentangled Representation Learning for 3D Face Shape}, 36 | author={Jiang, Zi-Hang and Wu, Qianyi and Chen, Keyu and Zhang, Juyong} 37 | booktitle={IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 38 | year={2019}, 39 | } 40 | 41 | Sparse Data Driven Mesh Deformation 42 | 43 | @article{Gao2017SparseDD, 44 | title={Sparse Data Driven Mesh Deformation}, 45 | author={Lin Gao and Yu-Kun Lai and Jie Yang and Ling-Xiao Zhang and Leif Kobbelt and Shihong Xia}, 46 | journal={CoRR}, 47 | year={2017}, 48 | volume={abs/1709.01250} 49 | } 50 | 51 | Alive Caricature from 2D to 3D 52 | 53 | @inproceedings{wu2018alive, 54 | title={Alive Caricature from 2D to 3D}, 55 | author={Wu, Qianyi and Zhang, Juyong and Lai, Yu-Kun and Zheng, Jianmin and Cai, Jianfei}, 56 | booktitle={IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 57 | year={2018}, 58 | } 59 | -------------------------------------------------------------------------------- /get_dr.cpp: -------------------------------------------------------------------------------- 1 | #include "util_3drotation_log_exp.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include ; 11 | 12 | namespace py=pybind11; 13 | 14 | struct TriTraits : public OpenMesh::DefaultTraits 15 | { 16 | /// Use double precision points 17 | typedef OpenMesh::Vec3d Point; 18 | /// Use double precision Normals 19 | typedef OpenMesh::Vec3d Normal; 20 | /// Use double precision TexCood2D 21 | typedef OpenMesh::Vec2d TexCoord2D; 22 | 23 | /// Use RGBA Color 24 | typedef OpenMesh::Vec4f Color; 25 | 26 | /// Status 27 | VertexAttributes(OpenMesh::Attributes::Status); 28 | FaceAttributes(OpenMesh::Attributes::Status); 29 | EdgeAttributes(OpenMesh::Attributes::Status); 30 | 31 | // VertexAttributes( 32 | // OpenMesh::Attributes:: 33 | // ) 34 | }; 35 | 36 | /// Simple Name for Mesh 37 | typedef OpenMesh::TriMesh_ArrayKernelT TriMesh; 38 | 39 | class DR_feature{ 40 | public: 41 | DR_feature(); 42 | void read_ref_mesh(std::string ref_mesh_name); 43 | void read_defor_mesh(std::string defor_mesh_name); 44 | std::vector get_feature(std::string ref_mesh_name, std::string defor_mesh_name); 45 | 46 | 47 | private: 48 | TriMesh ref_mesh_; 49 | TriMesh defor_mesh_; 50 | 51 | OpenMesh::EPropHandleT LB_weights; 52 | OpenMesh::VPropHandleT T_matrixs; 53 | private: 54 | void compute_ref_LB_weight(); 55 | void compute_Ti(TriMesh::VertexHandle v_it,TriMesh::VertexHandle v_to_it); 56 | }; 57 | 58 | DR_feature::DR_feature(){ 59 | ref_mesh_.add_property(LB_weights); 60 | defor_mesh_.add_property(T_matrixs); 61 | } 62 | 63 | void DR_feature::read_ref_mesh(std::string ref_mesh_name){ 64 | if(!OpenMesh::IO::read_mesh(ref_mesh_, ref_mesh_name)){ 65 | std::cout<<"read_ref_mesh_ : read file wrong!!!"<tolerance) 243 | T = L*RI.inverse(); 244 | else 245 | { 246 | Eigen::JacobiSVD svd(RI, Eigen::ComputeThinU | Eigen::ComputeThinV); 247 | Eigen::Matrix3d U,V; 248 | U=svd.matrixU(); 249 | V=svd.matrixV(); 250 | Eigen::Matrix3d S_inv(svd.singularValues().asDiagonal()); 251 | for(int i=0;i<3;i++) 252 | { 253 | if(fabs(S_inv(i,i))>tolerance) 254 | S_inv(i,i)=1.0/S_inv(i,i); 255 | else 256 | S_inv(i,i)=0.0; 257 | } 258 | T = L*V*S_inv*U.transpose(); 259 | } 260 | defor_mesh_.property(T_matrixs,v_it) = T; 261 | } 262 | 263 | 264 | std::vector DR_feature::get_feature(std::string ref_mesh_name, std::string defor_mesh_name){ 265 | read_ref_mesh(ref_mesh_name); 266 | read_defor_mesh(defor_mesh_name); 267 | 268 | std::vector dr_feature; 269 | 270 | TriMesh::VertexIter v_it; 271 | for(v_it=defor_mesh_.vertices_begin(); v_it!=defor_mesh_.vertices_end(); v_it++) 272 | { 273 | Eigen::Matrix3d T = defor_mesh_.property(T_matrixs,*v_it); 274 | Eigen::JacobiSVD svd(T, Eigen::ComputeThinU | Eigen::ComputeThinV); 275 | Eigen::Matrix3d U,V; 276 | U=svd.matrixU(); 277 | V=svd.matrixV(); 278 | Eigen::Matrix3d S(svd.singularValues().asDiagonal()); 279 | Eigen::Matrix3d Temp=Eigen::Matrix3d::Identity(); 280 | Temp(2,2) = (U*V.transpose()).determinant(); 281 | Eigen::Matrix3d R=U*Temp*V.transpose(); 282 | Eigen::Matrix3d Scale = V*Temp*S*V.transpose(); 283 | Eigen::Matrix3d logR = rotation_log_exp::log(R); 284 | 285 | dr_feature.push_back(Scale(0, 0)); 286 | dr_feature.push_back(Scale(0, 1)); 287 | dr_feature.push_back(Scale(0, 2)); 288 | dr_feature.push_back(Scale(1, 1)); 289 | dr_feature.push_back(Scale(1, 2)); 290 | dr_feature.push_back(Scale(2, 2)); 291 | dr_feature.push_back(logR(0, 1)); 292 | dr_feature.push_back(logR(0, 2)); 293 | dr_feature.push_back(logR(1, 2)); 294 | } 295 | return dr_feature; 296 | } 297 | 298 | py::array_t get_dr(std::string ref_mesh_name, std::string defor_mesh_name){ 299 | DR_feature feature; 300 | std::vector temp = feature.get_feature(ref_mesh_name, defor_mesh_name); 301 | 302 | auto result = py::array_t(temp.size()); 303 | auto result_buffer = result.request(); 304 | double *result_ptr = (double *)result_buffer.ptr; 305 | 306 | std::memcpy(result_ptr, temp.data(), temp.size()*sizeof(double)); 307 | 308 | return result; 309 | 310 | } 311 | 312 | PYBIND11_MODULE(get_dr, m){ 313 | m.doc() = "get dr"; 314 | m.def("get_dr", &get_dr, "get_dr"); 315 | } -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('build') 3 | from get_dr import * 4 | import numpy as np 5 | import time 6 | print(get_dr('1_new.obj', '2_new.obj')) 7 | -------------------------------------------------------------------------------- /util_3drotation_log_exp.cpp: -------------------------------------------------------------------------------- 1 | #include "util_3drotation_log_exp.h" 2 | #include 3 | 4 | Eigen::Matrix3d rotation_log_exp::exp(double angle, const Eigen::Vector3d &axis) 5 | { 6 | if(fabs(axis.norm()-1.0)>log_exp_tolerance) 7 | { 8 | std::cout<<"rotation_log_exp::exp1::input axis isn't an unit direction!!!"<log_exp_tolerance) 24 | { 25 | std::cout<<"rotation_log_exp::exp2::input matrix isn't skew-matrix!!!"<log_exp_tolerance) 36 | { 37 | std::cout<<"rotation_log_exp::exp3::input matrix isn't skew-matrix!!!"<log_exp_tolerance) 74 | { 75 | std::cout<<"rotation_log_exp::log::rotation_matrix isn't an orthogonal matrix!!!"<1.0) 80 | { 81 | if(fabs(csin-1.0)>log_exp_tolerance&&fabs(csin+1.0)>log_exp_tolerance) 82 | { 83 | std::cout<<"rotation_log_exp::log::csin "<0.0) k2 = sqrt(B(1,1)); 103 | else k2 = -sqrt(B(1,1)); 104 | if(k1*B(0,2)>0.0) k3 = sqrt(B(2,2)); 105 | else k3 = -sqrt(B(2,2)); 106 | axis(0)=k1;axis(1)=k2;axis(2)=k3; 107 | return ; 108 | } 109 | 110 | //tangle has 2 possible, 0~pi or pi~2pi 111 | Eigen::Vector3d taxis; 112 | taxis(0)=rotation_matrix(2,1)-rotation_matrix(1,2); 113 | taxis(1)=rotation_matrix(0,2)-rotation_matrix(2,0); 114 | taxis(2)=rotation_matrix(1,0)-rotation_matrix(0,1); 115 | Eigen::Vector3d t_axis=taxis/(2.0*sin(tangle)); 116 | double sinv = sin(tangle); 117 | double r01 = (1.0-csin)*t_axis(0)*t_axis(1)-t_axis(2)*sinv; 118 | double r02 = (1.0-csin)*t_axis(0)*t_axis(2)+t_axis(1)*sinv; 119 | double r10 = (1.0-csin)*t_axis(0)*t_axis(1)+t_axis(2)*sinv; 120 | double r12 = (1.0-csin)*t_axis(1)*t_axis(2)-t_axis(0)*sinv; 121 | double r20 = (1.0-csin)*t_axis(0)*t_axis(2)-t_axis(1)*sinv; 122 | double r21 = (1.0-csin)*t_axis(1)*t_axis(2)+t_axis(0)*sinv; 123 | double check = (rotation_matrix(0,1)-r01)*(rotation_matrix(0,1)-r01)+(rotation_matrix(0,2)-r02)*(rotation_matrix(0,2)-r02) 124 | +(rotation_matrix(1,0)-r10)*(rotation_matrix(1,0)-r10)+(rotation_matrix(1,2)-r12)*(rotation_matrix(1,2)-r12) 125 | +(rotation_matrix(2,0)-r20)*(rotation_matrix(2,0)-r20)+(rotation_matrix(2,1)-r21)*(rotation_matrix(2,1)-r21); 126 | 127 | if(checklog_exp_tolerance) 149 | std::cout<<"rotation_log_exp::log::computation is wrong!!!"<log_exp_tolerance) 191 | { 192 | std::cout<<"rotation_log_exp::exp1::input axis isn't an unit direction!!!"< 4 | 5 | 6 | //rotation matrix log and exp operation, reference Axis–angle representation on wiki 7 | namespace rotation_log_exp 8 | { 9 | static double log_exp_tolerance = 1.0e-6; 10 | Eigen::Matrix3d exp(const Eigen::Vector3d &angle_axis); 11 | Eigen::Matrix3d exp(double angle,const Eigen::Vector3d &axis); 12 | Eigen::Matrix3d exp(double angle,const Eigen::Matrix3d &cross_axis); 13 | Eigen::Matrix3d exp(const Eigen::Matrix3d &angle_cross_axis); 14 | 15 | void log(const Eigen::Matrix3d &rotation_matrix,double &angle,Eigen::Vector3d &axis); 16 | void log(const Eigen::Matrix3d &rotation_matrix,double &angle,Eigen::Matrix3d &cross_axis); 17 | Eigen::Matrix3d log(const Eigen::Matrix3d &rotation_matrix); 18 | 19 | Eigen::Matrix3d rotation_so3(const Eigen::Vector3d &angle_axis); 20 | Eigen::Matrix3d rotation_so3(double angle,const Eigen::Vector3d &axis); 21 | 22 | void so3_to_angle_axis(const Eigen::Matrix3d &r, double &angle, Eigen::Vector3d &axis); 23 | } 24 | 25 | 26 | #endif // ROTATION_H 27 | --------------------------------------------------------------------------------