diff --git a/bob/ip/flandmark/__init__.py b/bob/ip/flandmark/__init__.py index 2e175b0bfdc512dd50ef29eebeef7144caddcd00..463647bf729a03450b3d7f9bb5f4f28983a9316c 100644 --- a/bob/ip/flandmark/__init__.py +++ b/bob/ip/flandmark/__init__.py @@ -12,13 +12,14 @@ def get_config(): import bob.extension return bob.extension.get_config(__name__, version.externals) +def _init(): + # Setup default model for C-API + from pkg_resources import resource_filename + import os.path + from ._library import _set_default_model + _set_default_model(resource_filename(__name__, os.path.join('data', 'flandmark_model.dat'))) + +_init() # gets sphinx autodoc done right - don't remove it __all__ = [_ for _ in dir() if not _.startswith('_')] - -# Setup default model for C-API -from pkg_resources import resource_filename -import os.path -from ._library import __set_default_model__ -__set_default_model__(resource_filename(__name__, os.path.join('data', 'flandmark_model.dat'))) -del resource_filename, __set_default_model__, os diff --git a/bob/ip/flandmark/cpp/flandmark_detector.cpp b/bob/ip/flandmark/cpp/flandmark_detector.cpp index 328e29a69c21a5c272d640c8173d7d2b1f383ee2..bb9bab1b1f344ceb3630aa0cd1a4ae8e5ea4805c 100644 --- a/bob/ip/flandmark/cpp/flandmark_detector.cpp +++ b/bob/ip/flandmark/cpp/flandmark_detector.cpp @@ -12,755 +12,671 @@ #include <stdlib.h> #include <string.h> #include <float.h> +#include <stdexcept> +#include <boost/format.hpp> +#include <bob.ip.base/Affine.h> #include "liblbp.h" #include "flandmark_detector.h" -void flandmark_write_model(const char* filename, FLANDMARK_Model* model) -{ - int * p_int = 0, tsize = -1, tmp_tsize = -1; - uint8_t * p_uint8 = 0; - uint32_t * p_uint32 = 0; - - FILE *fout; - if ((fout = fopen(filename, "wb")) == NULL) - { - printf("Error opening file %s\n", filename); - exit(1); - } - - // write constants (size of matrices, etc) - fprintf(fout, " %c ", model->data.options.M); - fprintf(fout, " %d %d ", model->data.options.bw[0], model->data.options.bw[1]); - fprintf(fout, " %d %d ", model->data.options.bw_margin[0], model->data.options.bw_margin[1]); - fprintf(fout, " %d %d ", model->W_ROWS, model->W_COLS); - fprintf(fout, " %d %d ", model->data.imSize[0], model->data.imSize[1]); - for (int idx = 0; idx < model->data.options.M; ++idx) - { - fprintf(fout, " %d %d ", model->data.lbp[idx].WINS_ROWS, model->data.lbp[idx].WINS_COLS); - } - for (int idx = 0; idx < 3; ++idx) - { - fprintf(fout, " %d %d ", model->data.options.PSIG_ROWS[idx], model->data.options.PSIG_COLS[idx]); - printf("model->data.options.PSIG_ROWS[%d] = %d; model->data.options.PSIG_COLS[%d] = %d; \n", - idx, model->data.options.PSIG_ROWS[idx], - idx, model->data.options.PSIG_COLS[idx] ); - } - - // write model->W - printf("Writing model->W to file... "); - if (fwrite(model->W, model->W_ROWS*sizeof(double), 1, fout) != 1) - { - fclose(fout); - printf("Error writing file %s\n", filename); - exit(1); - } - printf("done.\n"); - - // write model->mapTable - printf("Writing model->data.mapTable to file... "); - if (fwrite(model->data.mapTable, model->data.options.M*4*sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - printf( "done.\n"); - - // write model->data.lbp --------------------------------------------------- - printf( "Writing model->data.lbp to file... \n"); - for (int idx = 0; idx < model->data.options.M; ++idx) - { - printf( "lbp[%d]... ", idx); - - // lbp{idx}.winSize - p_int = &(model->data.lbp[idx].winSize[0]); - if (fwrite(p_int, 2*sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - printf( " winSize... "); - - // lbp{idx}.hop - p_uint8 = &(model->data.lbp[idx].hop); - if (fwrite(p_uint8, sizeof(uint8_t), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - printf( " hop... "); - - // lbp{idx}.wins - p_uint32 = model->data.lbp[idx].wins; - tsize = model->data.lbp[idx].WINS_ROWS*model->data.lbp[idx].WINS_COLS; - if (fwrite(p_uint32, tsize*sizeof(uint32_t), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - printf( " wins... done.\n"); - } - - // write model->data.options.S -------------------------------------------- - printf( "Writing model->data.options.S to file... "); - p_int = &(model->data.options.S[0]); - if (fwrite(p_int, 4*model->data.options.M*sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - printf( "done.\n"); - - // write model->data.options.PsiGS# ----------------------------------------- - FLANDMARK_PSIG * PsiGi = NULL; - for (int psigs_idx = 0; psigs_idx < 3; ++psigs_idx) - { - printf("PsiGS for loop.\n"); - switch (psigs_idx) - { - case 0: - printf( "Case 0 = PsiGS0 setting pointer..."); - PsiGi = (model->data.options.PsiGS0); - printf( " done.\n"); - break; - case 1: - printf( "Case 0 = PsiGS1 setting pointer..."); - PsiGi = (model->data.options.PsiGS1); - printf( " done.\n"); - break; - case 2: - printf( "Case 0 = PsiGS2 setting pointer..."); - PsiGi = (model->data.options.PsiGS2); - printf( " done.\n"); - break; - } - - printf("calculating tsize\n"); - - tsize = model->data.options.PSIG_ROWS[psigs_idx]*model->data.options.PSIG_COLS[psigs_idx]; - - printf("tsize = %d\n", tsize); - - for (int idx = 0; idx < tsize; ++idx) - { - // write ROWS and COLS size - p_int = &PsiGi[idx].ROWS; - if (fwrite(p_int, sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - p_int = &PsiGi[idx].COLS; - if (fwrite(p_int, sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - // write disp - tmp_tsize = PsiGi[idx].ROWS*PsiGi[idx].COLS; - if (fwrite(PsiGi[idx].disp, tmp_tsize*sizeof(int), 1, fout) != 1) - { - fclose(fout); - printf( "Error writing file %s\n", filename); - exit(1); - } - } - } - - fclose(fout); -} +namespace bob { namespace ip { namespace flandmark { -FLANDMARK_Model * flandmark_init(const char* filename) +void flandmark_write_model(const char* filename, FLANDMARK_Model* model) { - int *p_int = 0, tsize = -1, tmp_tsize = -1; - uint8_t *p_uint8 = 0; - - FILE *fin; - if ((fin = fopen(filename, "rb")) == NULL) - { - printf("Error opening file %s\n", filename); - return 0; - } - - // allocate memory for FLANDMARK_Model - FLANDMARK_Model * tst = (FLANDMARK_Model*)malloc(sizeof(FLANDMARK_Model)); - - //int fscan_ret = -1; - if (fscanf(fin, " %c ", &tst->data.options.M) < 1) + int * p_int = 0, tsize = -1, tmp_tsize = -1; + uint8_t * p_uint8 = 0; + uint32_t * p_uint32 = 0; + + FILE *fout; + if ((fout = fopen(filename, "wb")) == NULL) + { + printf("Error opening file %s\n", filename); + exit(1); + } + + // write constants (size of matrices, etc) + fprintf(fout, " %c ", model->data.options.M); + fprintf(fout, " %d %d ", model->data.options.bw[0], model->data.options.bw[1]); + fprintf(fout, " %d %d ", model->data.options.bw_margin[0], model->data.options.bw_margin[1]); + fprintf(fout, " %d %d ", model->W_ROWS, model->W_COLS); + fprintf(fout, " %d %d ", model->data.imSize[0], model->data.imSize[1]); + for (int idx = 0; idx < model->data.options.M; ++idx) + { + fprintf(fout, " %d %d ", model->data.lbp[idx].WINS_ROWS, model->data.lbp[idx].WINS_COLS); + } + for (int idx = 0; idx < 3; ++idx) + { + fprintf(fout, " %d %d ", model->data.options.PSIG_ROWS[idx], model->data.options.PSIG_COLS[idx]); + printf("model->data.options.PSIG_ROWS[%d] = %d; model->data.options.PSIG_COLS[%d] = %d; \n", + idx, model->data.options.PSIG_ROWS[idx], + idx, model->data.options.PSIG_COLS[idx] ); + } + + // write model->W + printf("Writing model->W to file... "); + if (fwrite(model->W, model->W_ROWS*sizeof(double), 1, fout) != 1) + { + fclose(fout); + printf("Error writing file %s\n", filename); + exit(1); + } + printf("done.\n"); + + // write model->mapTable + printf("Writing model->data.mapTable to file... "); + if (fwrite(model->data.mapTable, model->data.options.M*4*sizeof(int), 1, fout) != 1) + { + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); + } + printf( "done.\n"); + + // write model->data.lbp --------------------------------------------------- + printf( "Writing model->data.lbp to file... \n"); + for (int idx = 0; idx < model->data.options.M; ++idx) + { + printf( "lbp[%d]... ", idx); + + // lbp{idx}.winSize + p_int = &(model->data.lbp[idx].winSize[0]); + if (fwrite(p_int, 2*sizeof(int), 1, fout) != 1) { - return 0; + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); } + printf( " winSize... "); - if (fscanf(fin, " %d %d ", &tst->data.options.bw[0], &tst->data.options.bw[1]) < 2) + // lbp{idx}.hop + p_uint8 = &(model->data.lbp[idx].hop); + if (fwrite(p_uint8, sizeof(uint8_t), 1, fout) != 1) { - return 0; + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); } + printf( " hop... "); - if (fscanf(fin, " %d %d ", &tst->data.options.bw_margin[0], &tst->data.options.bw_margin[1]) < 2) + // lbp{idx}.wins + p_uint32 = model->data.lbp[idx].wins; + tsize = model->data.lbp[idx].WINS_ROWS*model->data.lbp[idx].WINS_COLS; + if (fwrite(p_uint32, tsize*sizeof(uint32_t), 1, fout) != 1) { - return 0; + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); } - - if (fscanf(fin, " %d %d ", &tst->W_ROWS, &tst->W_COLS) < 2) + printf( " wins... done.\n"); + } + + // write model->data.options.S -------------------------------------------- + printf( "Writing model->data.options.S to file... "); + p_int = &(model->data.options.S[0]); + if (fwrite(p_int, 4*model->data.options.M*sizeof(int), 1, fout) != 1) + { + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); + } + printf( "done.\n"); + + // write model->data.options.PsiGS# ----------------------------------------- + FLANDMARK_PSIG * PsiGi = NULL; + for (int psigs_idx = 0; psigs_idx < 3; ++psigs_idx) + { + printf("PsiGS for loop.\n"); + switch (psigs_idx) { - return 0; + case 0: + printf( "Case 0 = PsiGS0 setting pointer..."); + PsiGi = (model->data.options.PsiGS0); + printf( " done.\n"); + break; + case 1: + printf( "Case 0 = PsiGS1 setting pointer..."); + PsiGi = (model->data.options.PsiGS1); + printf( " done.\n"); + break; + case 2: + printf( "Case 0 = PsiGS2 setting pointer..."); + PsiGi = (model->data.options.PsiGS2); + printf( " done.\n"); + break; } - if (fscanf(fin, " %d %d ", &tst->data.imSize[0], &tst->data.imSize[1]) < 2) + printf("calculating tsize\n"); + + tsize = model->data.options.PSIG_ROWS[psigs_idx]*model->data.options.PSIG_COLS[psigs_idx]; + + printf("tsize = %d\n", tsize); + + for (int idx = 0; idx < tsize; ++idx) { - return 0; + // write ROWS and COLS size + p_int = &PsiGi[idx].ROWS; + if (fwrite(p_int, sizeof(int), 1, fout) != 1) + { + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); + } + p_int = &PsiGi[idx].COLS; + if (fwrite(p_int, sizeof(int), 1, fout) != 1) + { + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); + } + // write disp + tmp_tsize = PsiGi[idx].ROWS*PsiGi[idx].COLS; + if (fwrite(PsiGi[idx].disp, tmp_tsize*sizeof(int), 1, fout) != 1) + { + fclose(fout); + printf( "Error writing file %s\n", filename); + exit(1); + } } + } - int M = tst->data.options.M; + fclose(fout); +} - tst->data.lbp = (FLANDMARK_LBP*)malloc(M*sizeof(FLANDMARK_LBP)); - for (int idx = 0; idx < M; ++idx) - { - if (fscanf(fin, " %d %d ", &tst->data.lbp[idx].WINS_ROWS, &tst->data.lbp[idx].WINS_COLS) < 2) - { - return 0; - } - } +FLANDMARK_Model * flandmark_init(const char* filename) +{ + int *p_int = 0, tsize = -1, tmp_tsize = -1; + uint8_t *p_uint8 = 0; + + FILE *fin; + if ((fin = fopen(filename, "rb")) == NULL) + { + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + } + + // allocate memory for FLANDMARK_Model + FLANDMARK_Model * tst = (FLANDMARK_Model*)malloc(sizeof(FLANDMARK_Model)); + + //int fscan_ret = -1; + if (fscanf(fin, " %c ", &tst->data.options.M) < 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + if (fscanf(fin, " %d %d ", &tst->data.options.bw[0], &tst->data.options.bw[1]) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + if (fscanf(fin, " %d %d ", &tst->data.options.bw_margin[0], &tst->data.options.bw_margin[1]) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + if (fscanf(fin, " %d %d ", &tst->W_ROWS, &tst->W_COLS) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + if (fscanf(fin, " %d %d ", &tst->data.imSize[0], &tst->data.imSize[1]) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + int M = tst->data.options.M; + + tst->data.lbp = (FLANDMARK_LBP*)malloc(M*sizeof(FLANDMARK_LBP)); + for (int idx = 0; idx < M; ++idx){ + if (fscanf(fin, " %d %d ", &tst->data.lbp[idx].WINS_ROWS, &tst->data.lbp[idx].WINS_COLS) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + } + + for (int idx = 0; idx < 3; ++idx){ + if (fscanf(fin, " %d %d ", &tst->data.options.PSIG_ROWS[idx], &tst->data.options.PSIG_COLS[idx]) < 2) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + } + + // load model.W ----------------------------------------------------------- + tst->W = (double*)malloc(tst->W_ROWS * sizeof(double)); + if (fread(tst->W, tst->W_ROWS * sizeof(double), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + + // load model.data.mapTable ----------------------------------------------- + p_int = (int*)malloc(M*4*sizeof(int)); + tst->data.mapTable = (int*)malloc(M*4*sizeof(int)); + if (fread(p_int, M*4*sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + for (int i = 0; i < M*4; ++i) + tst->data.mapTable[i] = p_int[i]; + free(p_int); + + // load model.data.lbp --------------------------------------------------- + for (int idx = 0; idx < M; ++idx){ + // lbp{idx}.winSize + p_int = (int*)malloc(2*sizeof(int)); + if (fread(p_int, 2*sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + for (int i = 0; i < 2; ++i) + tst->data.lbp[idx].winSize[i] = p_int[i]; + free(p_int); + + // lbp{idx}.hop + p_uint8 = (uint8_t*)malloc(sizeof(uint8_t)); + if (fread(p_uint8, sizeof(uint8_t), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + tst->data.lbp[idx].hop = p_uint8[0]; + free(p_uint8); + + // lbp{idx}.wins + tsize = tst->data.lbp[idx].WINS_ROWS*tst->data.lbp[idx].WINS_COLS; + tst->data.lbp[idx].wins = (uint32_t*)malloc(tsize * sizeof(uint32_t)); + if (fread(tst->data.lbp[idx].wins, tsize * sizeof(uint32_t), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + } + + // load model.options.S -------------------------------------------------- + p_int = (int*)malloc(4*M*sizeof(int)); + tst->data.options.S = (int*)malloc(4*M*sizeof(int)); + if (fread(p_int, 4*M*sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + for (int i = 0; i < 4*M; ++i) + tst->data.options.S[i] = p_int[i]; + free(p_int); + + // load model.options.PsiG ----------------------------------------------- + FLANDMARK_PSIG * PsiGi = NULL; + for (int psigs_idx = 0; psigs_idx < 3; ++psigs_idx){ + tsize = tst->data.options.PSIG_ROWS[psigs_idx]*tst->data.options.PSIG_COLS[psigs_idx]; + + switch (psigs_idx){ + case 0: + tst->data.options.PsiGS0 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); + PsiGi = tst->data.options.PsiGS0; + break; + case 1: + tst->data.options.PsiGS1 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); + PsiGi = tst->data.options.PsiGS1; + break; + case 2: + tst->data.options.PsiGS2 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); + PsiGi = tst->data.options.PsiGS2; + break; + } - for (int idx = 0; idx < 3; ++idx) - { - if (fscanf(fin, " %d %d ", &tst->data.options.PSIG_ROWS[idx], &tst->data.options.PSIG_COLS[idx]) < 2) - { - return 0; - } - } - - // load model.W ----------------------------------------------------------- - tst->W = (double*)malloc(tst->W_ROWS * sizeof(double)); - if (fread(tst->W, tst->W_ROWS * sizeof(double), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - } - - // load model.data.mapTable ----------------------------------------------- - p_int = (int*)malloc(M*4*sizeof(int)); - tst->data.mapTable = (int*)malloc(M*4*sizeof(int)); - if (fread(p_int, M*4*sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - } - for (int i = 0; i < M*4; ++i) - { - tst->data.mapTable[i] = p_int[i]; - } - free(p_int); - - // load model.data.lbp --------------------------------------------------- - for (int idx = 0; idx < M; ++idx) - { - // lbp{idx}.winSize - p_int = (int*)malloc(2*sizeof(int)); - if (fread(p_int, 2*sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - } - for (int i = 0; i < 2; ++i) - { - tst->data.lbp[idx].winSize[i] = p_int[i]; - } - free(p_int); - - // lbp{idx}.hop - p_uint8 = (uint8_t*)malloc(sizeof(uint8_t)); - if (fread(p_uint8, sizeof(uint8_t), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - } - tst->data.lbp[idx].hop = p_uint8[0]; - free(p_uint8); - - // lbp{idx}.wins - tsize = tst->data.lbp[idx].WINS_ROWS*tst->data.lbp[idx].WINS_COLS; - tst->data.lbp[idx].wins = (uint32_t*)malloc(tsize * sizeof(uint32_t)); - if (fread(tst->data.lbp[idx].wins, tsize * sizeof(uint32_t), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - //exit(1); - } - } - - // load model.options.S -------------------------------------------------- - p_int = (int*)malloc(4*M*sizeof(int)); - tst->data.options.S = (int*)malloc(4*M*sizeof(int)); - if (fread(p_int, 4*M*sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - //exit(1); - } - for (int i = 0; i < 4*M; ++i) - { - tst->data.options.S[i] = p_int[i]; - } - free(p_int); - - // load model.options.PsiG ----------------------------------------------- - FLANDMARK_PSIG * PsiGi = NULL; - for (int psigs_idx = 0; psigs_idx < 3; ++psigs_idx) - { - tsize = tst->data.options.PSIG_ROWS[psigs_idx]*tst->data.options.PSIG_COLS[psigs_idx]; - - switch (psigs_idx) - { - case 0: - tst->data.options.PsiGS0 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); - PsiGi = tst->data.options.PsiGS0; - break; - case 1: - tst->data.options.PsiGS1 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); - PsiGi = tst->data.options.PsiGS1; - break; - case 2: - tst->data.options.PsiGS2 = (FLANDMARK_PSIG*)malloc(tsize*sizeof(FLANDMARK_PSIG)); - PsiGi = tst->data.options.PsiGS2; - break; - } - - for (int idx = 0; idx < tsize; ++idx) - { - // disp ROWS - p_int = (int*)malloc(sizeof(int)); - if (fread(p_int, sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - //exit(1); - } - PsiGi[idx].ROWS = p_int[0]; - free(p_int); - // disp COLS - p_int = (int*)malloc(sizeof(int)); - if (fread(p_int, sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - //exit(1); - } - PsiGi[idx].COLS = p_int[0]; - free(p_int); - // disp - tmp_tsize = PsiGi[idx].ROWS*PsiGi[idx].COLS; - PsiGi[idx].disp = (int*)malloc(tmp_tsize*sizeof(int)); - if (fread(PsiGi[idx].disp, tmp_tsize*sizeof(int), 1, fin) != 1) - { - printf( "Error reading file %s\n", filename); - return 0; - //exit(1); - } - } - } - - fclose(fin); - - tst->normalizedImageFrame = (uint8_t*)calloc(tst->data.options.bw[0]*tst->data.options.bw[1], sizeof(uint8_t)); - - tst->bb = (double*)calloc(4, sizeof(double)); - - tst->sf = (float*)calloc(2, sizeof(float)); - - return tst; + for (int idx = 0; idx < tsize; ++idx){ + // disp ROWS + p_int = (int*)malloc(sizeof(int)); + if (fread(p_int, sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + PsiGi[idx].ROWS = p_int[0]; + free(p_int); + // disp COLS + p_int = (int*)malloc(sizeof(int)); + if (fread(p_int, sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + PsiGi[idx].COLS = p_int[0]; + free(p_int); + // disp + tmp_tsize = PsiGi[idx].ROWS*PsiGi[idx].COLS; + PsiGi[idx].disp = (int*)malloc(tmp_tsize*sizeof(int)); + if (fread(PsiGi[idx].disp, tmp_tsize*sizeof(int), 1, fin) != 1) + throw std::runtime_error((boost::format("Error opening file %s") % filename).str().c_str()); + } + } + + fclose(fin); + + tst->normalizedImageFrame = (uint8_t*)calloc(tst->data.options.bw[0]*tst->data.options.bw[1], sizeof(uint8_t)); + + return tst; } EError_T flandmark_check_model(FLANDMARK_Model* model, FLANDMARK_Model* tst) { - bool flag = false; - int tsize = -1, tmp_tsize = -1; - - // check model->data.options.M - printf("Checking mode->data.options.M..."); - flag = true; - if (model->data.options.M != tst->data.options.M) - { - flag = false; - printf("\n: %d ; %d", model->data.options.M, tst->data.options.M); - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_M; - } - - int M = model->data.options.M; - - // chceck model->data.options.bw - printf("Checking mode->data.options.bw..."); - flag = true; - if (model->data.options.bw[0] != tst->data.options.bw[0] || - model->data.options.bw[1] != tst->data.options.bw[1]) - { - flag = false; - printf("\n: %d ; %d", model->data.options.bw[0], tst->data.options.bw[0]); - printf("\n: %d ; %d", model->data.options.bw[1], tst->data.options.bw[1]); - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_BW; - } - - // chceck model->data.options.bw_margin - printf("Checking mode->data.options.bw_margin..."); - flag = true; - if (model->data.options.bw_margin[0] != tst->data.options.bw_margin[0] || - model->data.options.bw_margin[1] != tst->data.options.bw_margin[1]) - { - flag = false; - printf("\n: %d ; %d", model->data.options.bw_margin[0], tst->data.options.bw_margin[0]); - printf("\n: %d ; %d", model->data.options.bw_margin[1], tst->data.options.bw_margin[1]); - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_BW_MARGIN; - } - - // check model->W - printf( "Checking model->W... "); - flag = true; - for (int i = 0; i < tst->W_ROWS; ++i) - { - if (model->W[i] != tst->W[i]) - { - flag = false; - printf( "\n%d: %f ; %f", i, model->W[i], tst->W[i]); - printf( "Error."); - } - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_W; - } - - // check model->data.mapTable - printf( "Checking model->data.mapTable... "); - flag = true; - for (int i = 0; i < M*4; ++i) - { - if (model->data.mapTable[i] != tst->data.mapTable[i]) - { - flag = false; - printf( "\n%d: %d ; %d", i, model->data.mapTable[i], tst->data.mapTable[i]); - printf( "Error."); - } - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_DATA_MAPTABLE; - } - - // load model->data.lbp --------------------------------------------------- - for (int idx = 0; idx < model->data.options.M; ++idx) - { - flag = true; - printf( "checking lbp[%d]... ", idx); - - for (int i = 0; i < 2; ++i) - { - if (tst->data.lbp[idx].winSize[i] != model->data.lbp[idx].winSize[i]) - { - flag = false; - printf( "\n%d: %d ; %d", i, model->data.lbp[idx].winSize[i], tst->data.lbp[idx].winSize[i]); - printf( "Error."); - } - } - - // lbp{idx}.hop - if (tst->data.lbp[idx].hop != model->data.lbp[idx].hop) - { - flag = false; - printf( "\n %d ; %d", model->data.lbp[idx].hop, tst->data.lbp[idx].hop); - printf( "Error."); - } - - // lbp{idx}.wins - tsize = tst->data.lbp[idx].WINS_ROWS*tst->data.lbp[idx].WINS_COLS; - for (int i = 0; i < tsize; ++i) - { - if (model->data.lbp[idx].wins[i] != tst->data.lbp[idx].wins[i]) - { - flag = false; - printf( "\n%d: %d ; %d", i, model->data.lbp[idx].wins[i], tst->data.lbp[idx].wins[i]); - printf( "Error."); - } - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_DATA_LBP; - } - } - - // check model->data.options.S - printf( "Checking model->data.options.S... "); - flag = true; - for (int i = 0; i < 4*M; ++i) - { - if (model->data.options.S[i] != tst->data.options.S[i]) - { - flag = false; - printf( "\n%d: %d ; %d", i, model->data.options.S[i], tst->data.options.S[i]); - printf("Error."); - } - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_DATA_OPTIONS_S; - } - - // check model->data.options.PsiG - FLANDMARK_PSIG *PsiGi = NULL, *PsiGiTst = NULL; - for (int psig_idx = 0; psig_idx < 3; ++psig_idx) - { - switch(psig_idx) - { - case 0: - PsiGi = (model->data.options.PsiGS0); - PsiGiTst = (tst->data.options.PsiGS0); - break; - case 1: - PsiGi = (model->data.options.PsiGS1); - PsiGiTst = (tst->data.options.PsiGS1); - break; - case 2: - PsiGi = (model->data.options.PsiGS2); - PsiGiTst = (tst->data.options.PsiGS2); - break; - } - flag = true; - printf( "Checking model->data.options.PsiGS%d\n", psig_idx); - printf( "options.PSIG_ROWS[%d]; options.PSIG_COLS[%d]... ", psig_idx, psig_idx); - if (model->data.options.PSIG_ROWS[psig_idx] != tst->data.options.PSIG_ROWS[psig_idx] || - model->data.options.PSIG_COLS[psig_idx] != tst->data.options.PSIG_COLS[psig_idx]) - { - flag = false; - printf("Error."); - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_DATA_OPTIONS_PSIG; - } - // disp - flag = true; - tsize = tst->data.options.PSIG_ROWS[psig_idx]*tst->data.options.PSIG_COLS[psig_idx]; - printf( "options.PsiGS%d...", psig_idx); - for (int idx = 0; idx < tsize; ++idx) - { - if (PsiGi[idx].ROWS != PsiGiTst[idx].ROWS || - PsiGi[idx].COLS != PsiGiTst[idx].COLS) - { + bool flag = false; + int tsize = -1, tmp_tsize = -1; + + // check model->data.options.M + printf("Checking mode->data.options.M..."); + flag = true; + if (model->data.options.M != tst->data.options.M) + { + flag = false; + printf("\n: %d ; %d", model->data.options.M, tst->data.options.M); + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_M; + } + + int M = model->data.options.M; + + // chceck model->data.options.bw + printf("Checking mode->data.options.bw..."); + flag = true; + if (model->data.options.bw[0] != tst->data.options.bw[0] || + model->data.options.bw[1] != tst->data.options.bw[1]) + { + flag = false; + printf("\n: %d ; %d", model->data.options.bw[0], tst->data.options.bw[0]); + printf("\n: %d ; %d", model->data.options.bw[1], tst->data.options.bw[1]); + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_BW; + } + + // chceck model->data.options.bw_margin + printf("Checking mode->data.options.bw_margin..."); + flag = true; + if (model->data.options.bw_margin[0] != tst->data.options.bw_margin[0] || + model->data.options.bw_margin[1] != tst->data.options.bw_margin[1]) + { + flag = false; + printf("\n: %d ; %d", model->data.options.bw_margin[0], tst->data.options.bw_margin[0]); + printf("\n: %d ; %d", model->data.options.bw_margin[1], tst->data.options.bw_margin[1]); + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_BW_MARGIN; + } + + // check model->W + printf( "Checking model->W... "); + flag = true; + for (int i = 0; i < tst->W_ROWS; ++i) + { + if (model->W[i] != tst->W[i]) + { + flag = false; + printf( "\n%d: %f ; %f", i, model->W[i], tst->W[i]); + printf( "Error."); + } + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_W; + } + + // check model->data.mapTable + printf( "Checking model->data.mapTable... "); + flag = true; + for (int i = 0; i < M*4; ++i) + { + if (model->data.mapTable[i] != tst->data.mapTable[i]) + { + flag = false; + printf( "\n%d: %d ; %d", i, model->data.mapTable[i], tst->data.mapTable[i]); + printf( "Error."); + } + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_DATA_MAPTABLE; + } + + // load model->data.lbp --------------------------------------------------- + for (int idx = 0; idx < model->data.options.M; ++idx) + { + flag = true; + printf( "checking lbp[%d]... ", idx); + + for (int i = 0; i < 2; ++i) + { + if (tst->data.lbp[idx].winSize[i] != model->data.lbp[idx].winSize[i]) + { + flag = false; + printf( "\n%d: %d ; %d", i, model->data.lbp[idx].winSize[i], tst->data.lbp[idx].winSize[i]); + printf( "Error."); + } + } + + // lbp{idx}.hop + if (tst->data.lbp[idx].hop != model->data.lbp[idx].hop) + { + flag = false; + printf( "\n %d ; %d", model->data.lbp[idx].hop, tst->data.lbp[idx].hop); + printf( "Error."); + } + + // lbp{idx}.wins + tsize = tst->data.lbp[idx].WINS_ROWS*tst->data.lbp[idx].WINS_COLS; + for (int i = 0; i < tsize; ++i) + { + if (model->data.lbp[idx].wins[i] != tst->data.lbp[idx].wins[i]) + { + flag = false; + printf( "\n%d: %d ; %d", i, model->data.lbp[idx].wins[i], tst->data.lbp[idx].wins[i]); + printf( "Error."); + } + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_DATA_LBP; + } + } + + // check model->data.options.S + printf( "Checking model->data.options.S... "); + flag = true; + for (int i = 0; i < 4*M; ++i) + { + if (model->data.options.S[i] != tst->data.options.S[i]) + { + flag = false; + printf( "\n%d: %d ; %d", i, model->data.options.S[i], tst->data.options.S[i]); + printf("Error."); + } + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_DATA_OPTIONS_S; + } + + // check model->data.options.PsiG + FLANDMARK_PSIG *PsiGi = NULL, *PsiGiTst = NULL; + for (int psig_idx = 0; psig_idx < 3; ++psig_idx) + { + switch(psig_idx) + { + case 0: + PsiGi = (model->data.options.PsiGS0); + PsiGiTst = (tst->data.options.PsiGS0); + break; + case 1: + PsiGi = (model->data.options.PsiGS1); + PsiGiTst = (tst->data.options.PsiGS1); + break; + case 2: + PsiGi = (model->data.options.PsiGS2); + PsiGiTst = (tst->data.options.PsiGS2); + break; + } + flag = true; + printf( "Checking model->data.options.PsiGS%d\n", psig_idx); + printf( "options.PSIG_ROWS[%d]; options.PSIG_COLS[%d]... ", psig_idx, psig_idx); + if (model->data.options.PSIG_ROWS[psig_idx] != tst->data.options.PSIG_ROWS[psig_idx] || + model->data.options.PSIG_COLS[psig_idx] != tst->data.options.PSIG_COLS[psig_idx]) + { + flag = false; + printf("Error."); + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_DATA_OPTIONS_PSIG; + } + // disp + flag = true; + tsize = tst->data.options.PSIG_ROWS[psig_idx]*tst->data.options.PSIG_COLS[psig_idx]; + printf( "options.PsiGS%d...", psig_idx); + for (int idx = 0; idx < tsize; ++idx) + { + if (PsiGi[idx].ROWS != PsiGiTst[idx].ROWS || + PsiGi[idx].COLS != PsiGiTst[idx].COLS) + { printf( "\nPsiGS%d[%d].ROWS\n", psig_idx, idx); - flag = false; - printf("Error."); - } - tmp_tsize = PsiGiTst[idx].ROWS*PsiGiTst[idx].COLS; - for (int i = 0; i < tmp_tsize; ++i) - { - if (PsiGi[idx].disp[i] != PsiGiTst[idx].disp[i]) - { - flag = false; - printf( "\nPsiGS%d[%d] = %d; %d\n", psig_idx, idx, PsiGi[idx].disp[i], PsiGiTst[idx].disp[i]); - printf( "Error."); - } - } - } - flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); - if (!flag) - { - return ERROR_DATA_OPTIONS_PSIG; - } - } - return NO_ERR; + flag = false; + printf("Error."); + } + tmp_tsize = PsiGiTst[idx].ROWS*PsiGiTst[idx].COLS; + for (int i = 0; i < tmp_tsize; ++i) + { + if (PsiGi[idx].disp[i] != PsiGiTst[idx].disp[i]) + { + flag = false; + printf( "\nPsiGS%d[%d] = %d; %d\n", psig_idx, idx, PsiGi[idx].disp[i], PsiGiTst[idx].disp[i]); + printf( "Error."); + } + } + } + flag == true ? printf( "passed. \n") : printf( "NOT passed.\n"); + if (!flag) + { + return ERROR_DATA_OPTIONS_PSIG; + } + } + return NO_ERR; } void flandmark_free(FLANDMARK_Model* model) { - FLANDMARK_PSIG *PsiGi = NULL; - for (int psig_idx = 0; psig_idx < 3; ++psig_idx) - { - switch(psig_idx) - { - case 0: - PsiGi = (model->data.options.PsiGS0); - break; - case 1: - PsiGi = (model->data.options.PsiGS1); - break; - case 2: - PsiGi = (model->data.options.PsiGS2); - break; - } - - int tsize = model->data.options.PSIG_ROWS[psig_idx] * model->data.options.PSIG_COLS[psig_idx]; - for (int i = 0; i < tsize; ++i) - { - free(PsiGi[i].disp); - } - free(PsiGi); - } - - free(model->W); - for (int i = 0; i < model->data.options.M; ++i) - { - free(model->data.lbp[i].wins); - } - free(model->data.lbp); - free(model->data.options.S); - free(model->data.mapTable); - - //if (model->croppedImage) - // cvReleaseImage(&model->croppedImage); - - //if (model->resizedImage) - // cvReleaseImage(&model->resizedImage); - - if (model->normalizedImageFrame) - free(model->normalizedImageFrame); - - if (model->bb) - free(model->bb); - - if (model->sf) - free(model->sf); - - free(model); + FLANDMARK_PSIG *PsiGi = NULL; + for (int psig_idx = 0; psig_idx < 3; ++psig_idx) + { + switch(psig_idx) + { + case 0: + PsiGi = (model->data.options.PsiGS0); + break; + case 1: + PsiGi = (model->data.options.PsiGS1); + break; + case 2: + PsiGi = (model->data.options.PsiGS2); + break; + } + + int tsize = model->data.options.PSIG_ROWS[psig_idx] * model->data.options.PSIG_COLS[psig_idx]; + for (int i = 0; i < tsize; ++i) + { + free(PsiGi[i].disp); + } + free(PsiGi); + } + + free(model->W); + for (int i = 0; i < model->data.options.M; ++i) + { + free(model->data.lbp[i].wins); + } + free(model->data.lbp); + free(model->data.options.S); + free(model->data.mapTable); + + if (model->normalizedImageFrame) + free(model->normalizedImageFrame); + + free(model); } void flandmark_get_psi_mat(FLANDMARK_PSI* Psi, FLANDMARK_Model* model, int lbpidx) { - char * Features; - const uint8_t * Images = model->normalizedImageFrame; - uint32_t im_H = (uint32_t)model->data.imSize[0]; uint32_t im_W = (uint32_t)model->data.imSize[1]; - const uint32_t * Wins = model->data.lbp[lbpidx].wins; - uint16_t win_H = (uint16_t)model->data.lbp[lbpidx].winSize[0]; uint16_t win_W = (uint16_t)model->data.lbp[lbpidx].winSize[1]; - uint16_t nPyramids = model->data.lbp[lbpidx].hop; - uint32_t nDim = liblbp_pyr_get_dim(win_H, win_W, nPyramids); uint32_t nData = model->data.lbp[lbpidx].WINS_COLS; - - Features = (char*)calloc(nDim*nData, sizeof(char)); - if (Features == NULL) - { - printf( "Not enough memory for LBP features.\n"); - exit(1); - } - Psi->PSI_ROWS = nDim; Psi->PSI_COLS = nData; - - uint32_t cnt0, mirror, x, x1, y, y1, idx, *win; - const uint8_t *img_ptr; - - win = (uint32_t*)malloc(win_H*win_W*sizeof(uint32_t)); - if(win == NULL) - { - printf( "Not enough memory for cropped_window.\n"); - exit(1); - } - - for(uint32_t i = 0; i < nData; ++i) - { - idx = Wins[INDEX(0,i,4)]-1; - x1 = Wins[INDEX(1,i,4)]-1; - y1 = Wins[INDEX(2,i,4)]-1; - mirror = Wins[INDEX(3,i,4)]; - - img_ptr = &Images[idx*im_H*im_W]; - - cnt0 = 0; - - if(mirror == 0) - { - for(x=x1; x < x1+win_W; x++) - for(y=y1; y < y1+win_H; y++) - win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; - } else { - for(x=x1+win_W-1; x >= x1; x--) - for(y=y1; y < y1+win_H; y++) - win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; - } - liblbp_pyr_features(&Features[nDim*i], nDim, win, win_H, win_W); - } - free(win); - - Psi->data = Features; + char * Features; + const uint8_t * Images = model->normalizedImageFrame; + uint32_t im_H = (uint32_t)model->data.imSize[0]; uint32_t im_W = (uint32_t)model->data.imSize[1]; + const uint32_t * Wins = model->data.lbp[lbpidx].wins; + uint16_t win_H = (uint16_t)model->data.lbp[lbpidx].winSize[0]; uint16_t win_W = (uint16_t)model->data.lbp[lbpidx].winSize[1]; + uint16_t nPyramids = model->data.lbp[lbpidx].hop; + uint32_t nDim = liblbp_pyr_get_dim(win_H, win_W, nPyramids); uint32_t nData = model->data.lbp[lbpidx].WINS_COLS; + + Features = (char*)calloc(nDim*nData, sizeof(char)); + if (Features == NULL) + throw std::runtime_error("Not enough memory for LBP features."); + Psi->PSI_ROWS = nDim; Psi->PSI_COLS = nData; + + uint32_t cnt0, mirror, x, x1, y, y1, idx, *win; + const uint8_t *img_ptr; + + win = (uint32_t*)malloc(win_H*win_W*sizeof(uint32_t)); + if(win == NULL) + throw std::runtime_error("Not enough memory for cropped_window."); + + for(uint32_t i = 0; i < nData; ++i) + { + idx = Wins[INDEX(0,i,4)]-1; + x1 = Wins[INDEX(1,i,4)]-1; + y1 = Wins[INDEX(2,i,4)]-1; + mirror = Wins[INDEX(3,i,4)]; + + img_ptr = &Images[idx*im_H*im_W]; + + cnt0 = 0; + + if(mirror == 0) { + for(x=x1; x < x1+win_W; x++) + for(y=y1; y < y1+win_H; y++) + win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; + } else { + for(x=x1+win_W-1; x >= x1; x--) + for(y=y1; y < y1+win_H; y++) + win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; + } + liblbp_pyr_features(&Features[nDim*i], nDim, win, win_H, win_W); + } + free(win); + + Psi->data = Features; } void flandmark_get_psi_mat_sparse(FLANDMARK_PSI_SPARSE* Psi, FLANDMARK_Model* model, int lbpidx) { - t_index * Features; - uint8_t * Images = model->normalizedImageFrame; - uint32_t im_H = (uint32_t)model->data.imSize[0]; - uint32_t im_W = (uint32_t)model->data.imSize[1]; - uint32_t * Wins = model->data.lbp[lbpidx].wins; - uint16_t win_H = (uint16_t)model->data.lbp[lbpidx].winSize[0]; - uint16_t win_W = (uint16_t)model->data.lbp[lbpidx].winSize[1]; - uint16_t nPyramids = model->data.lbp[lbpidx].hop; - uint32_t nDim = liblbp_pyr_get_dim(win_H, win_W, nPyramids)/256; - uint32_t nData = model->data.lbp[lbpidx].WINS_COLS; - - uint32_t cnt0, mirror, x, x1, y, y1, idx, *win; - uint8_t *img_ptr; - - Features = (t_index*)calloc(nDim*nData, sizeof(t_index)); - if (Features == NULL) - { - printf( "Not enough memory for LBP features.\n"); - exit(1); - } - - win = (uint32_t*)calloc(win_H*win_W, sizeof(uint32_t)); - if(win == NULL) - { - printf( "Not enough memory for cropped_window.\n"); - exit(1); - } - - for(uint32_t i = 0; i < nData; ++i) - { - idx = Wins[INDEX(0,i,4)]-1; - x1 = Wins[INDEX(1,i,4)]-1; - y1 = Wins[INDEX(2,i,4)]-1; - mirror = Wins[INDEX(3,i,4)]; - - img_ptr = &Images[idx*im_H*im_W]; - - cnt0 = 0; - - if(mirror == 0) - { - for(x=x1; x < x1+win_W; x++) - for(y=y1; y < y1+win_H; y++) - win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; - } else { - for(x=x1+win_W-1; x >= x1; x--) - for(y=y1; y < y1+win_H; y++) - win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; - } - liblbp_pyr_features_sparse(&Features[nDim*i], nDim, win, win_H, win_W); - } - - Psi->PSI_COLS = nData; - Psi->PSI_ROWS = nDim; - Psi->idxs = Features; - - free(win); + t_index * Features; + uint8_t * Images = model->normalizedImageFrame; + uint32_t im_H = (uint32_t)model->data.imSize[0]; + uint32_t im_W = (uint32_t)model->data.imSize[1]; + uint32_t * Wins = model->data.lbp[lbpidx].wins; + uint16_t win_H = (uint16_t)model->data.lbp[lbpidx].winSize[0]; + uint16_t win_W = (uint16_t)model->data.lbp[lbpidx].winSize[1]; + uint16_t nPyramids = model->data.lbp[lbpidx].hop; + uint32_t nDim = liblbp_pyr_get_dim(win_H, win_W, nPyramids)/256; + uint32_t nData = model->data.lbp[lbpidx].WINS_COLS; + + uint32_t cnt0, mirror, x, x1, y, y1, idx, *win; + uint8_t *img_ptr; + + Features = (t_index*)calloc(nDim*nData, sizeof(t_index)); + if (Features == NULL) + throw std::runtime_error("Not enough memory for LBP features."); + + win = (uint32_t*)calloc(win_H*win_W, sizeof(uint32_t)); + if(win == NULL) + throw std::runtime_error("Not enough memory for cropped_window."); + + for(uint32_t i = 0; i < nData; ++i) + { + idx = Wins[INDEX(0,i,4)]-1; + x1 = Wins[INDEX(1,i,4)]-1; + y1 = Wins[INDEX(2,i,4)]-1; + mirror = Wins[INDEX(3,i,4)]; + + img_ptr = &Images[idx*im_H*im_W]; + + cnt0 = 0; + + if(mirror == 0){ + for(x=x1; x < x1+win_W; x++) + for(y=y1; y < y1+win_H; y++) + win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; + } else { + for(x=x1+win_W-1; x >= x1; x--) + for(y=y1; y < y1+win_H; y++) + win[cnt0++] = img_ptr[INDEX(y,x,im_H)]; + } + liblbp_pyr_features_sparse(&Features[nDim*i], nDim, win, win_H, win_W); + } + + Psi->PSI_COLS = nData; + Psi->PSI_ROWS = nDim; + Psi->idxs = Features; + + free(win); } void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTable, FLANDMARK_PSI_SPARSE *Psi_sparse, double **q, double **g) @@ -776,39 +692,35 @@ void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTa double * s1 = (double *)calloc(2*q1_length, sizeof(double)); double * s1_maxs = (double *)calloc(q1_length, sizeof(double)); - for (int i = 0; i < q1_length; ++i) - { - // dot product <g_5, PsiGS1> - flandmark_maximize_gdotprod( - //s2_maxs, s2_idxs, - &s1[INDEX(0, i, 2)], (double*)&s1[INDEX(1, i, 2)], - q[5], g[4], options->PsiGS1[INDEX(i, 0, options->PSIG_ROWS[1])].disp, - options->PsiGS1[INDEX(i, 0, options->PSIG_ROWS[1])].COLS, tsize - ); - s1[INDEX(0, i, 2)] += q[1][i]; + for (int i = 0; i < q1_length; ++i) { + // dot product <g_5, PsiGS1> + flandmark_maximize_gdotprod( + //s2_maxs, s2_idxs, + &s1[INDEX(0, i, 2)], (double*)&s1[INDEX(1, i, 2)], + q[5], g[4], options->PsiGS1[INDEX(i, 0, options->PSIG_ROWS[1])].disp, + options->PsiGS1[INDEX(i, 0, options->PSIG_ROWS[1])].COLS, tsize + ); + s1[INDEX(0, i, 2)] += q[1][i]; } - for (int i = 0; i < q1_length; ++i) - { - s1_maxs[i] = s1[INDEX(0, i, 2)]; + for (int i = 0; i < q1_length; ++i) { + s1_maxs[i] = s1[INDEX(0, i, 2)]; } // right branch (s2->s6) - store maximum and index of s6 for all positions of s2 int q2_length = Psi_sparse[2].PSI_COLS; double * s2 = (double *)calloc(2*q2_length, sizeof(double)); double * s2_maxs = (double *)calloc(q2_length, sizeof(double)); - for (int i = 0; i < q2_length; ++i) - { - // dot product <g_6, PsiGS2> - flandmark_maximize_gdotprod( - //s2_maxs, s2_idxs, - &s2[INDEX(0, i, 2)], (double*)&s2[INDEX(1, i, 2)], - q[6], g[5], options->PsiGS2[INDEX(i, 0, options->PSIG_ROWS[2])].disp, - options->PsiGS2[INDEX(i, 0, options->PSIG_ROWS[2])].COLS, tsize); - s2[INDEX(0, i, 2)] += q[2][i]; + for (int i = 0; i < q2_length; ++i){ + // dot product <g_6, PsiGS2> + flandmark_maximize_gdotprod( + //s2_maxs, s2_idxs, + &s2[INDEX(0, i, 2)], (double*)&s2[INDEX(1, i, 2)], + q[6], g[5], options->PsiGS2[INDEX(i, 0, options->PSIG_ROWS[2])].disp, + options->PsiGS2[INDEX(i, 0, options->PSIG_ROWS[2])].COLS, tsize); + s2[INDEX(0, i, 2)] += q[2][i]; } - for (int i = 0; i < q2_length; ++i) - { - s2_maxs[i] = s2[INDEX(0, i, 2)]; + for (int i = 0; i < q2_length; ++i){ + s2_maxs[i] = s2[INDEX(0, i, 2)]; } // the root s0 and its connections @@ -816,8 +728,7 @@ void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTa double maxs0 = -FLT_MAX; int maxs0_idx = -1; double maxq10 = -FLT_MAX, maxq20 = -FLT_MAX, maxq30 = -FLT_MAX, maxq40 = -FLT_MAX, maxq70 = -FLT_MAX; double * s0 = (double *)calloc(M*q0_length, sizeof(double)); - for (int i = 0; i < q0_length; ++i) - { + for (int i = 0; i < q0_length; ++i){ // q10 maxq10 = -FLT_MAX; flandmark_maximize_gdotprod( @@ -851,17 +762,15 @@ void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTa q[7], g[6], options->PsiGS0[INDEX(i, 4, options->PSIG_ROWS[0])].disp, options->PsiGS0[INDEX(i, 4, options->PSIG_ROWS[0])].COLS, tsize); // sum q10+q20+q30+q40+q70 - if (maxs0 < maxq10+maxq20+maxq30+maxq40+maxq70+q[0][i]) - { - maxs0_idx = i; - s0[INDEX(0, i, M)] = i; - maxs0 = maxq10+maxq20+maxq30+maxq40+maxq70+q[0][i]; + if (maxs0 < maxq10+maxq20+maxq30+maxq40+maxq70+q[0][i]){ + maxs0_idx = i; + s0[INDEX(0, i, M)] = i; + maxs0 = maxq10+maxq20+maxq30+maxq40+maxq70+q[0][i]; } } // get indices - for (int i = 0; i < M; ++i) - { + for (int i = 0; i < M; ++i){ indices[i] = (int)s0[INDEX(0, maxs0_idx, M)+i]+1; } @@ -873,235 +782,183 @@ void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTa // convert 1D indices to 2D coordinates of estimated positions //int * optionsS = &options->S[0]; const int * optionsS = options->S; - for (int i = 0; i < M; ++i) - { + for (int i = 0; i < M; ++i){ int rows = optionsS[INDEX(3, i, 4)] - optionsS[INDEX(1, i, 4)] + 1; - smax[INDEX(0, i, 2)] = float(COL(indices[i], rows) + optionsS[INDEX(0, i, 4)]); - smax[INDEX(1, i, 2)] = float(ROW(indices[i], rows) + optionsS[INDEX(1, i, 4)]); + // MG: changed order of returned landmarks to be (y,x) + smax[INDEX(1, i, 2)] = float(COL(indices[i], rows) + optionsS[INDEX(0, i, 4)]); + smax[INDEX(0, i, 2)] = float(ROW(indices[i], rows) + optionsS[INDEX(1, i, 4)]); } free(indices); } -int flandmark_detect_base(uint8_t* face_image, FLANDMARK_Model* model, double * landmarks) +void flandmark_detect_base(uint8_t* face_image, FLANDMARK_Model* model, double* landmarks) { - const int M = model->data.options.M; - const double * W = model->W; - int tsize = -1, cols = -1, rows = -1; - const int * mapTable = model->data.mapTable; - - if (!model->normalizedImageFrame) - { - model->normalizedImageFrame = face_image; - } else { - // - } - - // get PSI matrix - FLANDMARK_PSI_SPARSE * Psi_sparse = (FLANDMARK_PSI_SPARSE*)malloc(M*sizeof(FLANDMARK_PSI_SPARSE)); - for (int idx = 0; idx < M; ++idx) - { - flandmark_get_psi_mat_sparse(&Psi_sparse[idx], model, idx); - } - - // get Q and G - double ** q = (double**)calloc(M, sizeof(double*)); - double ** g = (double**)calloc((M-1), sizeof(double*)); - - int idx_qtemp = 0; - - for (int idx = 0; idx < M; ++idx) - { - // Q - tsize = mapTable[INDEX(idx, 1, M)] - mapTable[INDEX(idx, 0, M)] + 1; - - double * q_temp = (double*)calloc(tsize, sizeof(double)); - memcpy(q_temp, W+mapTable[INDEX(idx, 0, M)]-1, tsize*sizeof(double)); - - // sparse dot product <W_q, PSI_q> - cols = Psi_sparse[idx].PSI_COLS; rows = Psi_sparse[idx].PSI_ROWS; - uint32_t *psi_temp = Psi_sparse[idx].idxs; - q[idx] = (double*)malloc(cols*sizeof(double)); - for (int i = 0; i < cols; ++i) - { - double dotprod = 0.0f; - for (int j = 0; j < rows; ++j) - { - idx_qtemp = psi_temp[(rows*i) + j]; - dotprod += q_temp[ idx_qtemp ]; - } - q[idx][i] = dotprod; - } - free(q_temp); - - // G - if (idx > 0) - { - tsize = mapTable[INDEX(idx, 3, M)] - mapTable[INDEX(idx, 2, M)] + 1; - g[idx - 1] = (double*)malloc(tsize*sizeof(double)); - memcpy(g[idx - 1], W+mapTable[INDEX(idx, 2, M)]-1, tsize*sizeof(double)); - } - } + const int M = model->data.options.M; + const double * W = model->W; + int tsize = -1, cols = -1, rows = -1; + const int * mapTable = model->data.mapTable; + + if (!model->normalizedImageFrame) + { + model->normalizedImageFrame = face_image; + } + + // get PSI matrix + FLANDMARK_PSI_SPARSE * Psi_sparse = (FLANDMARK_PSI_SPARSE*)malloc(M*sizeof(FLANDMARK_PSI_SPARSE)); + for (int idx = 0; idx < M; ++idx) + { + flandmark_get_psi_mat_sparse(&Psi_sparse[idx], model, idx); + } + + // get Q and G + double ** q = (double**)calloc(M, sizeof(double*)); + double ** g = (double**)calloc((M-1), sizeof(double*)); + + int idx_qtemp = 0; + + for (int idx = 0; idx < M; ++idx) + { + // Q + tsize = mapTable[INDEX(idx, 1, M)] - mapTable[INDEX(idx, 0, M)] + 1; + + double * q_temp = (double*)calloc(tsize, sizeof(double)); + memcpy(q_temp, W+mapTable[INDEX(idx, 0, M)]-1, tsize*sizeof(double)); + + // sparse dot product <W_q, PSI_q> + cols = Psi_sparse[idx].PSI_COLS; rows = Psi_sparse[idx].PSI_ROWS; + uint32_t *psi_temp = Psi_sparse[idx].idxs; + q[idx] = (double*)malloc(cols*sizeof(double)); + for (int i = 0; i < cols; ++i) + { + double dotprod = 0.0f; + for (int j = 0; j < rows; ++j) + { + idx_qtemp = psi_temp[(rows*i) + j]; + dotprod += q_temp[ idx_qtemp ]; + } + q[idx][i] = dotprod; + } + free(q_temp); + + // G + if (idx > 0) + { + tsize = mapTable[INDEX(idx, 3, M)] - mapTable[INDEX(idx, 2, M)] + 1; + g[idx - 1] = (double*)malloc(tsize*sizeof(double)); + memcpy(g[idx - 1], W+mapTable[INDEX(idx, 2, M)]-1, tsize*sizeof(double)); + } + } // argmax flandmark_argmax(landmarks, &model->data.options, mapTable, Psi_sparse, q, g); - // cleanup Psi_sparse[].idxs - for (int i = 0; i < M; ++i) - { - free(Psi_sparse[i].idxs); - } - free(Psi_sparse); - - // cleanup q - for (int i = 0; i < M; ++i) - { - free(q[i]); - } - free(q); - // cleanup g - for (int i = 0; i < M - 1; ++i) - { - free(g[i]); - } - free(g); - - return 0; + // cleanup Psi_sparse[].idxs + for (int i = 0; i < M; ++i) + { + free(Psi_sparse[i].idxs); + } + free(Psi_sparse); + + // cleanup q + for (int i = 0; i < M; ++i) + { + free(q[i]); + } + free(q); + // cleanup g + for (int i = 0; i < M - 1; ++i) + { + free(g[i]); + } + free(g); + } -int flandmark_detect(IplImage *img, int *bbox, FLANDMARK_Model *model, double *landmarks, int *bw_margin) +void flandmark_detect(const blitz::Array<uint8_t,2>& image, int* bbox, FLANDMARK_Model *model, double *landmarks, int *bw_margin) { - int retval = 0; - - if (bw_margin) - { - model->data.options.bw_margin[0] = bw_margin[0]; - model->data.options.bw_margin[1] = bw_margin[1]; - } + if (bw_margin) + { + model->data.options.bw_margin[0] = bw_margin[0]; + model->data.options.bw_margin[1] = bw_margin[1]; + } + + int corrected_bbx[4]; + + // Get normalized image frame + flandmark_get_normalized_image_frame(image, bbox, corrected_bbx, model->normalizedImageFrame, model); + + // Call flandmark_detect_base + flandmark_detect_base(model->normalizedImageFrame, model, landmarks); + + // transform coordinates of detected landmarks from normalized image frame back to the original image + double sx = double(corrected_bbx[3] - corrected_bbx[1]) / model->data.options.bw[0]; + double sy = double(corrected_bbx[2] - corrected_bbx[0]) / model->data.options.bw[1]; + for (int i = 0; i < 2*model->data.options.M; i+=2) + { + landmarks[i] = landmarks[i]*sy + corrected_bbx[0]; + landmarks[i+1] = landmarks[i+1]*sx + corrected_bbx[1]; + } +} - // Get normalized image frame - retval = flandmark_get_normalized_image_frame(img, bbox, model->bb, model->normalizedImageFrame, model); - if (retval) +void flandmark_maximize_gdotprod(double * maximum, double * idx, const double * first, const double * second, const int * third, const int cols, const int tsize) +{ + *maximum = -FLT_MAX; + *idx = -1; + for (int dp_i = 0; dp_i < cols; ++dp_i) + { + double dotprod = 0.0f; + for (int dp_j = 0; dp_j < tsize; ++dp_j) { - // flandmark_get_normlalized_image_frame ERROR; - return 1; + dotprod += second[dp_j]*(double)(third[dp_i*tsize+dp_j]); } - - // Call flandmark_detect_base - retval = flandmark_detect_base(model->normalizedImageFrame, model, landmarks); - if (retval) + if (*maximum < first[dp_i]+dotprod) { - // flandmark_detect_base ERROR - return 2; + *idx = dp_i; + *maximum = first[dp_i]+dotprod; } - - // transform coordinates of detected landmarks from normalized image frame back to the original image - model->sf[0] = (float)(model->bb[2]-model->bb[0])/model->data.options.bw[0]; - model->sf[1] = (float)(model->bb[3]-model->bb[1])/model->data.options.bw[1]; - for (int i = 0; i < 2*model->data.options.M; i += 2) - { - landmarks[i] = landmarks[i]*model->sf[0] + model->bb[0]; - landmarks[i+1] = landmarks[i+1]*model->sf[1] + model->bb[1]; - } - - return 0; + } } -void flandmark_maximize_gdotprod(double * maximum, double * idx, const double * first, const double * second, const int * third, const int cols, const int tsize) +void flandmark_imcrop(const blitz::Array<uint8_t, 2>& input, blitz::Array<uint8_t,2>& output, int* bbx) { - *maximum = -FLT_MAX; - *idx = -1; - for (int dp_i = 0; dp_i < cols; ++dp_i) - { - double dotprod = 0.0f; - for (int dp_j = 0; dp_j < tsize; ++dp_j) - { - dotprod += second[dp_j]*(double)(third[dp_i*tsize+dp_j]); - } - if (*maximum < first[dp_i]+dotprod) - { - *idx = dp_i; - *maximum = first[dp_i]+dotprod; - } - } -} + if (bbx[0] < 0 or bbx[2] >= input.extent(0) or bbx[1] < 0 or bbx[3] >= input.extent(1)) + throw std::runtime_error("Bounding box exceeds image resolution"); -//int flandmark_imcrop(IplImage *input, IplImage *output, const CvRect region, FLANDMARK_Model *model) -int flandmark_imcrop(IplImage *input, IplImage *output, const CvRect region) -{ - if (input->width <= 0 || input->height <= 0 || region.width <= 0 || region.height <= 0) - { - return 1; - } - - if (input->depth != IPL_DEPTH_8U) - { - return 1; - } - - cvSetImageROI(input, region); - if (output->width < region.width || output->height < region.height) - { - cvReleaseImage(&output); - output = cvCreateImage(cvSize(region.width, region.height), IPL_DEPTH_8U, 1); - } else { - output->width = region.width; - output->height = region.height; - } - cvCopy(input, output, NULL); - cvResetImageROI(input); - - return 0; + output.resize(bbx[2]-bbx[0]+1, bbx[3]-bbx[1]+1); + blitz::Range a = blitz::Range::all(); + output(a,a) = input(blitz::Range(bbx[0], bbx[2]), blitz::Range(bbx[1], bbx[3])); } -int flandmark_get_normalized_image_frame(IplImage *input, const int bbox[], double *bb, uint8_t *face_img, FLANDMARK_Model *model) +void flandmark_get_normalized_image_frame(const blitz::Array<uint8_t, 2>& input, const int bbox[], int *corrected_bbx, uint8_t *face_img, FLANDMARK_Model *model) { - bool flag; - int d[2]; - double c[2], nd[2]; - - // extend bbox by bw_margin - d[0] = bbox[2]-bbox[0]+1; d[1] = bbox[3]-bbox[1]+1; - c[0] = (bbox[2]+bbox[0])/2.0f; c[1] = (bbox[3]+bbox[1])/2.0f; - nd[0] = d[0]*model->data.options.bw_margin[0]/100.0f + d[0]; - nd[1] = d[1]*model->data.options.bw_margin[1]/100.0f + d[1]; - - bb[0] = (c[0] - nd[0]/2.0f); - bb[1] = (c[1] - nd[1]/2.0f); - bb[2] = (c[0] + nd[0]/2.0f); - bb[3] = (c[1] + nd[1]/2.0f); - - flag = bb[0] > 0 && bb[1] > 0 && bb[2] < input->width && bb[3] < input->height - && bbox[0] > 0 && bbox[1] > 0 && bbox[2] < input->width && bbox[3] < input->height; - - if (!flag) - { - return 1; - } - - IplImage *croppedImage = cvCreateImage(cvSize(input->width, input->height), IPL_DEPTH_8U, 1); - - IplImage *resizedImage = cvCreateImage(cvSize(model->data.options.bw[0], model->data.options.bw[1]), IPL_DEPTH_8U, 1); - - // crop and resize image to normalized frame - if(flandmark_imcrop(input, croppedImage, cvRect((int)bb[0], (int)bb[1], (int)bb[2]-(int)bb[0]+1, (int)bb[3]-(int)bb[1]+1))) - { - // something was bad - return 1; - } - // resize - cvResize(croppedImage, resizedImage, CV_INTER_CUBIC); - - // tranform IplImage to simple 1D uint8 array representing 2D uint8 normalized image frame - for (int x = 0; x < model->data.options.bw[0]; ++x) - { - for (int y = 0; y < model->data.options.bw[1]; ++y) - { - face_img[INDEX(x, y, model->data.options.bw[1])] = (uint8_t)((resizedImage->imageData + resizedImage->widthStep*x)[y]); - } - } - - cvReleaseImage(&croppedImage); - cvReleaseImage(&resizedImage); - - return 0; + int d[2]; + double c[2], nd[2]; + + // extend bbox by bw_margin + d[0] = bbox[2]-bbox[0]+1; + d[1] = bbox[3]-bbox[1]+1; + c[0] = (bbox[2]+bbox[0])/2.; + c[1] = (bbox[3]+bbox[1])/2.; + nd[0] = d[0]*model->data.options.bw_margin[1]/100. + d[0]; + nd[1] = d[1]*model->data.options.bw_margin[0]/100. + d[1]; + + corrected_bbx[0] = int(c[0] - nd[0]/2.); + corrected_bbx[1] = int(c[1] - nd[1]/2.); + corrected_bbx[2] = int(c[0] + nd[0]/2.); + corrected_bbx[3] = int(c[1] + nd[1]/2.); + + blitz::Array<uint8_t, 2> croppedImage; + blitz::Array<double, 2> scaledImage(model->data.options.bw[1], model->data.options.bw[0]); + + flandmark_imcrop(input, croppedImage, corrected_bbx); + bob::ip::base::scale(croppedImage, scaledImage); + + // tranform blitz array to simple 1D uint8 array representing 2D uint8 normalized image frame + for (int x = 0; x < model->data.options.bw[0]; ++x){ + for (int y = 0; y < model->data.options.bw[1]; ++y){ + face_img[INDEX(x, y, model->data.options.bw[1])] = (uint8_t)round(scaledImage(y,x)); + } + } } + +} } } // namespace bob ip flandmark diff --git a/bob/ip/flandmark/cpp/flandmark_detector.h b/bob/ip/flandmark/cpp/flandmark_detector.h index 94de22320e1e44d276d9d627ec97e62affb48363..b93f511dfea1d1ad78d6a4048883e0d5c04a746f 100644 --- a/bob/ip/flandmark/cpp/flandmark_detector.h +++ b/bob/ip/flandmark/cpp/flandmark_detector.h @@ -12,14 +12,15 @@ #define __FLANDMARK_DETECTOR_H_ #include <stdint.h> -#include <cv.h> -#include <cvaux.h> +#include <blitz/array.h> // index row-order matrices #define INDEX(ROW, COL, NUM_ROWS) ((COL)*(NUM_ROWS)+(ROW)) #define ROW(IDX, ROWS) (((IDX)-1) % (ROWS)) #define COL(IDX, ROWS) (((IDX)-1) / (ROWS)) +namespace bob { namespace ip { namespace flandmark { + typedef struct psig_struct { int * disp; int ROWS, COLS; @@ -52,8 +53,6 @@ typedef struct model_struct { int W_ROWS, W_COLS; FLANDMARK_Data data; uint8_t *normalizedImageFrame; - double *bb; - float *sf; } FLANDMARK_Model; typedef struct psi_struct { @@ -156,13 +155,13 @@ void flandmark_maximize_gdotprod(double *maximum, double *idx, const double *fir * * */ -int flandmark_get_normalized_image_frame(IplImage *input, const int bbox[], double *bb, uint8_t *face_img, FLANDMARK_Model *model); +void flandmark_get_normalized_image_frame(const blitz::Array<uint8_t,2>& input, const int bbox[], int *bb, uint8_t *face_img, FLANDMARK_Model *model); /** * Function imcrop * */ -int flandmark_imcrop(IplImage *input, IplImage *output, const CvRect region); +void flandmark_imcrop(const blitz::Array<uint8_t,2>& input, blitz::Array<double,2>& output, const int* bbx); /** * Function argmax @@ -180,7 +179,7 @@ void flandmark_argmax(double *smax, FLANDMARK_Options *options, const int *mapTa * \param[in, out] int array representing 2D array of size [2 x options.M] with estimated positions of landmarks * \return int indicator of success or fail of the detection */ -int flandmark_detect_base(uint8_t *face_image, FLANDMARK_Model *model, double *landmarks); +void flandmark_detect_base(uint8_t *face_image, FLANDMARK_Model *model, double *landmarks); /** * Function flandmark_detect @@ -188,6 +187,8 @@ int flandmark_detect_base(uint8_t *face_image, FLANDMARK_Model *model, double *l * Estimates positions of facial landmarks given the image and the bounding box of the detected face * */ -int flandmark_detect(IplImage *img, int * bbox, FLANDMARK_Model *model, double *landmarks, int * bw_margin = 0); +void flandmark_detect(const blitz::Array<uint8_t,2>& img, int * bbox, FLANDMARK_Model *model, double *landmarks, int * bw_margin = 0); + +} } } // namespace bob ip flandmark #endif // __LIBFLD_DETECTOR_H_ diff --git a/bob/ip/flandmark/flandmark.cpp b/bob/ip/flandmark/flandmark.cpp index 6aee28857aab2498088d5be4af9b701090f18efc..d7964b5bcab2efee652122f01105d9631b8177ac 100644 --- a/bob/ip/flandmark/flandmark.cpp +++ b/bob/ip/flandmark/flandmark.cpp @@ -17,7 +17,7 @@ #include <cstring> -#include "flandmark_detector.h" +#include "cpp/flandmark_detector.h" /****************************************** * Implementation of Localizer base class * @@ -26,85 +26,66 @@ #define CLASS_NAME "Flandmark" static auto s_class = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX "." CLASS_NAME, - - "A key-point localization for faces using Flandmark", - - "This class can be used to locate facial landmarks on pre-detected faces. " - "You input an image and a bounding-box specification and it returns you the " - "positions for multiple key-points for the given face image.\n" - "\n" - "Consult http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php for more " - "information.\n" - "\n" + BOB_EXT_MODULE_PREFIX "." CLASS_NAME, + + "A key-point localization for faces using Flandmark", + + "This class can be used to locate facial landmarks on pre-detected faces. " + "You input an image and a bounding-box specification and it returns you the " + "positions for multiple key-points for the given face image.\n" + "\n" + "Consult http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php for more " + "information.\n" + "\n" +) +.add_constructor( + bob::extension::FunctionDoc( + CLASS_NAME, + "Constructor", + "Initializes the key-point locator with a model." ) - .add_constructor( - bob::extension::FunctionDoc( - CLASS_NAME, - "Constructor", - "Initializes the key-point locator with a model." - ) - .add_prototype("[model]", "") - .add_parameter("model", "str (path), optional", "Path to the localization model. If not set (or set to ``None``), then use the default localization model, stored on the class variable ``__default_model__``)") - ) - ; + .add_prototype("[model]", "") + .add_parameter("model", "str (path), optional", "Path to the localization model. If not set (or set to ``None``), then use the default localization model, stored on the class variable ``__default_model__``)") +); typedef struct { PyObject_HEAD - FLANDMARK_Model* flandmark; + bob::ip::flandmark::FLANDMARK_Model* flandmark; char* filename; } PyBobIpFlandmarkObject; -static int PyBobIpFlandmark_init -(PyBobIpFlandmarkObject* self, PyObject* args, PyObject* kwds) { - +static int PyBobIpFlandmark_init(PyBobIpFlandmarkObject* self, PyObject* args, PyObject* kwds) { +BOB_TRY /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"model", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); + char** kwlist = s_class.kwlist(); - PyObject* model = 0; + const char* model = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &model)) return -1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, - &PyBobIo_FilenameConverter, &model)) return -1; - - if (!model) { //use what is stored in __default_model__ - PyObject* default_model = PyObject_GetAttrString((PyObject*)self, - "__default_model__"); + if (!model) { + //use what is stored in __default_model__ + PyObject* default_model = PyObject_GetAttrString((PyObject*)self, "_default_model"); if (!default_model) { - PyErr_Format(PyExc_RuntimeError, "`%s' needs a model to properly initialize, but the user has not passed one and `__default_model__' is not properly set", Py_TYPE(self)->tp_name); + PyErr_Format(PyExc_RuntimeError, "`%s' needs a model to properly initialize, but the user has not passed one and `_default_model' is not properly set", Py_TYPE(self)->tp_name); return -1; } + auto default_model_ = make_safe(default_model); - auto ok = PyBobIo_FilenameConverter(default_model, &model); - Py_DECREF(default_model); - - if (!ok || !model) return -1; + model = PyString_AS_STRING(default_model); } - const char* c_filename = 0; - -# if PY_VERSION_HEX >= 0x03000000 - c_filename = PyBytes_AS_STRING(model); -# else - c_filename = PyString_AS_STRING(model); -# endif - Py_DECREF(model); - - //now we have a filename we can use - if (!c_filename) return -1; - - self->flandmark = flandmark_init(c_filename); - if (!self->flandmark) { - PyErr_Format(PyExc_RuntimeError, "`%s' could not initialize from model file `%s'", Py_TYPE(self)->tp_name, c_filename); + self->flandmark = bob::ip::flandmark::flandmark_init(model); + if (!self->flandmark){ + PyErr_Format(PyExc_RuntimeError, "`%s' could not initialize from model file `%s'", Py_TYPE(self)->tp_name, model); return -1; } //flandmark is now initialized, set filename - self->filename = strndup(c_filename, 256); + self->filename = strndup(model, 256); //all good, flandmark is ready return 0; - +BOB_CATCH_MEMBER("constructor", -1) } static void PyBobIpFlandmark_delete (PyBobIpFlandmarkObject* self) { @@ -115,153 +96,79 @@ static void PyBobIpFlandmark_delete (PyBobIpFlandmarkObject* self) { Py_TYPE(self)->tp_free((PyObject*)self); } -static void delete_image(IplImage* i) { - cvReleaseImage(&i); -} - -/** - * Returns a list of key-point annotations given an image and an iterable over - * bounding boxes. - */ -static PyObject* call(PyBobIpFlandmarkObject* self, - boost::shared_ptr<IplImage> image, int nbbx, boost::shared_array<int> bbx) { - - PyObject* retval = PyTuple_New(nbbx); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (int i=0; i<nbbx; ++i) { - - //allocate output array _and_ Flandmark buffer within a single structure - Py_ssize_t shape[2]; - shape[0] = self->flandmark->data.options.M; - shape[1] = 2; - PyObject* landmarks = PyArray_SimpleNew(2, shape, NPY_FLOAT64); - if (!landmarks) return 0; - auto landmarks_ = make_safe(landmarks); - double* buffer = reinterpret_cast<double*>(PyArray_DATA((PyArrayObject*)landmarks)); - - int result = 0; - Py_BEGIN_ALLOW_THREADS - result = flandmark_detect(image.get(), &bbx[4*i], self->flandmark, buffer); - Py_END_ALLOW_THREADS - - if (result != NO_ERR) { - Py_INCREF(Py_None); - landmarks = Py_None; - } - else { - //swap keypoint coordinates (x, y) -> (y, x) - double tmp; - for (int k = 0; k < (2*self->flandmark->data.options.M); k += 2) { - tmp = buffer[k]; - buffer[k] = buffer[k+1]; - buffer[k+1] = tmp; - } - Py_INCREF(landmarks); - } - - PyTuple_SET_ITEM(retval, i, landmarks); - - } - - Py_INCREF(retval); - return retval; - -} - -static auto s_call = bob::extension::FunctionDoc( - "locate", - "Locates keypoints on a **single** facial bounding-box on the provided image." - "This method will locate 8 keypoints inside the bounding-box defined " - "for the current input image, organized in this way:\n" - "\n" - "0. Face center\n" - "1. Canthus-rl (inner corner of the right eye).\n" - "\n" - " .. note::\n" - " \n" - " The \"right eye\" means the right eye at the face w.r.t. the person " - "on the image. That is the left eye in the image, from the viewer's " - "perspective.\n" - "\n" - "2. Canthus-lr (inner corner of the left eye)\n" - "3. Mouth-corner-r (right corner of the mouth)\n" - "4. Mouth-corner-l (left corner of the mouth)\n" - "5. Canthus-rr (outer corner of the right eye)\n" - "6. Canthus-ll (outer corner of the left eye)\n" - "7. Nose\n" - "\n" - "Each point is returned as tuple defining the pixel positions in the form " - "(y, x).\n" - "\n" - ) - .add_prototype("image, y, x, height, width", "landmarks") - .add_parameter("image", "array-like (2D, uint8)", - "The image Flandmark will operate on") - .add_parameter("y, x", "int", "The top left-most corner of the bounding box containing the face image you want to locate keypoints on.") - .add_parameter("height, width", "int", "The dimensions accross ``y`` (height) and ``x`` (width) for the bounding box, in number of pixels.") - .add_return("landmarks", "array (2D, float64)", "Each row in the output array contains the locations of keypoints in the format ``(y, x)``") - ; - -static PyObject* PyBobIpFlandmark_call_single(PyBobIpFlandmarkObject* self, - PyObject *args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"image", "y", "x", "height", "width", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - PyBlitzArrayObject* image = 0; - int y = 0; - int x = 0; - int height = 0; - int width = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&iiii", kwlist, - &PyBlitzArray_Converter, &image, &y, &x, &height, &width)) return 0; +static auto s_locate = bob::extension::FunctionDoc( + "locate", + "Locates keypoints on a **single** facial bounding-box on the provided image.", + "This method will locate 8 keypoints inside the bounding-box defined for the current input image, organized in this way:\n" + "\n" + "0. Face center\n" + "1. Canthus-rl (inner corner of the right eye).\n" + "\n" + " .. note::\n" + " \n" + " The \"right eye\" means the right eye at the face w.r.t. the person on the image. " + " That is the left eye in the image, from the viewer's perspective.\n" + "\n" + "2. Canthus-lr (inner corner of the left eye)\n" + "3. Mouth-corner-r (right corner of the mouth)\n" + "4. Mouth-corner-l (left corner of the mouth)\n" + "5. Canthus-rr (outer corner of the right eye)\n" + "6. Canthus-ll (outer corner of the left eye)\n" + "7. Nose\n" + "\n" + "Each point is returned as tuple defining the pixel positions in the form ``(y, x)``.", + true +) +.add_prototype("image, y, x, height, width", "landmarks") +.add_parameter("image", "array-like (2D, uint8)", "The image Flandmark will operate on") +.add_parameter("y, x", "int", "The top left-most corner of the bounding box containing the face image you want to locate keypoints on.") +.add_parameter("height, width", "int", "The dimensions accross ``y`` (height) and ``x`` (width) for the bounding box, in number of pixels.") +.add_return("landmarks", "array (2D, float64)", "Each row in the output array contains the locations of keypoints in the format ``(y, x)``") +; + +static PyObject* PyBobIpFlandmark_locate(PyBobIpFlandmarkObject* self, PyObject *args, PyObject* kwds) { +BOB_TRY + char** kwlist = s_locate.kwlist(); + + PyBlitzArrayObject* image; + int bbx[4]; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&iiii", kwlist, &PyBlitzArray_Converter, &image, &bbx[0], &bbx[1], &bbx[2], &bbx[3])) return 0; + + // create bounding box in format (top, left, bottom, right) + bbx[2] += bbx[0] - 1; + bbx[3] += bbx[1] - 1; auto image_ = make_safe(image); - //check + // check if (image->type_num != NPY_UINT8 || image->ndim != 2) { PyErr_Format(PyExc_TypeError, "`%s' input `image' data must be a 2D array with dtype `uint8' (i.e. a gray-scaled image), but you passed a %" PY_FORMAT_SIZE_T "d array with data type `%s'", Py_TYPE(self)->tp_name, image->ndim, PyBlitzArray_TypenumAsString(image->type_num)); return 0; } - // converts to OpenCV's IplImage - boost::shared_ptr<IplImage> cv_image(cvCreateImage(cvSize(image->shape[1], image->shape[0]), IPL_DEPTH_8U, 1), std::ptr_fun(delete_image)); + // detect + std::vector<double> detected(2*self->flandmark->data.options.M); + bob::ip::flandmark::flandmark_detect(*PyBlitzArrayCxx_AsBlitz<uint8_t, 2>(image), bbx, self->flandmark, &detected[0]); - // copy image data aligned (see http://chi3x10.wordpress.com/2008/05/07/be-aware-of-memory-alignment-of-iplimage-in-opencv) - for (int yy = 0; yy < image->shape[0]; ++yy) - std::copy(reinterpret_cast<char*>(image->data) + yy * image->shape[1], reinterpret_cast<char*>(image->data) + (yy+1) * image->shape[1], cv_image->imageData + yy * cv_image->widthStep); - - //prepares the bbx vector - boost::shared_array<int> bbx(new int[4]); - bbx[0] = x; - bbx[1] = y; - bbx[2] = x + width; - bbx[3] = y + height; - - PyObject* retval = call(self, cv_image, 1, bbx); - if (!retval) return 0; - - //gets the first entry, return it - PyObject* retval0 = PyTuple_GET_ITEM(retval, 0); - if (!retval0) return 0; - - Py_INCREF(retval0); - Py_DECREF(retval); - - return retval0; + // extract landmarks + blitz::Array<double, 2> landmarks(self->flandmark->data.options.M, 2); + for (int k = 0; k < self->flandmark->data.options.M; ++k){ + landmarks(k,0) = detected[2*k]; + landmarks(k,1) = detected[2*k+1]; + } + return PyBlitzArrayCxx_AsNumpy(landmarks); +BOB_CATCH_MEMBER("locate", 0) }; static PyMethodDef PyBobIpFlandmark_methods[] = { { - s_call.name(), - (PyCFunction)PyBobIpFlandmark_call_single, + s_locate.name(), + (PyCFunction)PyBobIpFlandmark_locate, METH_VARARGS|METH_KEYWORDS, - s_call.doc() + s_locate.doc() }, {0} /* Sentinel */ }; @@ -274,8 +181,7 @@ PyObject* PyBobIpFlandmark_Repr(PyBobIpFlandmarkObject* self) { * <bob.ip.flandmark(model='...')> */ - PyObject* retval = PyUnicode_FromFormat("<%s(model='%s')>", - Py_TYPE(self)->tp_name, self->filename); + PyObject* retval = PyUnicode_FromFormat("<%s(model='%s')>", Py_TYPE(self)->tp_name, self->filename); #if PYTHON_VERSION_HEX < 0x03000000 if (!retval) return 0; @@ -289,40 +195,31 @@ PyObject* PyBobIpFlandmark_Repr(PyBobIpFlandmarkObject* self) { } PyTypeObject PyBobIpFlandmark_Type = { - PyVarObject_HEAD_INIT(0, 0) - s_class.name(), /* tp_name */ - sizeof(PyBobIpFlandmarkObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)PyBobIpFlandmark_delete, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)PyBobIpFlandmark_Repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)PyBobIpFlandmark_call_single, /* tp_call */ - (reprfunc)PyBobIpFlandmark_Repr, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - s_class.doc(), /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyBobIpFlandmark_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PyBobIpFlandmark_init, /* tp_init */ + PyVarObject_HEAD_INIT(0, 0) + 0 }; + +bool init_PyBobIpFlandmark(PyObject* module){ + // initialize the type struct + PyBobIpFlandmark_Type.tp_name = s_class.name(); + PyBobIpFlandmark_Type.tp_basicsize = sizeof(PyBobIpFlandmarkObject); + PyBobIpFlandmark_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyBobIpFlandmark_Type.tp_doc = s_class.doc(); + PyBobIpFlandmark_Type.tp_dict = PyDict_New(); + + // set the functions + PyBobIpFlandmark_Type.tp_new = PyType_GenericNew; + PyBobIpFlandmark_Type.tp_init = reinterpret_cast<initproc>(PyBobIpFlandmark_init); + PyBobIpFlandmark_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIpFlandmark_delete); + PyBobIpFlandmark_Type.tp_methods = PyBobIpFlandmark_methods; + PyBobIpFlandmark_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobIpFlandmark_locate); + PyBobIpFlandmark_Type.tp_str = reinterpret_cast<reprfunc>(PyBobIpFlandmark_Repr); + PyBobIpFlandmark_Type.tp_repr = reinterpret_cast<reprfunc>(PyBobIpFlandmark_Repr); + + // check that everything is fine + if (PyType_Ready(&PyBobIpFlandmark_Type) < 0) return false; + + // add the type to the module + Py_INCREF(&PyBobIpFlandmark_Type); + return PyModule_AddObject(module, "Flandmark", (PyObject*)&PyBobIpFlandmark_Type) >= 0; +} diff --git a/bob/ip/flandmark/main.cpp b/bob/ip/flandmark/main.cpp index 9a18a8049833a27c0fabd42851bb5a8b0db215f0..ab2dc82cea3ce326dc067eb4ad61b174e0b94f4f 100644 --- a/bob/ip/flandmark/main.cpp +++ b/bob/ip/flandmark/main.cpp @@ -15,24 +15,24 @@ #include <bob.extension/documentation.h> extern PyTypeObject PyBobIpFlandmark_Type; +extern bool init_PyBobIpFlandmark(PyObject*); static auto s_setter = bob::extension::FunctionDoc( - "__set_default_model__", - "Internal function to set the default model for the Flandmark class" - ) - .add_prototype("path", "") - .add_parameter("path", "str", "The path to the new model file") - ; + "_set_default_model", + "Internal function to set the default model for the Flandmark class" +) +.add_prototype("path", "") +.add_parameter("path", "str", "The path to the new model file") +; PyObject* set_flandmark_model(PyObject*, PyObject* o) { - - int ok = PyDict_SetItemString(PyBobIpFlandmark_Type.tp_dict, - "__default_model__", o); +BOB_TRY + int ok = PyDict_SetItemString(PyBobIpFlandmark_Type.tp_dict, "_default_model", o); if (ok == -1) return 0; Py_RETURN_NONE; - +BOB_CATCH_FUNCTION("_set_default_model", 0) } static PyMethodDef module_methods[] = { @@ -60,12 +60,6 @@ static PyModuleDef module_definition = { static PyObject* create_module (void) { - //makes sure that PyBobIpFlandmark_Type has a dictionary on tp_dict - PyBobIpFlandmark_Type.tp_dict = PyDict_New(); - if (!PyBobIpFlandmark_Type.tp_dict) return 0; - - PyBobIpFlandmark_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIpFlandmark_Type) < 0) return 0; # if PY_VERSION_HEX >= 0x03000000 PyObject* module = PyModule_Create(&module_definition); @@ -77,9 +71,7 @@ static PyObject* create_module (void) { # endif if (!module) return 0; - /* register the types to python */ - Py_INCREF(&PyBobIpFlandmark_Type); - if (PyModule_AddObject(module, "Flandmark", (PyObject *)&PyBobIpFlandmark_Type) < 0) return 0; + if (!init_PyBobIpFlandmark(module)) return 0; /* imports dependencies */ if (import_bob_blitz() < 0) return 0; diff --git a/bob/ip/flandmark/test.py b/bob/ip/flandmark/test.py index bed454ef0c6d9839e2d1358cd1bfcec880e1a756..61c9e7f8dc36f7302f560b809ce6a68b78d06544 100644 --- a/bob/ip/flandmark/test.py +++ b/bob/ip/flandmark/test.py @@ -33,23 +33,6 @@ MULTI_BBX = [ [253, 42, 28, 28], ] #from OpenCV's cascade detector -def opencv_detect(image): - """Detects a face using OpenCV's cascade detector - - Returns a list of arrays containing (x, y, width, height) for each detected - face. - """ - - from cv2 import CascadeClassifier - - cc = CascadeClassifier(F('haarcascade_frontalface_alt.xml')) - return cc.detectMultiScale( - image, - 1.3, #scaleFactor (at each time the image is re-scaled) - 4, #minNeighbors (around candidate to be retained) - 0, #flags (normally, should be set to zero) - (20,20), #(minSize, maxSize) (of detected objects on that scale) - ) def pnpoly(point, vertices): """Python translation of the C algorithm taken from: @@ -80,19 +63,6 @@ def is_inside(point, box, eps=1e-5): ], dtype=float) return pnpoly((point[1], point[0]), vertices) -def opencv_available(test): - """Decorator for detecting if OpenCV/Python bindings are available""" - from nose.plugins.skip import SkipTest - - @functools.wraps(test) - def wrapper(*args, **kwargs): - try: - import cv2 - return test(*args, **kwargs) - except ImportError: - raise SkipTest("The cv2 module is not available") - - return wrapper def test_is_inside(): @@ -117,19 +87,6 @@ def test_is_outside(): assert not is_inside((1.5, 1.5), box, eps=1e-10) assert not is_inside((-0.5, -0.5), box, eps=1e-10) -@opencv_available -def test_lena_opencv(): - - img = bob.io.base.load(LENA) - gray = bob.ip.color.rgb_to_gray(img) - (x, y, width, height) = opencv_detect(gray)[0] - - flm = Flandmark() - keypoints = flm.locate(gray, y, x, height, width) - nose.tools.eq_(keypoints.shape, (8, 2)) - nose.tools.eq_(keypoints.dtype, 'float64') - for k in keypoints: - assert is_inside(k, (y, x, height, width), eps=1) def test_lena(): @@ -144,21 +101,6 @@ def test_lena(): for k in keypoints: assert is_inside(k, (y, x, height, width), eps=1) -@opencv_available -def test_multi_opencv(): - - img = bob.io.base.load(MULTI) - gray = bob.ip.color.rgb_to_gray(img) - bbx = opencv_detect(gray) - - flm = Flandmark() - for (x, y, width, height) in bbx: - keypoints = flm.locate(gray, y, x, height, width) - nose.tools.eq_(keypoints.shape, (8, 2)) - nose.tools.eq_(keypoints.dtype, 'float64') - for k in keypoints: - assert is_inside(k, (y, x, height, width), eps=1) - def test_multi(): img = bob.io.base.load(MULTI) diff --git a/bob/ip/flandmark/version.cpp b/bob/ip/flandmark/version.cpp index d8b969f19e0dab7fef8d089d3df9c963a8ba915f..254e0167c14620742e9f79e1c61a011e6f900f7a 100644 --- a/bob/ip/flandmark/version.cpp +++ b/bob/ip/flandmark/version.cpp @@ -12,8 +12,6 @@ #include <bob.core/config.h> #include <bob.io.base/config.h> -#include <cv.h> - static PyObject* build_version_dictionary() { @@ -21,7 +19,6 @@ static PyObject* build_version_dictionary() { if (!retval) return 0; auto retval_ = make_safe(retval); - if (!dict_steal(retval, "OpenCV", Py_BuildValue("s", CV_VERSION))) return 0; if (!dict_steal(retval, "Blitz++", blitz_version())) return 0; if (!dict_steal(retval, "Boost", boost_version())) return 0; if (!dict_steal(retval, "Compiler", compiler_version())) return 0; diff --git a/setup.py b/setup.py index fa1d32849d5ed3877c3f9372b49df44cedc8a9b2..9dbb352e4565af3ff01764f98d7296744422382f 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ """Bindings for flandmark """ -bob_packages = ['bob.core', 'bob.io.base'] +bob_packages = ['bob.core', 'bob.io.base', 'bob.sp', 'bob.ip.base'] from setuptools import setup, find_packages, dist dist.Distribution(dict(setup_requires=['bob.extension', 'bob.blitz'] + bob_packages)) @@ -18,7 +18,7 @@ build_requires = load_requirements() # Define package version version = open("version.txt").read().rstrip() -packages = ['boost', "opencv>=2.0"] +packages = ['boost'] boost_modules = ['system'] setup( @@ -39,8 +39,6 @@ setup( setup_requires = build_requires, install_requires = build_requires, - - ext_modules=[ Extension("bob.ip.flandmark.version", [ @@ -54,8 +52,8 @@ setup( Extension("bob.ip.flandmark._library", [ - "bob/ip/flandmark/flandmark_detector.cpp", - "bob/ip/flandmark/liblbp.cpp", + "bob/ip/flandmark/cpp/flandmark_detector.cpp", + "bob/ip/flandmark/cpp/liblbp.cpp", "bob/ip/flandmark/flandmark.cpp", "bob/ip/flandmark/main.cpp", ], diff --git a/version.txt b/version.txt index 0d0f1af82bee4308f9e49b2adb6e4aa498bda98a..1a78b34537ab70360822a5d0733a88ab70b02247 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.4b0 \ No newline at end of file +2.1.0b0