├── .gitignore ├── README.md ├── assets ├── avg_v1.0.png ├── avg_v1.1.png └── avg_v2.0.gif ├── bfm_visual_tool.sln └── bfm_visual_tool ├── MainWindow.cpp ├── MainWindow.h ├── MainWindow.qrc ├── MainWindow.ui ├── OpenGLWidget.cpp ├── OpenGLWidget.h ├── Resources └── bfm_tool.ico ├── bfm.cpp ├── bfm.h ├── bfm_tool.rc ├── bfm_visual_tool.vcxproj ├── bfm_visual_tool.vcxproj.filters ├── bfm_visual_tool.vcxproj.user ├── constant.h ├── data.h ├── inputs-2017.txt ├── inputs.txt ├── main.cpp ├── random.cpp ├── random.h └── vec.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bfm_visual_tool/GeneratedFiles 3 | 4 | bfm_visual_tool/x64 5 | 6 | x64 7 | 8 | *.ply 9 | 10 | .vs 11 | *.bin 12 | bfm_visual_tool/data/data.zip 13 | *.h5 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BFM模型可视化工具 - C++ 2 | 3 | 通过C++和Qt5构建的一个Basel人脸模型(Basel Face Model, BFM)的可视化工具。 4 | 5 | 6 | 7 | 8 | 9 | ## 功能介绍 10 | 11 | ### 生成随机人脸 12 | 13 | 设置`random range` 后的滑动条,可以调节随机程度(正态分布的方差),0.0时为平均脸。 14 | 15 | 设置完成之后点击下方按钮即可在左侧生成随机人脸。 16 | 17 | ### 设置PC权重 18 | 19 | 可以修改面部Shape、Texture和Expr的PC权重,BFM共有199个PC可以在左侧下拉栏中选择,右测滑动条调节数值大小,调节完成后点击对应的按钮完成设置。 20 | 21 | *[NOTE] 修改PC权重需要在已经生成人脸的前提下使用* 22 | 23 | ### 将生成人脸存储到文件 24 | 25 | 目前支持的文件格式仅有PLY格式,可以通过MeshLab打开进行查看。 26 | 27 | 28 | 29 | ## 其他功能 30 | 31 | ### 预然人脸操作 32 | 33 | 该部分通过Qt5内置OpenGL实现,支持按键如下: 34 | 35 | * 鼠标左键:长按后可以拖拉旋转人脸; 36 | * 鼠标滚轮:缩放; 37 | * 键盘A/W/S/D:向左转/放大/向右转/缩小。 38 | 39 | -------------------------------------------------------------------------------- /assets/avg_v1.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bemfool/bfm-visual-tool/032d8b7629c497d7c3b4edef997a24008a8b3031/assets/avg_v1.0.png -------------------------------------------------------------------------------- /assets/avg_v1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bemfool/bfm-visual-tool/032d8b7629c497d7c3b4edef997a24008a8b3031/assets/avg_v1.1.png -------------------------------------------------------------------------------- /assets/avg_v2.0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bemfool/bfm-visual-tool/032d8b7629c497d7c3b4edef997a24008a8b3031/assets/avg_v2.0.gif -------------------------------------------------------------------------------- /bfm_visual_tool.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfm_visual_tool", "bfm_visual_tool\bfm_visual_tool.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64 15 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64 16 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64 17 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {2D3C74E0-D3D8-471B-A33A-DFAF1B53A3D3} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /bfm_visual_tool/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | 3 | const double SHAPE_SCALE = 0.1; 4 | const double TEX_SCALE = 120; 5 | const double EXPR_SCALE = 0.3; 6 | 7 | MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) 8 | { 9 | ui.setupUi(this); 10 | statusBar()->showMessage("loading...", 3000); 11 | model.init("inputs.txt"); 12 | initUI(); 13 | initSignalSlots(); 14 | setWindowTitle("Tools for Basel Face Model"); 15 | statusBar()->showMessage("ready"); 16 | } 17 | 18 | void MainWindow::initUI() 19 | { 20 | genRndFaceBtn = ui.centralWidget->findChild("genRndFaceBtn"); 21 | savePlyBtn = ui.centralWidget->findChild("savePlyBtn"); 22 | setShapePcBtn = ui.centralWidget->findChild("setShapePcBtn"); 23 | setTexPcBtn = ui.centralWidget->findChild("setTexPcBtn"); 24 | setExprPcBtn = ui.centralWidget->findChild("setExprPcBtn"); 25 | 26 | rndRangeSlider = ui.centralWidget->findChild("rndRangeSlider"); 27 | shapeSlider = ui.centralWidget->findChild("shapeSlider"); 28 | texSlider = ui.centralWidget->findChild("texSlider"); 29 | exprSlider = ui.centralWidget->findChild("exprSlider"); 30 | 31 | shapeComboBox = ui.centralWidget->findChild("shapeComboBox"); 32 | texComboBox = ui.centralWidget->findChild("texComboBox"); 33 | exprComboBox = ui.centralWidget->findChild("exprComboBox"); 34 | for (int i = 1; i <= model.get_n_id_pc(); i++) { 35 | shapeComboBox->addItem(QString::number(i)); 36 | texComboBox->addItem(QString::number(i)); 37 | } 38 | for (int i = 1; i <= model.get_n_expr_pc(); i++) 39 | exprComboBox->addItem(QString::number(i)); 40 | 41 | saveFilename = ui.centralWidget->findChild("saveFilename"); 42 | openGLWidget = ui.centralWidget->findChild("openGLWidget"); 43 | qDebug() << "[viewer] ui init done.\n"; 44 | } 45 | 46 | void MainWindow::initSignalSlots() 47 | { 48 | QObject::connect(genRndFaceBtn, SIGNAL(clicked()), this, SLOT(generateRandomFace())); 49 | QObject::connect(setShapePcBtn, SIGNAL(clicked()), this, SLOT(setShapePc())); 50 | QObject::connect(setTexPcBtn, SIGNAL(clicked()), this, SLOT(setTexPc())); 51 | QObject::connect(setExprPcBtn, SIGNAL(clicked()), this, SLOT(setExprPc())); 52 | 53 | QObject::connect(shapeComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(synShapeSlider())); 54 | QObject::connect(texComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(synTexSlider())); 55 | QObject::connect(exprComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(synExprSlider())); 56 | 57 | QObject::connect(savePlyBtn, SIGNAL(clicked()), this, SLOT(savePly())); 58 | } 59 | 60 | void MainWindow::generateRandomFace() 61 | { 62 | statusBar()->showMessage("generating...", 3000); 63 | double sliderVal = (double)rndRangeSlider->value(); 64 | model.generate_random_face(sliderVal / SHAPE_SCALE, sliderVal / TEX_SCALE, sliderVal / EXPR_SCALE); 65 | openGLWidget->theta = 0.0; 66 | openGLWidget->scale = 1.0; 67 | openGLWidget->update(); 68 | synShapeSlider(); 69 | synTexSlider(); 70 | synExprSlider(); 71 | } 72 | 73 | void MainWindow::synShapeSlider() 74 | { 75 | int pc = shapeComboBox->currentIndex(); 76 | shapeSlider->setValue(int(model.get_mutable_shape_coef()(pc) * SHAPE_SCALE)); 77 | } 78 | 79 | 80 | void MainWindow::synTexSlider() 81 | { 82 | int pc = texComboBox->currentIndex(); 83 | texSlider->setValue(int(model.get_mutable_tex_coef()(pc) * TEX_SCALE)); 84 | } 85 | 86 | void MainWindow::synExprSlider() 87 | { 88 | int pc = exprComboBox->currentIndex(); 89 | exprSlider->setValue(int(model.get_mutable_expr_coef()(pc) * EXPR_SCALE)); 90 | } 91 | 92 | 93 | void MainWindow::setShapePc() 94 | { 95 | int pc = shapeComboBox->currentIndex(); 96 | double pcValue = shapeSlider->value() / SHAPE_SCALE; 97 | model.get_mutable_shape_coef()(pc) = pcValue; 98 | model.generate_face(); 99 | openGLWidget->update(); 100 | } 101 | 102 | void MainWindow::setTexPc() 103 | { 104 | int pc = texComboBox->currentIndex(); 105 | double pcValue = texSlider->value() / TEX_SCALE; 106 | model.get_mutable_tex_coef()(pc) = pcValue; 107 | model.generate_face(); 108 | openGLWidget->update(); 109 | } 110 | 111 | void MainWindow::setExprPc() 112 | { 113 | int pc = exprComboBox->currentIndex(); 114 | double pcValue = exprSlider->value() / EXPR_SCALE; 115 | model.get_mutable_expr_coef()(pc) = pcValue; 116 | model.generate_face(); 117 | openGLWidget->update(); 118 | } 119 | 120 | void MainWindow::savePly() 121 | { 122 | std::string filename = saveFilename->toPlainText().toStdString(); 123 | 124 | /* Make sure filename is like *.ply format (default filename = rnd_face.ply) */ 125 | int fSize = filename.size(); 126 | if (fSize == 0) 127 | filename = "rnd_face.ply"; 128 | else if (fSize <= 4 || filename.substr(fSize - 4) != ".ply") 129 | filename = filename + ".ply"; 130 | 131 | model.ply_write(filename); 132 | QDialog *dialog = new QDialog; 133 | dialog->setModal(true); 134 | dialog->resize(300, 100); 135 | QLabel *label = new QLabel(dialog); 136 | label->setText("save - success"); 137 | dialog->exec(); 138 | } 139 | 140 | void MainWindow::keyPressEvent(QKeyEvent *event) { 141 | switch (event->key()) { 142 | case Qt::Key_A: 143 | openGLWidget->theta += 0.1; 144 | break; 145 | case Qt::Key_D: 146 | openGLWidget->theta -= 0.1; 147 | break; 148 | case Qt::Key_W: 149 | openGLWidget->scale += 0.1; 150 | break; 151 | case Qt::Key_S: 152 | openGLWidget->scale -= 0.1; 153 | break; 154 | default: 155 | break; 156 | } 157 | openGLWidget->update(); 158 | } 159 | 160 | 161 | void MainWindow::wheelEvent(QWheelEvent *event) { 162 | openGLWidget->scale += event->delta() / 1200.0; 163 | if (openGLWidget->scale <= 0.0) 164 | openGLWidget->scale = 0.01; 165 | openGLWidget->update(); 166 | } -------------------------------------------------------------------------------- /bfm_visual_tool/MainWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /********************************************************************* 3 | 4 | Author: Bemfoo 5 | Date: 2019-10-26 6 | Description: The main widget window of Basel face model visual tool. 7 | 8 | **********************************************************************/ 9 | 10 | #include 11 | #include "ui_MainWindow.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "OpenGLWidget.h" 19 | #include 20 | #include "bfm.h" 21 | 22 | class QSlider; 23 | class QPushButton; 24 | class QLabel; 25 | class QComboBox; 26 | class QOpenGLWidget; 27 | class QKeyEvent; 28 | class QWheelEvent; 29 | class QDialog; 30 | 31 | class MainWindow : public QMainWindow 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | MainWindow(QWidget *parent = Q_NULLPTR); 37 | bfm &getModel() { return model; } 38 | void keyPressEvent(QKeyEvent *event); 39 | void wheelEvent(QWheelEvent *event); 40 | 41 | private slots: 42 | void generateRandomFace(); 43 | void synShapeSlider(); 44 | void synTexSlider(); 45 | void synExprSlider(); 46 | void setShapePc(); 47 | void setTexPc(); 48 | void setExprPc(); 49 | void savePly(); 50 | 51 | private: 52 | Ui::MainWindowClass ui; 53 | 54 | bfm model; 55 | 56 | OpenGLWidget *openGLWidget; 57 | QPushButton *genRndFaceBtn; 58 | QPushButton *savePlyBtn; 59 | QPushButton *setShapePcBtn; 60 | QPushButton *setTexPcBtn; 61 | QPushButton *setExprPcBtn; 62 | 63 | QSlider *shapeSlider; 64 | QSlider *texSlider; 65 | QSlider *exprSlider; 66 | QSlider *rndRangeSlider; 67 | 68 | QComboBox *shapeComboBox; 69 | QComboBox *texComboBox; 70 | QComboBox *exprComboBox; 71 | 72 | QTextEdit *saveFilename; 73 | 74 | void initUI(); 75 | void initSignalSlots(); 76 | }; 77 | -------------------------------------------------------------------------------- /bfm_visual_tool/MainWindow.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /bfm_visual_tool/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindowClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1025 10 | 709 11 | 12 | 13 | 14 | QtTest 15 | 16 | 17 | 18 | 19 | 20 | 580 21 | 80 22 | 421 23 | 28 24 | 25 | 26 | 27 | generate random face 28 | 29 | 30 | 31 | 32 | 33 | 20 34 | 20 35 | 531 36 | 651 37 | 38 | 39 | 40 | 41 | 42 | 43 | 580 44 | 30 45 | 421 46 | 41 47 | 48 | 49 | 50 | 51 | 52 | 53 | random range 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 69 | 70 | 200 71 | 72 | 73 | 2 74 | 75 | 76 | Qt::Horizontal 77 | 78 | 79 | 80 | 81 | 82 | 83 | max 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 580 93 | 140 94 | 421 95 | 41 96 | 97 | 98 | 99 | 100 | 101 | 102 | No. 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -1000 120 | 121 | 122 | 1000 123 | 124 | 125 | Qt::Horizontal 126 | 127 | 128 | 129 | 130 | 131 | 132 | max 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 580 142 | 190 143 | 421 144 | 28 145 | 146 | 147 | 148 | set shape PC 149 | 150 | 151 | 152 | 153 | 154 | 580 155 | 120 156 | 421 157 | 16 158 | 159 | 160 | 161 | =================== shape PC ======================= 162 | 163 | 164 | 165 | 166 | 167 | 580 168 | 300 169 | 421 170 | 28 171 | 172 | 173 | 174 | set texture PC 175 | 176 | 177 | 178 | 179 | 180 | 580 181 | 250 182 | 421 183 | 41 184 | 185 | 186 | 187 | 188 | 189 | 190 | No. 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | -1000 208 | 209 | 210 | 1000 211 | 212 | 213 | Qt::Horizontal 214 | 215 | 216 | 217 | 218 | 219 | 220 | max 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 580 230 | 230 231 | 421 232 | 16 233 | 234 | 235 | 236 | =================== texture PC ======================= 237 | 238 | 239 | 240 | 241 | 242 | 580 243 | 620 244 | 421 245 | 31 246 | 247 | 248 | 249 | 250 | QLayout::SetFixedSize 251 | 252 | 253 | 254 | 255 | filename: 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 236 264 | 29 265 | 266 | 267 | 268 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 269 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 270 | p, li { white-space: pre-wrap; } 271 | </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> 272 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'SimSun';">rnd_face.ply</span></p></body></html> 273 | 274 | 275 | 276 | 277 | 278 | 279 | save as PLY 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 580 289 | 340 290 | 421 291 | 16 292 | 293 | 294 | 295 | =============== == expression PC ======================= 296 | 297 | 298 | 299 | 300 | 301 | 580 302 | 360 303 | 421 304 | 41 305 | 306 | 307 | 308 | 309 | 310 | 311 | No. 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | -1000 329 | 330 | 331 | 1000 332 | 333 | 334 | Qt::Horizontal 335 | 336 | 337 | 338 | 339 | 340 | 341 | max 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 580 351 | 410 352 | 421 353 | 28 354 | 355 | 356 | 357 | set texture PC 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 0 366 | 0 367 | 1025 368 | 26 369 | 370 | 371 | 372 | 373 | 文件 374 | 375 | 376 | 377 | 378 | 379 | 380 | 帮助 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 载入模型 390 | 391 | 392 | 393 | 394 | 更换模型 395 | 396 | 397 | 398 | 399 | BFM模型预处理 400 | 401 | 402 | 403 | 404 | 405 | 406 | OpenGLWidget 407 | QOpenGLWidget 408 |
OpenGLWidget.h
409 |
410 |
411 | 412 | 413 | 414 | 415 |
416 | -------------------------------------------------------------------------------- /bfm_visual_tool/OpenGLWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenGLWidget.h" 2 | #include "MainWindow.h" 3 | 4 | OpenGLWidget::OpenGLWidget(QWidget *parent) : QOpenGLWidget(parent) {} 5 | 6 | 7 | void OpenGLWidget::initializeGL() 8 | { 9 | initializeOpenGLFunctions(); 10 | glClearColor(0, 0, 0, 1); 11 | glEnable(GL_DEPTH_TEST); 12 | glEnable(GL_LIGHT0); 13 | glEnable(GL_LIGHTING); 14 | glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); 15 | glEnable(GL_COLOR_MATERIAL); 16 | glLoadIdentity(); 17 | gluLookAt(0, 0, 300000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); 18 | } 19 | 20 | 21 | void OpenGLWidget::resizeGL(int width, int height) 22 | { 23 | glViewport(0, 0, width, height); 24 | glMatrixMode(GL_PROJECTION); 25 | glLoadIdentity(); 26 | gluPerspective(60.0, (GLfloat)width / (GLfloat)height, 1.0, 600000.0); 27 | glMatrixMode(GL_MODELVIEW); 28 | glLoadIdentity(); 29 | gluLookAt(0, 0, 300000.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 30 | } 31 | 32 | 33 | void OpenGLWidget::paintGL() 34 | { 35 | MainWindow *p = (MainWindow*)(parentWidget()->parentWidget()); 36 | shape = p->getModel().get_current_blendshape(); 37 | tex = p->getModel().get_current_tex(); 38 | tl = p->getModel().get_tl(); 39 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 40 | if (shape.nr()!=0) { 41 | /* human face model */ 42 | double sint = sin(theta), cost = cos(theta); 43 | for (int i = 0; i < tl.size()/3; i++) { 44 | glBegin(GL_TRIANGLES); 45 | double xIdx = tl(i * 3) - 1; 46 | double yIdx = tl(i * 3 + 1) - 1; 47 | double zIdx = tl(i * 3 + 2) - 1; 48 | glColor3f(tex(xIdx * 3) / 255.0, tex(xIdx * 3 + 1) / 255.0, tex(xIdx * 3 + 2) / 255.0); 49 | glVertex3f(shape(xIdx * 3) * scale * cost - shape(xIdx * 3 + 2) * scale * sint, shape(xIdx * 3 + 1) * scale, shape(xIdx * 3) * scale * sint + shape(xIdx * 3 + 2) * scale * cost); 50 | glColor3f(tex(yIdx * 3) / 255.0, tex(yIdx * 3 + 1) / 255.0, tex(yIdx * 3 + 2) / 255.0); 51 | glVertex3f(shape(yIdx * 3) * scale * cost - shape(yIdx * 3 + 2) * scale * sint, shape(yIdx * 3 + 1) * scale, shape(yIdx * 3) * scale * sint + shape(yIdx * 3 + 2) * scale * cost); 52 | glColor3f(tex(zIdx * 3) / 255.0, tex(zIdx * 3 + 1) / 255.0, tex(zIdx * 3 + 2) / 255.0); 53 | glVertex3f(shape(zIdx * 3) * scale * cost - shape(zIdx * 3 + 2) * scale * sint, shape(zIdx * 3 + 1) * scale, shape(zIdx * 3) * scale * sint + shape(zIdx * 3 + 2) * scale * cost); 54 | glEnd(); 55 | } 56 | } 57 | else { 58 | /* initial scene - triangle */ 59 | glBegin(GL_TRIANGLES); 60 | glColor3f(1.0, 0.0, 0.0); 61 | glVertex3f(-50000 * cos(theta) * scale, 0, 0); 62 | glColor3f(0.0, 1.0, 0.0); 63 | glVertex3f(50000 * cos(theta) * scale, 0, 0); 64 | glColor3f(0.0, 0.0, 1.0); 65 | glVertex3f(0.0, 50000 * scale, 0); 66 | glEnd(); 67 | } 68 | } 69 | 70 | 71 | void OpenGLWidget::mousePressEvent(QMouseEvent *event) 72 | { 73 | if (event->button() == Qt::LeftButton) 74 | oldX = event->x(); /* record the current X pos */ 75 | } 76 | 77 | 78 | void OpenGLWidget::mouseMoveEvent(QMouseEvent *event) 79 | { 80 | if (event->buttons() & Qt::LeftButton) { 81 | double clockwise; 82 | if (event->x() < oldX) 83 | clockwise = -1.0; 84 | else if (event->x() > oldX) 85 | clockwise = 1.0; 86 | else 87 | clockwise = 0; 88 | oldX = event->x(); 89 | theta += clockwise * 0.1; 90 | update(); 91 | } 92 | } -------------------------------------------------------------------------------- /bfm_visual_tool/OpenGLWidget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /********************************************************************* 3 | 4 | Author: Bemfoo 5 | Date: 2019-10-26 6 | Description: A Qt5 widget implemented by built-in OpenGL to show Basel 7 | face model. 8 | 9 | **********************************************************************/ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | class QMouseEvent; 20 | class QKeyEvent; 21 | 22 | /* 23 | * Class: OpenGLWidget 24 | * -------------------------------------------------------------------- 25 | * The widget is used to show generated face. 26 | */ 27 | class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | explicit OpenGLWidget(QWidget *parent = Q_NULLPTR); 33 | 34 | public: 35 | void initializeGL() Q_DECL_OVERRIDE; 36 | void paintGL() Q_DECL_OVERRIDE; 37 | void resizeGL(int w, int h) Q_DECL_OVERRIDE; 38 | 39 | 40 | /* 41 | * Function: mouseMoveEvent 42 | * ------------------------------------------------------------ 43 | * When mouse move, rotate model in the direction judged by the 44 | * relative position between current X and oldX. 45 | */ 46 | 47 | void mouseMoveEvent(QMouseEvent *event); 48 | 49 | 50 | /* 51 | * Function: mousePressEvent 52 | * ------------------------------------------------------------- 53 | * When mouse clicks, mark current X pos as oldX. 54 | */ 55 | 56 | void mousePressEvent(QMouseEvent *event); 57 | 58 | public: 59 | double oldX; /* last position of mouse, used for rotation */ 60 | double theta = 0.0; /* rotation degree */ 61 | double scale = 1.0; /* zooming scale */ 62 | 63 | dlib::matrix shape; 64 | dlib::matrix tex; 65 | dlib::matrix tl; 66 | }; 67 | -------------------------------------------------------------------------------- /bfm_visual_tool/Resources/bfm_tool.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bemfool/bfm-visual-tool/032d8b7629c497d7c3b4edef997a24008a8b3031/bfm_visual_tool/Resources/bfm_tool.ico -------------------------------------------------------------------------------- /bfm_visual_tool/bfm.cpp: -------------------------------------------------------------------------------- 1 | #include "bfm.h" 2 | 3 | bfm::bfm(const std::string &filename) { 4 | init(filename); 5 | } 6 | 7 | 8 | void bfm::init(const std::string &filename) { 9 | if (!read_parm_from_file(filename)) 10 | return; 11 | init_parm(); 12 | load_data(); 13 | } 14 | 15 | 16 | void bfm::data_check() { 17 | bfm_out << "check data\n"; 18 | bfm_out << " (1) shape mu: \n"; 19 | bfm_out << " Yours: " << shape_mu(0, 0) << "\n"; 20 | bfm_out << " Correct: -57239 42966 80410\n\n"; 21 | bfm_out << " (2) shape ev: \n"; 22 | bfm_out << " Yours: " << shape_ev(0, 0) << " " << shape_ev(1, 0) << "\n"; 23 | bfm_out << " Correct: 884340 555880\n\n"; 24 | bfm_out << " (3) shape pc: \n"; 25 | bfm_out << " Yours: " << shape_pc(0, 0) << "\n"; 26 | bfm_out << " Correct: -0.0024\n\n"; 27 | bfm_out << " (4) texture mu: \n"; 28 | bfm_out << " Yours: " << tex_mu(0, 0) << endl; 29 | bfm_out << " Correct: 182.8750 135.0400 107.1400\n" << endl; 30 | bfm_out << " (5) texture ev: \n"; 31 | bfm_out << " Yours: " << tex_ev(0) << " " << tex_ev(1) << "\n"; 32 | bfm_out << " Correct: 4103.2 2024.1\n\n"; 33 | bfm_out << " (6) texture pc: \n"; 34 | bfm_out << " Yours: " << tex_pc(0, 0) << "\n"; 35 | bfm_out << " Correct: -0.0028\n\n"; 36 | bfm_out << " (7) expression mu: \n"; 37 | bfm_out << " Yours: " << expr_mu(0, 0) << endl; 38 | bfm_out << " Correct: 182.8750 135.0400 107.1400\n" << endl; 39 | bfm_out << " (8) expression ev: \n"; 40 | bfm_out << " Yours: " << expr_ev(0) << " " << expr_ev(1) << "\n"; 41 | bfm_out << " Correct: 4103.2 2024.1\n\n"; 42 | bfm_out << " (9) expression pc: \n"; 43 | bfm_out << " Yours: " << expr_pc(0, 0) << "\n"; 44 | bfm_out << " Correct: -0.0028\n\n"; 45 | bfm_out << " (10) triangle list: \n"; 46 | bfm_out << " Yours: " << tl(0) << " " << tl(1) << "\n"; 47 | bfm_out << " Correct: -0.0028\n\n"; 48 | } 49 | 50 | 51 | bool bfm::read_parm_from_file(const std::string &filename) { 52 | ifstream in(filename, std::ios::in); 53 | if (!in) { 54 | bfm_out << "[ERROR] Can't open " << filename.c_str() << ".\n"; 55 | return false; 56 | } 57 | in >> bfm_h5_path; 58 | in >> n_vertice >> n_face >> n_id_pc >> n_expr_pc; 59 | in >> n_landmark >> landmark_idx_path; 60 | in >> intrinsic_parm[0] >> intrinsic_parm[1] >> intrinsic_parm[2] >> intrinsic_parm[3]; 61 | in >> shape_mu_h5_path >> shape_ev_h5_path >> shape_pc_h5_path; 62 | in >> tex_mu_h5_path >> tex_ev_h5_path >> tex_pc_h5_path; 63 | in >> expr_mu_h5_path >> expr_ev_h5_path >> expr_pc_h5_path; 64 | in >> tl_h5_path; 65 | 66 | in.close(); 67 | return true; 68 | } 69 | 70 | 71 | void bfm::init_parm() { 72 | shape_coef.set_size(n_id_pc, 1); 73 | shape_mu.set_size(n_vertice * 3, 1); 74 | shape_ev.set_size(n_id_pc, 1); 75 | shape_pc.set_size(n_vertice * 3, n_id_pc); 76 | 77 | tex_coef.set_size(n_id_pc, 1); 78 | tex_mu.set_size(n_vertice * 3, 1); 79 | tex_ev.set_size(n_id_pc, 1); 80 | tex_pc.set_size(n_vertice * 3, n_id_pc); 81 | 82 | expr_coef.set_size(n_expr_pc, 1); 83 | expr_mu.set_size(n_vertice * 3, 1); 84 | expr_ev.set_size(n_expr_pc, 1); 85 | expr_pc.set_size(n_vertice * 3, n_expr_pc); 86 | 87 | tl.set_size(n_face * 3, 1); 88 | 89 | current_shape.set_size(n_vertice * 3, 1); 90 | current_tex.set_size(n_vertice * 3, 1); 91 | current_expr.set_size(n_vertice * 3, 1); 92 | current_blendshape.set_size(n_vertice * 3, 1); 93 | 94 | landmark_idx.resize(n_landmark); 95 | } 96 | 97 | 98 | bool bfm::load_data() { 99 | float *shape_mu_raw = new float[n_vertice * 3]; 100 | float *shape_ev_raw = new float[n_id_pc]; 101 | float *shape_pc_raw = new float[n_vertice * 3 * n_id_pc]; 102 | float *tex_mu_raw = new float[n_vertice * 3]; 103 | float *tex_ev_raw = new float[n_id_pc]; 104 | float *tex_pc_raw = new float[n_vertice * 3 * n_id_pc]; 105 | float *expr_mu_raw = new float[n_vertice * 3]; 106 | float *expr_ev_raw = new float[n_expr_pc]; 107 | float *expr_pc_raw = new float[n_vertice * 3 * n_expr_pc]; 108 | unsigned int *tl_raw = new unsigned int[n_face * 3]; 109 | 110 | H5File file(bfm_h5_path, H5F_ACC_RDONLY); 111 | load_hdf5_model(shape_mu, shape_mu_h5_path, PredType::NATIVE_FLOAT); 112 | load_hdf5_model(shape_ev, shape_ev_h5_path, PredType::NATIVE_FLOAT); 113 | load_hdf5_model(shape_pc, shape_pc_h5_path, PredType::NATIVE_FLOAT); 114 | 115 | load_hdf5_model(tex_mu, tex_mu_h5_path, PredType::NATIVE_FLOAT); 116 | load_hdf5_model(tex_ev, tex_ev_h5_path, PredType::NATIVE_FLOAT); 117 | load_hdf5_model(tex_pc, tex_pc_h5_path, PredType::NATIVE_FLOAT); 118 | 119 | load_hdf5_model(expr_mu, expr_mu_h5_path, PredType::NATIVE_FLOAT); 120 | load_hdf5_model(expr_ev, expr_ev_h5_path, PredType::NATIVE_FLOAT); 121 | load_hdf5_model(expr_pc, expr_pc_h5_path, PredType::NATIVE_FLOAT); 122 | 123 | load_hdf5_model(tl, tl_h5_path, PredType::NATIVE_UINT32); 124 | file.close(); 125 | 126 | shape_mu = shape_mu * 1000.0; 127 | 128 | ifstream in(landmark_idx_path, std::ios::in); 129 | if (!in) { 130 | bfm_out << "[ERROR] Can't open " << landmark_idx_path.c_str() << ".\n"; 131 | return false; 132 | } 133 | for (int i = 0; i < n_landmark; i++) { 134 | int tmp_idx; 135 | in >> tmp_idx; 136 | landmark_idx[i] = tmp_idx - 1; 137 | } 138 | bfm_out << "[bfm] load data - success.\n"; 139 | return true; 140 | } 141 | 142 | 143 | void bfm::generate_random_face(double scale) { 144 | shape_coef = randn(n_id_pc, scale); 145 | tex_coef = randn(n_id_pc, scale); 146 | expr_coef = randn(n_expr_pc, scale); 147 | generate_face(); 148 | } 149 | 150 | 151 | void bfm::generate_random_face(double shape_scale, double tex_scale, double expr_scale) { 152 | shape_coef = randn(n_id_pc, shape_scale); 153 | tex_coef = randn(n_id_pc, tex_scale); 154 | expr_coef = randn(n_expr_pc, expr_scale); 155 | generate_face(); 156 | } 157 | 158 | 159 | void bfm::generate_face() { 160 | current_shape = coef2object(shape_coef, shape_mu, shape_pc, shape_ev); 161 | current_tex = coef2object(tex_coef, tex_mu, tex_pc, tex_ev); 162 | current_expr = coef2object(expr_coef, expr_mu, expr_pc, expr_ev); 163 | current_blendshape = current_shape + current_expr; 164 | } 165 | 166 | 167 | dlib::matrix bfm::coef2object(dlib::matrix &coef, dlib::matrix &mu, 168 | dlib::matrix &pc, dlib::matrix &ev) { 169 | return mu + pc * pointwise_multiply(coef, ev); 170 | } 171 | 172 | 173 | void bfm::ply_write(string fn, bool pick_landmark) { 174 | ofstream out; 175 | /* Note: In Linux Cpp, we should use std::ios::bfm_out as flag, which is not necessary in Windows */ 176 | out.open(fn, std::ios::out | std::ios::binary); 177 | if (!out) { 178 | bfm_out << "Creation of " << fn.c_str() << " failed.\n"; 179 | return; 180 | } 181 | out << "ply\n"; 182 | out << "format binary_little_endian 1.0\n"; 183 | out << "comment Made from the 3D Morphable Face Model of the Univeristy of Basel, Switzerland.\n"; 184 | out << "element vertex " << n_vertice << "\n"; 185 | out << "property float x\n"; 186 | out << "property float y\n"; 187 | out << "property float z\n"; 188 | out << "property uchar red\n"; 189 | out << "property uchar green\n"; 190 | out << "property uchar blue\n"; 191 | out << "element face " << n_face << "\n"; 192 | out << "property list uchar int vertex_indices\n"; 193 | out << "end_header\n"; 194 | 195 | int cnt = 0; 196 | for (int i = 0; i < 68; i++) 197 | std::cout << " " << landmark_idx[i] << std::endl; 198 | 199 | for (int i = 0; i < n_vertice; i++) { 200 | float x = float(current_blendshape(i * 3)); 201 | float y = float(current_blendshape(i * 3 + 1)); 202 | float z = float(current_blendshape(i * 3 + 2)); 203 | unsigned char r, g, b; 204 | if (find(landmark_idx.begin(), landmark_idx.end(), i) != landmark_idx.end()) { 205 | r = 255; 206 | g = 0; 207 | b = 0; 208 | cnt++; 209 | } 210 | else { 211 | r = current_tex(i * 3); 212 | g = current_tex(i * 3 + 1); 213 | b = current_tex(i * 3 + 2); 214 | } 215 | out.write((char *)&x, sizeof(x)); 216 | out.write((char *)&y, sizeof(y)); 217 | out.write((char *)&z, sizeof(z)); 218 | out.write((char *)&r, sizeof(r)); 219 | out.write((char *)&g, sizeof(g)); 220 | out.write((char *)&b, sizeof(b)); 221 | } 222 | if (pick_landmark && cnt != n_landmark) { 223 | bfm_out << "[ERROR] Pick too less landmarks.\n"; 224 | bfm_out << "Number of picked points is " << cnt << ".\n"; 225 | } 226 | 227 | unsigned char N_VER_PER_FACE = 3; 228 | for (int i = 0; i < n_face; i++) { 229 | out.write((char *)&N_VER_PER_FACE, sizeof(N_VER_PER_FACE)); 230 | int x = tl(i * 3) - 1; 231 | int y = tl(i * 3 + 1) - 1; 232 | int z = tl(i * 3 + 2) - 1; 233 | out.write((char *)&y, sizeof(y)); 234 | out.write((char *)&x, sizeof(x)); 235 | out.write((char *)&z, sizeof(z)); 236 | } 237 | out.close(); 238 | } -------------------------------------------------------------------------------- /bfm_visual_tool/bfm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "data.h" 3 | #include "random.h" 4 | 5 | class bfm { 6 | public: 7 | bfm() {} 8 | bfm(const std::string &filename); 9 | void init(const std::string &filename); 10 | void data_check(); 11 | void generate_random_face(double scale = 0.0); 12 | void generate_random_face(double shape_scale, double tex_scale, double expr_scale); 13 | void generate_average_face() { generate_random_face(0.0); } 14 | void generate_face(); 15 | void ply_write(string fn = "rnd_face.ply", bool pick_landmarks = false); 16 | int get_n_id_pc() { return n_id_pc; } 17 | int get_n_expr_pc() { return n_expr_pc; } 18 | int get_n_face() { return n_face; } 19 | int get_n_vertice() { return n_vertice; } 20 | dlib::matrix &get_mutable_shape_coef() { return shape_coef; } 21 | dlib::matrix &get_mutable_tex_coef() { return tex_coef; } 22 | dlib::matrix &get_mutable_expr_coef() { return expr_coef; } 23 | const dlib::matrix &get_current_shape() { return current_shape; } 24 | const dlib::matrix &get_current_tex() { return current_tex; } 25 | const dlib::matrix &get_current_expr() { return current_expr; } 26 | const dlib::matrix &get_current_blendshape() { return current_blendshape; } 27 | const dlib::matrix &get_tl() { return tl; } 28 | private: 29 | bool read_parm_from_file(const std::string &filename); 30 | void init_parm(); 31 | bool load_data(); 32 | dlib::matrix coef2object(dlib::matrix &coef, dlib::matrix &mu, 33 | dlib::matrix &pc, dlib::matrix &ev); 34 | 35 | std::string bfm_h5_path; 36 | std::string landmark_idx_path; 37 | 38 | std::string shape_mu_h5_path; 39 | std::string shape_ev_h5_path; 40 | std::string shape_pc_h5_path; 41 | 42 | std::string tex_mu_h5_path; 43 | std::string tex_ev_h5_path; 44 | std::string tex_pc_h5_path; 45 | 46 | std::string expr_mu_h5_path; 47 | std::string expr_ev_h5_path; 48 | std::string expr_pc_h5_path; 49 | 50 | std::string tl_h5_path; 51 | 52 | int n_vertice; 53 | int n_face; 54 | int n_id_pc; 55 | int n_expr_pc; 56 | int n_landmark; 57 | 58 | double external_parm[6] = { 0.f }; /* yaw roll pitch tx ty tz */ 59 | double intrinsic_parm[4] = { 0.f }; /* fx fy cx cy */ 60 | 61 | dlib::matrix shape_coef; 62 | dlib::matrix shape_mu; 63 | dlib::matrix shape_ev; 64 | dlib::matrix shape_pc; 65 | 66 | dlib::matrix tex_coef; 67 | dlib::matrix tex_mu; 68 | dlib::matrix tex_ev; 69 | dlib::matrix tex_pc; 70 | 71 | dlib::matrix expr_coef; 72 | dlib::matrix expr_mu; 73 | dlib::matrix expr_ev; 74 | dlib::matrix expr_pc; 75 | 76 | dlib::matrix tl; /* triangle list */ 77 | 78 | dlib::matrix current_shape; 79 | dlib::matrix current_tex; 80 | dlib::matrix current_expr; 81 | dlib::matrix current_blendshape; 82 | 83 | std::vector landmark_idx; 84 | }; -------------------------------------------------------------------------------- /bfm_visual_tool/bfm_tool.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "./Resources/bfm_tool.ico" -------------------------------------------------------------------------------- /bfm_visual_tool/bfm_visual_tool.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {B12702AD-ABFB-343A-A199-8E24837244A3} 15 | Qt4VSv1.0 16 | 10.0.17134.0 17 | bfm_visual_tool 18 | 19 | 20 | 21 | Application 22 | v141 23 | 24 | 25 | Application 26 | v141 27 | 28 | 29 | 30 | $(MSBuildProjectDirectory)\QtMsBuild 31 | 32 | 33 | $(SolutionDir)$(Platform)\$(Configuration)\ 34 | 35 | 36 | $(SolutionDir)$(Platform)\$(Configuration)\ 37 | D:\Software\hdf5\CMake-hdf5-1.10.5\CMake-hdf5-1.10.5\HDF5-1.10.5-win64\include;$(IncludePath);D:\Software\dlib\dlib-19.17\dlib-19.17;D:\Software\OpenCV3\opencv\build\include\opencv2;D:\Software\OpenCV3\opencv\build\include;D:\Software\OpenCV3\opencv\build\include\opencv 38 | D:\Software\hdf5\CMake-hdf5-1.10.5\CMake-hdf5-1.10.5\HDF5-1.10.5-win64\lib;$(LibraryPath);D:\Software\dlib\dlib-19.17\dlib-19.17;D:\Software\OpenCV3\opencv\build\x64\vc14\lib 39 | $(VC_ReferencesPath_x64);D:\Software\dlib\dlib-19.17\dlib-19.17; 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_OPENGLEXTENSIONS_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) 60 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtOpenGLExtensions;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) 61 | Disabled 62 | ProgramDatabase 63 | MultiThreadedDebugDLL 64 | true 65 | 66 | 67 | Windows 68 | $(OutDir)\$(ProjectName).exe 69 | $(QTDIR)\lib;%(AdditionalLibraryDirectories) 70 | true 71 | qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5OpenGLd.lib;opengl32.lib;glu32.lib;Qt5OpenGLExtensionsd.lib;Qt5Widgetsd.lib;%(AdditionalDependencies) 72 | 73 | 74 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 75 | Moc'ing %(Identity)... 76 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName)\.;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtOpenGLExtensions;$(QTDIR)\include\QtWidgets 77 | UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_OPENGLEXTENSIONS_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions) 78 | 79 | 80 | Uic'ing %(Identity)... 81 | .\GeneratedFiles\ui_%(Filename).h 82 | 83 | 84 | Rcc'ing %(Identity)... 85 | .\GeneratedFiles\qrc_%(Filename).cpp 86 | 87 | 88 | 89 | 90 | true 91 | UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_OPENGLEXTENSIONS_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions);H5_BUILT_AS_DYNAMIC_LIB; 92 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtOpenGLExtensions;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories) 93 | 94 | MultiThreadedDLL 95 | true 96 | /bigobj %(AdditionalOptions) 97 | 98 | 99 | Windows 100 | $(OutDir)\$(ProjectName).exe 101 | $(QTDIR)\lib;%(AdditionalLibraryDirectories);D:\Software\dlib\build2\Debug 102 | false 103 | qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5OpenGL.lib;opengl32.lib;glu32.lib;Qt5OpenGLExtensions.lib;Qt5Widgets.lib;%(AdditionalDependencies);szip.lib;zlib.lib;hdf5.lib;hdf5_cpp.lib;dlib.lib;opencv_world320.lib; 104 | 105 | 106 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 107 | Moc'ing %(Identity)... 108 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName)\.;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtOpenGL;$(QTDIR)\include\QtOpenGLExtensions;$(QTDIR)\include\QtWidgets 109 | UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_OPENGL_LIB;QT_OPENGLEXTENSIONS_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions);H5_BUILT_AS_DYNAMIC_LIB; 110 | 111 | 112 | Uic'ing %(Identity)... 113 | .\GeneratedFiles\ui_%(Filename).h 114 | 115 | 116 | Rcc'ing %(Identity)... 117 | .\GeneratedFiles\qrc_%(Filename).cpp 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /bfm_visual_tool/bfm_visual_tool.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 14 | qrc;* 15 | false 16 | 17 | 18 | {99349809-55BA-4b9d-BF79-8FDBB0286EB3} 19 | ui 20 | 21 | 22 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 23 | qrc;* 24 | false 25 | 26 | 27 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 28 | moc;h;cpp 29 | False 30 | 31 | 32 | {9b057d09-802b-46f7-a10f-459442a4343e} 33 | 34 | 35 | {3b2f48ab-e426-4a03-8770-59e185a22d09} 36 | 37 | 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files\bfm_utils 50 | 51 | 52 | Source Files\bfm_utils 53 | 54 | 55 | Source Files 56 | 57 | 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | 67 | 68 | Form Files 69 | 70 | 71 | 72 | 73 | Resource Files 74 | 75 | 76 | 77 | 78 | Header Files\bfm_utils 79 | 80 | 81 | Header Files\bfm_utils 82 | 83 | 84 | Header Files\bfm_utils 85 | 86 | 87 | Header Files\bfm_utils 88 | 89 | 90 | Header Files\bfm_utils 91 | 92 | 93 | 94 | 95 | Resource Files 96 | 97 | 98 | 99 | 100 | Resource Files 101 | 102 | 103 | -------------------------------------------------------------------------------- /bfm_visual_tool/bfm_visual_tool.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | D:\Software\qt\qt\5.13.1\msvc2017_64 6 | PATH=$(QTDIR)\bin%3b$(PATH) 7 | 8 | 9 | D:\Software\qt\qt\5.13.1\msvc2017_64 10 | PATH=$(QTDIR)\bin%3b$(PATH) 11 | 12 | -------------------------------------------------------------------------------- /bfm_visual_tool/constant.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define USE_QT true 5 | 6 | #ifdef USE_QT 7 | #include 8 | #define bfm_out qDebug() 9 | #else 10 | #define bfm_out std::cout 11 | #endif 12 | 13 | /* camera type */ 14 | typedef int camera_type; 15 | enum { 16 | PARALLEL = 0, 17 | PINHOLE = 1, 18 | }; 19 | 20 | typedef int op_type; 21 | enum { 22 | COARSE = 0, 23 | REAL = 1, 24 | }; -------------------------------------------------------------------------------- /bfm_visual_tool/data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "vec.h" 6 | #include "constant.h" 7 | #include "H5Cpp.h" 8 | 9 | using namespace H5; 10 | using namespace std; 11 | 12 | /* Macro Function: load_hdf5_model 13 | * Usage: load_hdf5_model(model_type, dataset_path, data_type); 14 | * Parameters: 15 | * model_type: data name, e.g. shape_mu; 16 | * dataset_path: dataset path in .h5 file, e.g. "/shape/model/mean" 17 | * data_type: data type in dataset, e.g. PredType::NATIVE_FLOAT 18 | * *********************************************************************** 19 | * Load data from .h5 format file into corresponding data struction. 20 | */ 21 | 22 | #define load_hdf5_model(model_type, dataset_path, data_type) { \ 23 | DataSet model_type##_data = file.openDataSet(dataset_path); \ 24 | model_type##_data.read(model_type##_raw, data_type); \ 25 | model_type##_data.close(); \ 26 | raw2matrix(model_type, model_type##_raw); \ 27 | delete[] model_type##_raw; \ 28 | } 29 | 30 | 31 | template 32 | void raw2matrix(dlib::matrix &m, T *raw) { 33 | bfm_out << "check: " << m.nr() << " " << m.nc() << "\n"; 34 | for (int i = 0; i < m.nr(); i++) 35 | for (int j = 0; j < m.nc(); j++) 36 | m(i, j) = raw[i * m.nc() + j]; 37 | } 38 | -------------------------------------------------------------------------------- /bfm_visual_tool/inputs-2017.txt: -------------------------------------------------------------------------------- 1 | D:\database\bfm\2017\model2017-1_bfm_nomouth.h5 2 | 53149 105694 199 100 3 | 68 D:\database\bfm\3DMM_model\landmark.anl 4 | 1744.327628674942 1747.838275588676 800 600 5 | shape/model/mean shape/model/pcaVariance shape/model/pcaBasis 6 | color/model/mean color/model/pcaVariance color/model/pcaBasis 7 | expression/model/mean expression/model/pcaVariance expression/model/pcaBasis 8 | shape/representer/cells -------------------------------------------------------------------------------- /bfm_visual_tool/inputs.txt: -------------------------------------------------------------------------------- 1 | D:\database\bfm\3DMM_model\BaselFaceModel_mod.h5 2 | 46990 93322 99 29 3 | 68 D:\database\bfm\3DMM_model\landmark_outer.anl 4 | 1744.327628674942 1747.838275588676 800 600 5 | shapeMU shapeEV shapePC 6 | texMU texEV texPC 7 | expMU expEV expPC 8 | faces 9 | -------------------------------------------------------------------------------- /bfm_visual_tool/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /bfm_visual_tool/random.cpp: -------------------------------------------------------------------------------- 1 | #include "random.h" 2 | 3 | dlib::matrix randn(int n, double scale) { 4 | dlib::matrix res(n, 1); 5 | std::default_random_engine e; 6 | e.seed(time(NULL)); 7 | std::normal_distribution dis(0, scale); 8 | for (int i = 0; i < n; i++) 9 | res(i) = dis(e); 10 | return res; 11 | } 12 | -------------------------------------------------------------------------------- /bfm_visual_tool/random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | /* Function: randn 7 | * Usage: 8 | * std::vector seq = randn(n); 9 | * std::vector seq = randn(n, scale); 10 | * Parameters: 11 | * n - The number of random element to be generated. 12 | * ------------------------------------------------------------- 13 | * Generate a sequence of random numbers into a vector sequence. 14 | * Its distribution is normal distribution whose sigma = 0 ,and 15 | * miu = 1. 16 | */ 17 | 18 | dlib::matrix randn(int n, double scale); -------------------------------------------------------------------------------- /bfm_visual_tool/vec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | /* Definition of 3d coordinate, because dlib only support dlib::point, which is 2d */ 6 | typedef dlib::vector point3f; 7 | typedef dlib::vector point3d; 8 | template using point3x = dlib::vector; 9 | typedef dlib::point point2d; --------------------------------------------------------------------------------