-
Notifications
You must be signed in to change notification settings - Fork 13
/
multilinearmodelbuilder.h
135 lines (107 loc) · 3.81 KB
/
multilinearmodelbuilder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef MULTILINEARMODELBUILDER_H
#define MULTILINEARMODELBUILDER_H
#include "blendshape_data.h"
#include "tensor.hpp"
#include "utils.hpp"
class MultilinearModelBuilder {
public:
MultilinearModelBuilder(){}
void build(){
cout << "building multilinear model ..." << endl;
vector<BlendShape> shapes;
const int nShapes = 150; // 150 identity
const int nExprs = 47; // 46 expressions + 1 neutral
const int nVerts = 11510; // 11510 vertices for each mesh
const string path = "/home/phg/Data/FaceWarehouse_Data_0/";
const string foldername = "Tester_";
const string bsfolder = "Blendshape";
const string filename = "shape.bs";
shapes.resize(nShapes);
for(int i=0;i<nShapes;i++) {
stringstream ss;
ss << path << foldername << (i+1) << "/" << bsfolder + "/" + filename;
shapes[i].read(ss.str());
}
int nCoords = nVerts * 3;
// create an order 3 tensor for the blend shapes
Tensor3 t(nShapes, nExprs, nCoords);
// fill in the data
for(int i=0;i<shapes.size();i++) {
const BlendShape& bsi = shapes[i];
for(int j=0;j<bsi.expressionCount();j++) {
const BlendShape::shape_t& bsij = bsi.expression(j);
for(int k=0, cidx = 0;k<nVerts;k++, cidx+=3) {
const BlendShape::vert_t& v = bsij[k];
t(i, j, cidx) = v.x;
t(i, j, cidx+1) = v.y;
t(i, j, cidx+2) = v.z;
}
}
}
cout << "Tensor assembled." << endl;
// create deformation map
Tensor2 distmap(nShapes, nVerts);
for(int i=0;i<shapes.size();i++) {
const BlendShape::shape_t& bsi0 = shapes[i].expression(0);
const BlendShape& bsi = shapes[i];
for(int j=1;j<bsi.expressionCount();j++) {
const BlendShape::shape_t& bsij = bsi.expression(j);
for(int k=0, cidx = 0;k<nVerts;k++, cidx+=3) {
const BlendShape::vert_t& v0 = bsi0[k];
const BlendShape::vert_t& v = bsij[k];
float dx = v.x - v0.x, dy = v.y - v0.y, dz = v.z - v0.z;
distmap(i, k) += sqrt(dx*dx+dy*dy+dz*dz);
}
}
}
distmap.Write("distmap.txt");
// perform svd to get core tensor
cout << "Performing SVD on the blendshapes ..." << endl;
int ms[2] = {0, 1}; // only the first two modes
int ds[2] = {50, 25}; // pick 50 for identity and 25 for expression
vector<int> modes(ms, ms+2);
vector<int> dims(ds, ds+2);
auto comp2 = t.svd(modes, dims);
cout << "SVD done." << endl;
auto tcore = std::get<0>(comp2);
auto tus = std::get<1>(comp2);
cout << "writing core tensor ..." << endl;
tcore.Write("blendshape_core.tensor");
cout << "writing U tensors ..." << endl;
for(int i=0;i<tus.size();i++) {
tus[i].Write("blendshape_u_" + std::to_string(ms[i]) + ".tensor");
}
cout << "Validation begins ..." << endl;
Tensor3 tin;
tin.Read("blendshape_core.tensor");
cout << "Core tensor dimensions = "
<< tin.layers() << "x"
<< tin.rows() << "x"
<< tin.cols() << endl;
double maxDiffio = 0;
for(int i=0;i<tin.layers();i++) {
for(int j=0;j<tin.rows();j++) {
for(int k=0;k<tin.cols();k++) {
maxDiffio = std::max(fabs(tin(i, j, k) - tcore(i, j, k)), maxDiffio);
}
}
}
cout << "Max difference io = " << maxDiffio << endl;
tin = tin.ModeProduct(tus[0], 0).ModeProduct(tus[1], 1);
cout << "Dimensions = "
<< tin.layers() << "x"
<< tin.rows() << "x"
<< tin.cols() << endl;
double maxDiff = 0;
for(int i=0;i<tin.layers();i++) {
for(int j=0;j<tin.rows();j++) {
for(int k=0;k<tin.cols();k++) {
maxDiff = std::max(fabs(tin(i, j, k) - t(i, j, k)), maxDiff);
}
}
}
cout << "Max difference = " << maxDiff << endl;
cout << "done" << endl;
}
};
#endif // MULTILINEARMODELBUILDER_H