Commit 6b5c39957ab3caf12c9b7c0aa6594f843ef1de9d

Authored by bklare
2 parents 50f1dd39 c73a5623

Merge branch 'master' of https://github.com/biometrics/openbr

Showing 48 changed files with 635 additions and 560 deletions
3rdparty/stasm/stasm/CMakeLists.txt deleted
1 -# Stasm CMakeLists  
2 -  
3 -aux_source_directory(stasm/src STASM_SRC)  
4 -include_directories(stasm/include)  
5 -  
6 -#aux_source_directory(tasm/src TASM_SRC)  
7 -#include_directories(tasm/include)  
8 -  
9 -add_library(stasm SHARED ${STASM_SRC} ${TASM_SRC})  
10 -qt5_use_modules(stasm ${QT_DEPENDENCIES})  
11 -  
12 -set_target_properties(stasm PROPERTIES  
13 - DEFINE_SYMBOL STASM_LIBRARY  
14 - VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}  
15 - SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}  
16 - LINK_INTERFACE_LIBRARIES ""  
17 - AUTOMOC TRUE)  
18 -  
19 -target_link_libraries(stasm ${OpenCV_LIBS} ${Qt5Core_QTMAIN_LIBRARIES})  
20 -  
21 -file(GLOB STASM_HEADERS stasm/include/*.h)  
22 -install(FILES ${STASM_HEADERS} DESTINATION include/stasm)  
23 -file(GLOB CLASSIC_HEADERS stasm/include/classic/*.mh)  
24 -install(FILES ${CLASSIC_HEADERS} DESTINATION include/stasm/classic)  
25 -file(GLOB HAT_HEADERS stasm/include/hat/*.mh)  
26 -install(FILES ${HAT_HEADERS} DESTINATION include/stasm/hat)  
27 -#file(GLOB TASM_HEADERS tasm/include/*.h)  
28 -#install(FILES ${TASM_HEADERS} DESTINATION include/tasm)  
29 -  
30 -install(TARGETS stasm RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)  
3rdparty/stasm/stasm/stasm/src/print.cpp deleted
1 -// print.cpp: printing and logging utilities for the Stasm library  
2 -//  
3 -// Copyright (C) 2005-2013, Stephen Milborrow  
4 -  
5 -#include "print.h"  
6 -#include "err.h"  
7 -#include "misc.h"  
8 -  
9 -#include <stdio.h>  
10 -#include <sys/stat.h>  
11 -#include <stdarg.h>  
12 -  
13 -namespace stasm  
14 -{  
15 -bool print_g; // true to allow output to stdout (but error msgs always printed)  
16 -  
17 -bool trace_g; // true to trace Stasm internal operation  
18 -  
19 -static FILE* logfile_g; // lprintfs go to this log file as well as stdout  
20 -  
21 -//-----------------------------------------------------------------------------  
22 -  
23 -// Open the log file. After this, when you call lprintf, you print to the log  
24 -// file (as well as to stdout). This inits the global variable logfile_g.  
25 -  
26 -void OpenLogFile( // also inits the global variable logfile_g  
27 - const char* path) // in: log file path, default is "stasm.log"  
28 -{  
29 - if (!logfile_g)  
30 - {  
31 - if (print_g)  
32 - printf("Generating %s\n", path);  
33 - logfile_g = fopen(path, "wb");  
34 - if (!logfile_g)  
35 - Err("Cannot open \"%s\"", path);  
36 - // check that we can write to the log file  
37 - if (fputs("log file\n", logfile_g) < 0)  
38 - Err("Cannot write to \"%s\"", path);  
39 - rewind(logfile_g); // rewind so above test msg is not in the log file  
40 - }  
41 -}  
42 -  
43 -// Like printf but only prints if print_g flag is set.  
44 -// Also prints to the log file if it is open (regardless of print_g).  
45 -  
46 -void lprintf(const char* format, ...) // args like printf  
47 -{  
48 - char s[SBIG];  
49 - va_list args;  
50 - va_start(args, format);  
51 - VSPRINTF(s, format, args);  
52 - va_end(args);  
53 - if (print_g)  
54 - {  
55 - printf("%s", s);  
56 - fflush(stdout); // flush so if there is a crash we can see what happened  
57 - }  
58 - if (logfile_g)  
59 - {  
60 - // we don't check fputs here, to prevent recursive calls and msgs  
61 - fputs(s, logfile_g);  
62 - fflush(logfile_g);  
63 - }  
64 -}  
65 -  
66 -// Like printf but prints to the log file only (and not to stdout).  
67 -// Used for detailed stuff that we don't usually want to see.  
68 -  
69 -void logprintf(const char* format, ...) // args like printf  
70 -{  
71 - if (logfile_g)  
72 - {  
73 - char s[SBIG];  
74 - va_list args;  
75 - va_start(args, format);  
76 - VSPRINTF(s, format, args);  
77 - va_end(args);  
78 - // we don't check fputs here, to prevent recursive calls and msgs  
79 - fputs(s, logfile_g);  
80 - fflush(logfile_g);  
81 - }  
82 -}  
83 -  
84 -// Like lprintf but always prints even if print_g is false.  
85 -  
86 -void lprintf_always(const char* format, ...)  
87 -{  
88 - char s[SBIG];  
89 - va_list args;  
90 - va_start(args, format);  
91 - VSPRINTF(s, format, args);  
92 - va_end(args);  
93 - printf("%s", s);  
94 - fflush(stdout); // flush so if there is a crash we can see what happened  
95 - if (logfile_g)  
96 - {  
97 - // we don't check fputs here, to prevent recursive calls and msgs  
98 - fputs(s, logfile_g);  
99 - fflush(logfile_g);  
100 - }  
101 -}  
102 -  
103 -// Like puts but prints to the log file as well if it is open,  
104 -// and does not append a newline.  
105 -  
106 -void lputs(const char* s)  
107 -{  
108 - printf("%s", s);  
109 - fflush(stdout); // flush so if there is a crash we can see what happened  
110 - logprintf("%s", s);  
111 -}  
112 -  
113 -// Print message only once on the screen, and only 100 times to the log file.  
114 -// This is used when similar messages could be printed many times and it  
115 -// suffices to let the user know just once. By convention the message is  
116 -// printed followed by "..." so the user knows that just the first message  
117 -// was printed. The user can look in the log file for further messages if  
118 -// necessary (but we print only 100 times to the log file --- else all the  
119 -// log prints make tasm slow).  
120 -  
121 -void PrintOnce(  
122 - int& printed, // io: zero=print, nonzero=no print  
123 - const char* format, ...) // in: args like printf  
124 -{  
125 - char s[SBIG];  
126 - va_list args;  
127 - va_start(args, format);  
128 - VSPRINTF(s, format, args);  
129 - va_end(args);  
130 - if (printed == 0 && print_g)  
131 - {  
132 - printed = 1;  
133 - printf("%s", s);  
134 - fflush(stdout); // flush so if there is a crash we can see what happened  
135 - }  
136 - if (printed < 100 && logfile_g)  
137 - {  
138 - fputs(s, logfile_g);  
139 - fflush(logfile_g);  
140 - printed++;  
141 - if (printed == 100)  
142 - logprintf("no more prints of the above message (printed == 100)\n");  
143 - }  
144 -}  
145 -  
146 -} // namespace stasm  
3rdparty/stasm4.0.0/stasm/MOD_1/facedet.cpp
@@ -47,28 +47,16 @@ void DetectFaces( // all face rects into detpars @@ -47,28 +47,16 @@ void DetectFaces( // all face rects into detpars
47 int minwidth, 47 int minwidth,
48 cv::CascadeClassifier cascade) // in: as percent of img width 48 cv::CascadeClassifier cascade) // in: as percent of img width
49 { 49 {
50 - int leftborder = 0, topborder = 0; // border size in pixels  
51 - Image bordered_img(BORDER_FRAC == 0?  
52 - img: EnborderImg(leftborder, topborder, img));  
53 -  
54 - // Detection results are very slightly better with equalization  
55 - // (tested on the MUCT images, which are not pre-equalized), and  
56 - // it's quick enough to equalize (roughly 10ms on a 1.6 GHz laptop).  
57 -  
58 - Image equalized_img; cv::equalizeHist(bordered_img, equalized_img);  
59 -  
60 CV_Assert(minwidth >= 1 && minwidth <= 100); 50 CV_Assert(minwidth >= 1 && minwidth <= 100);
61 51
62 - int minpix = MAX(100, cvRound(img.cols * minwidth / 100.));  
63 -  
64 // the params below are accurate but slow 52 // the params below are accurate but slow
65 - static const double SCALE_FACTOR = 1.1;  
66 - static const int MIN_NEIGHBORS = 3; 53 + static const double SCALE_FACTOR = 1.2;
  54 + static const int MIN_NEIGHBORS = 5;
67 static const int DETECTOR_FLAGS = 0; 55 static const int DETECTOR_FLAGS = 0;
68 56
69 vec_Rect facerects = // all face rects in image 57 vec_Rect facerects = // all face rects in image
70 - Detect(equalized_img, &cascade, NULL,  
71 - SCALE_FACTOR, MIN_NEIGHBORS, DETECTOR_FLAGS, minpix); 58 + Detect(img, &cascade, NULL,
  59 + SCALE_FACTOR, MIN_NEIGHBORS, DETECTOR_FLAGS, 64);
72 60
73 // copy face rects into the detpars vector 61 // copy face rects into the detpars vector
74 62
@@ -80,8 +68,6 @@ void DetectFaces( // all face rects into detpars @@ -80,8 +68,6 @@ void DetectFaces( // all face rects into detpars
80 // detpar.x and detpar.y is the center of the face rectangle 68 // detpar.x and detpar.y is the center of the face rectangle
81 detpar.x = facerect->x + facerect->width / 2.; 69 detpar.x = facerect->x + facerect->width / 2.;
82 detpar.y = facerect->y + facerect->height / 2.; 70 detpar.y = facerect->y + facerect->height / 2.;
83 - detpar.x -= leftborder; // discount the border we added earlier  
84 - detpar.y -= topborder;  
85 detpar.width = double(facerect->width); 71 detpar.width = double(facerect->width);
86 detpar.height = double(facerect->height); 72 detpar.height = double(facerect->height);
87 detpar.yaw = 0; // assume face has no yaw in this version of Stasm 73 detpar.yaw = 0; // assume face has no yaw in this version of Stasm
@@ -187,10 +173,10 @@ void FaceDet::DetectFaces_( // call once per image to find all the faces @@ -187,10 +173,10 @@ void FaceDet::DetectFaces_( // call once per image to find all the faces
187 //CV_Assert(!facedet_g.empty()); // check that OpenFaceDetector_ was called 173 //CV_Assert(!facedet_g.empty()); // check that OpenFaceDetector_ was called
188 174
189 DetectFaces(detpars_, img, minwidth, cascade); 175 DetectFaces(detpars_, img, minwidth, cascade);
190 - DiscardMissizedFaces(detpars_); 176 + //DiscardMissizedFaces(detpars_);
191 if (multiface) // order faces on increasing distance from left margin 177 if (multiface) // order faces on increasing distance from left margin
192 { 178 {
193 - sort(detpars_.begin(), detpars_.end(), IncreasingLeftMargin); 179 + sort(detpars_.begin(), detpars_.end(), DecreasingWidth);
194 } 180 }
195 else 181 else
196 { 182 {
3rdparty/stasm4.0.0/stasm/MOD_1/facedet.h
@@ -38,13 +38,11 @@ public: @@ -38,13 +38,11 @@ public:
38 38
39 FaceDet() {} // constructor 39 FaceDet() {} // constructor
40 40
41 -  
42 -private:  
43 - vector<DetPar> detpars_; // all the valid faces in the current image  
44 -  
45 int iface_; // index of current face for NextFace_ 41 int iface_; // index of current face for NextFace_
46 // indexes into detpars_ 42 // indexes into detpars_
  43 + vector<DetPar> detpars_; // all the valid faces in the current image
47 44
  45 +private:
48 DISALLOW_COPY_AND_ASSIGN(FaceDet); 46 DISALLOW_COPY_AND_ASSIGN(FaceDet);
49 47
50 }; // end class FaceDet 48 }; // end class FaceDet
3rdparty/stasm4.0.0/stasm/stasm_lib.cpp
@@ -160,7 +160,8 @@ int stasm_search_auto_ext( // extended version of stasm_search_auto @@ -160,7 +160,8 @@ int stasm_search_auto_ext( // extended version of stasm_search_auto
160 const char* data, 160 const char* data,
161 const int width, 161 const int width,
162 const int height, 162 const int height,
163 - StasmCascadeClassifier cascade) 163 + StasmCascadeClassifier cascade,
  164 + FaceDet &detection)
164 { 165 {
165 int returnval = 1; // assume success 166 int returnval = 1; // assume success
166 *foundface = 0; // but assume no face found 167 *foundface = 0; // but assume no face found
@@ -176,15 +177,14 @@ int stasm_search_auto_ext( // extended version of stasm_search_auto @@ -176,15 +177,14 @@ int stasm_search_auto_ext( // extended version of stasm_search_auto
176 // Allocate image 177 // Allocate image
177 Image img = Image(height, width,(unsigned char*)data); 178 Image img = Image(height, width,(unsigned char*)data);
178 179
179 - FaceDet facedet;  
180 -  
181 // call the face detector to detect the face rectangle(s) 180 // call the face detector to detect the face rectangle(s)
182 - facedet.DetectFaces_(img, NULL, false, 10, NULL, cascade.faceCascade); 181 + if (detection.detpars_.empty())
  182 + detection.DetectFaces_(img, NULL, true, 10, NULL, cascade.faceCascade);
183 183
184 // Get the start shape for the next face in the image, and the ROI around it. 184 // Get the start shape for the next face in the image, and the ROI around it.
185 // The shape will be wrt the ROI frame. 185 // The shape will be wrt the ROI frame.
186 if (NextStartShapeAndRoi(shape, face_roi, detpar_roi, detpar, 186 if (NextStartShapeAndRoi(shape, face_roi, detpar_roi, detpar,
187 - img, mods_g, facedet, cascade)) 187 + img, mods_g, detection, cascade))
188 { 188 {
189 // now working with maybe flipped ROI and start shape in ROI frame 189 // now working with maybe flipped ROI and start shape in ROI frame
190 *foundface = 1; 190 *foundface = 1;
@@ -219,9 +219,10 @@ int stasm_search_auto(// call repeatedly to find all faces @@ -219,9 +219,10 @@ int stasm_search_auto(// call repeatedly to find all faces
219 const char *data, 219 const char *data,
220 const int width, 220 const int width,
221 const int height, 221 const int height,
222 - StasmCascadeClassifier cascade) 222 + StasmCascadeClassifier cascade,
  223 + FaceDet &detection)
223 { 224 {
224 - return stasm_search_auto_ext(foundface, landmarks, NULL, data, width, height, cascade); 225 + return stasm_search_auto_ext(foundface, landmarks, NULL, data, width, height, cascade, detection);
225 } 226 }
226 227
227 int stasm_search_single( // wrapper for stasm_search_auto and friends 228 int stasm_search_single( // wrapper for stasm_search_auto and friends
@@ -237,7 +238,8 @@ int stasm_search_single( // wrapper for stasm_search_auto and friends @@ -237,7 +238,8 @@ int stasm_search_single( // wrapper for stasm_search_auto and friends
237 (void) datadir; 238 (void) datadir;
238 (void) imgpath; 239 (void) imgpath;
239 240
240 - return stasm_search_auto(foundface, landmarks, img, width, height, cascade); 241 + FaceDet detection;
  242 + return stasm_search_auto(foundface, landmarks, img, width, height, cascade, detection);
241 } 243 }
242 244
243 int stasm_search_pinned( // call after the user has pinned some points 245 int stasm_search_pinned( // call after the user has pinned some points
3rdparty/stasm4.0.0/stasm/stasm_lib.h
@@ -64,6 +64,10 @@ @@ -64,6 +64,10 @@
64 64
65 #include "stasmcascadeclassifier.h" 65 #include "stasmcascadeclassifier.h"
66 66
  67 +namespace stasm {
  68 + class FaceDet;
  69 +}
  70 +
67 static const int stasm_NLANDMARKS = 77; // number of landmarks 71 static const int stasm_NLANDMARKS = 77; // number of landmarks
68 72
69 extern const char* const stasm_VERSION; 73 extern const char* const stasm_VERSION;
@@ -89,7 +93,8 @@ int stasm_search_auto( // call repeatedly to find all faces @@ -89,7 +93,8 @@ int stasm_search_auto( // call repeatedly to find all faces
89 const char* data, 93 const char* data,
90 const int width, 94 const int width,
91 const int height, 95 const int height,
92 - StasmCascadeClassifier cascade); 96 + StasmCascadeClassifier cascade,
  97 + stasm::FaceDet &detection);
93 98
94 extern "C" 99 extern "C"
95 int stasm_search_single( // wrapper for stasm_search_auto and friends 100 int stasm_search_single( // wrapper for stasm_search_auto and friends
CMakeLists.txt
@@ -13,7 +13,7 @@ if(NOT DEFINED CPACK_PACKAGE_VERSION_MAJOR) @@ -13,7 +13,7 @@ if(NOT DEFINED CPACK_PACKAGE_VERSION_MAJOR)
13 set(CPACK_PACKAGE_VERSION_MAJOR 1) 13 set(CPACK_PACKAGE_VERSION_MAJOR 1)
14 endif() 14 endif()
15 if(NOT DEFINED CPACK_PACKAGE_VERSION_MINOR) 15 if(NOT DEFINED CPACK_PACKAGE_VERSION_MINOR)
16 - set(CPACK_PACKAGE_VERSION_MINOR 0) 16 + set(CPACK_PACKAGE_VERSION_MINOR 1)
17 endif() 17 endif()
18 if(NOT DEFINED CPACK_PACKAGE_VERSION_PATCH) 18 if(NOT DEFINED CPACK_PACKAGE_VERSION_PATCH)
19 set(CPACK_PACKAGE_VERSION_PATCH 0) 19 set(CPACK_PACKAGE_VERSION_PATCH 0)
@@ -158,8 +158,8 @@ endif() @@ -158,8 +158,8 @@ endif()
158 158
159 # Download the models 159 # Download the models
160 ExternalProject_Add(models 160 ExternalProject_Add(models
161 - URL http://github.com/biometrics/openbr/releases/download/v1.0.0/models.tar.gz  
162 - URL_MD5 0a7c79226d6629954aa32c835a1007b9 161 + URL http://github.com/biometrics/openbr/releases/download/v1.1.0/models.tar.gz
  162 + URL_MD5 26cf71abd48cec8d7b2abf3e8f4ebfc4
163 SOURCE_DIR "${PROJECT_SOURCE_DIR}/share/openbr/models" 163 SOURCE_DIR "${PROJECT_SOURCE_DIR}/share/openbr/models"
164 CONFIGURE_COMMAND "" 164 CONFIGURE_COMMAND ""
165 BUILD_COMMAND "" 165 BUILD_COMMAND ""
app/br/br.cpp
@@ -169,8 +169,8 @@ public: @@ -169,8 +169,8 @@ public:
169 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalRegression'."); 169 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalRegression'.");
170 br_eval_regression(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : ""); 170 br_eval_regression(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : "");
171 } else if (!strcmp(fun, "evalKNN")) { 171 } else if (!strcmp(fun, "evalKNN")) {
172 - check(parc == 3, "Incorrect parameter count for 'evalKNN'.");  
173 - br_eval_knn(parv[0], parv[1], parv[2]); 172 + check(parc >= 2 && parc <= 3, "Incorrect parameter count for 'evalKNN'.");
  173 + br_eval_knn(parv[0], parv[1], parc > 2 ? parv[2] : "");
174 } else if (!strcmp(fun, "pairwiseCompare")) { 174 } else if (!strcmp(fun, "pairwiseCompare")) {
175 check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'pairwiseCompare'."); 175 check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'pairwiseCompare'.");
176 br_pairwise_compare(parv[0], parv[1], parc == 3 ? parv[2] : ""); 176 br_pairwise_compare(parv[0], parv[1], parc == 3 ? parv[2] : "");
@@ -186,6 +186,9 @@ public: @@ -186,6 +186,9 @@ public:
186 } else if (!strcmp(fun, "plotMetadata")) { 186 } else if (!strcmp(fun, "plotMetadata")) {
187 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); 187 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
188 br_plot_metadata(parc-1, parv, parv[parc-1], true); 188 br_plot_metadata(parc-1, parv, parv[parc-1], true);
  189 + } else if (!strcmp(fun, "plotKNN")) {
  190 + check(parc >=2, "Incorrect parameter count for 'plotKNN'.");
  191 + br_plot_knn(parc-1, parv, parv[parc-1], true);
189 } else if (!strcmp(fun, "project")) { 192 } else if (!strcmp(fun, "project")) {
190 check(parc == 2, "Insufficient parameter count for 'project'."); 193 check(parc == 2, "Insufficient parameter count for 'project'.");
191 br_project(parv[0], parv[1]); 194 br_project(parv[0], parv[1]);
@@ -279,13 +282,14 @@ private: @@ -279,13 +282,14 @@ private:
279 "-evalDetection <predicted_gallery> <truth_gallery> [{csv}] [{normalize}] [{minSize}] [{maxSize}]\n" 282 "-evalDetection <predicted_gallery> <truth_gallery> [{csv}] [{normalize}] [{minSize}] [{maxSize}]\n"
280 "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>] [sample_index] [total_examples]]\n" 283 "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>] [sample_index] [total_examples]]\n"
281 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n" 284 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n"
282 - "-evalKNN <knn_graph> <knn_truth> [{iet_file}]\n" 285 + "-evalKNN <knn_graph> <knn_truth> [{csv}]\n"
283 "-pairwiseCompare <target_gallery> <query_gallery> [{output}]\n" 286 "-pairwiseCompare <target_gallery> <query_gallery> [{output}]\n"
284 "-inplaceEval <simmat> <target> <query> [{csv}]\n" 287 "-inplaceEval <simmat> <target> <query> [{csv}]\n"
285 "-assertEval <simmat> <mask> <accuracy>\n" 288 "-assertEval <simmat> <mask> <accuracy>\n"
286 "-plotDetection <file> ... <file> {destination}\n" 289 "-plotDetection <file> ... <file> {destination}\n"
287 "-plotLandmarking <file> ... <file> {destination}\n" 290 "-plotLandmarking <file> ... <file> {destination}\n"
288 "-plotMetadata <file> ... <file> <columns>\n" 291 "-plotMetadata <file> ... <file> <columns>\n"
  292 + "-plotKNN <file> ... <file> {destination}\n"
289 "-project <input_gallery> {output_gallery}\n" 293 "-project <input_gallery> {output_gallery}\n"
290 "-deduplicate <input_gallery> <output_gallery> <threshold>\n" 294 "-deduplicate <input_gallery> <output_gallery> <threshold>\n"
291 "-likely <input_type> <output_type> <output_likely_source>\n" 295 "-likely <input_type> <output_type> <output_likely_source>\n"
docs/docs/api_docs/cl_api.md
@@ -59,6 +59,17 @@ DOCUMENT ME @@ -59,6 +59,17 @@ DOCUMENT ME
59 59
60 * **wraps:** [br_pairwise_compare](c_api/functions.md#br_pairwise_compare) 60 * **wraps:** [br_pairwise_compare](c_api/functions.md#br_pairwise_compare)
61 61
  62 +### -crossValidate {: #crossvalidate }
  63 +
  64 +Either performs n fold cross validation (if nFolds > 0), or a single iteration of a train / test split with the first of the n folds as the test partition (nFolds < 0).
  65 +
  66 +* **arguments:**
  67 +
  68 + -crossValidate <nFolds> -algorithm "CrossValidate(description=$ALG,randomSeed=5):CrossValidate+Dist" -train <inputFile> <model>
  69 +
  70 + -crossValidate <nFolds> -algorithm <model> -enroll <inputFile> input.gal -compare input.gal . out.eval
  71 +
  72 +
62 ### -eval {: #eval } 73 ### -eval {: #eval }
63 74
64 Evaluate a similarity matrix 75 Evaluate a similarity matrix
docs/docs/install.md
@@ -35,7 +35,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR. @@ -35,7 +35,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR.
35 35
36 $ git clone https://github.com/biometrics/openbr.git 36 $ git clone https://github.com/biometrics/openbr.git
37 $ cd openbr 37 $ cd openbr
38 - $ git checkout 1.0 38 + $ git checkout v1.1.0
39 $ git submodule init 39 $ git submodule init
40 $ git submodule update 40 $ git submodule update
41 41
@@ -116,7 +116,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR. @@ -116,7 +116,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR.
116 116
117 $ git clone https://github.com/biometrics/openbr.git 117 $ git clone https://github.com/biometrics/openbr.git
118 $ cd openbr 118 $ cd openbr
119 - $ git checkout 1.0 119 + $ git checkout v1.1.0
120 $ git submodule init 120 $ git submodule init
121 $ git submodule update 121 $ git submodule update
122 122
@@ -196,7 +196,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR. @@ -196,7 +196,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR.
196 $ cd /c 196 $ cd /c
197 $ git clone https://github.com/biometrics/openbr.git 197 $ git clone https://github.com/biometrics/openbr.git
198 $ cd openbr 198 $ cd openbr
199 - $ git checkout 1.0 199 + $ git checkout v1.1.0
200 $ git submodule init 200 $ git submodule init
201 $ git submodule update 201 $ git submodule update
202 202
@@ -277,7 +277,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR. @@ -277,7 +277,7 @@ A hacker&#39;s guide to building, editing, and running OpenBR.
277 277
278 $ git clone https://github.com/biometrics/openbr.git 278 $ git clone https://github.com/biometrics/openbr.git
279 $ cd openbr 279 $ cd openbr
280 - $ git checkout 1.0 280 + $ git checkout v1.1.0
281 $ git submodule init 281 $ git submodule init
282 $ git submodule update 282 $ git submodule update
283 283
openbr/core/boost.cpp
@@ -131,23 +131,16 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b @@ -131,23 +131,16 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b
131 131
132 //------------------------------------- FeatureEvaluator --------------------------------------- 132 //------------------------------------- FeatureEvaluator ---------------------------------------
133 133
134 -void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount, int channels) 134 +void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount)
135 { 135 {
136 representation = _representation; 136 representation = _representation;
137 -  
138 - int dx, dy;  
139 - Size windowSize = representation->windowSize(&dx, &dy);  
140 - data.create((int)_maxSampleCount, (windowSize.width + dx) * (windowSize.height + dy), CV_32SC(channels));  
141 cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); 137 cls.create( (int)_maxSampleCount, 1, CV_32FC1 );
142 } 138 }
143 139
144 -void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) 140 +void FeatureEvaluator::setImage(const Template &src, uchar clsLabel, int idx)
145 { 141 {
146 cls.ptr<float>(idx)[0] = clsLabel; 142 cls.ptr<float>(idx)[0] = clsLabel;
147 -  
148 - Mat pp;  
149 - representation->preprocess(img, pp);  
150 - pp.reshape(0, 1).copyTo(data.row(idx)); 143 + data.append(representation->preprocess(src));
151 } 144 }
152 145
153 //----------------------------- CascadeBoostParams ------------------------------------------------- 146 //----------------------------- CascadeBoostParams -------------------------------------------------
openbr/core/boost.h
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 #define _BOOST_H_ 2 #define _BOOST_H_
3 3
4 #include "ml.h" 4 #include "ml.h"
5 -#include <time.h>  
6 #include <openbr/openbr_plugin.h> 5 #include <openbr/openbr_plugin.h>
7 6
8 #ifdef _WIN32 7 #ifdef _WIN32
@@ -17,9 +16,9 @@ namespace br @@ -17,9 +16,9 @@ namespace br
17 struct FeatureEvaluator 16 struct FeatureEvaluator
18 { 17 {
19 ~FeatureEvaluator() {} 18 ~FeatureEvaluator() {}
20 - void init(Representation *_representation, int _maxSampleCount, int channels);  
21 - void setImage(const cv::Mat& img, uchar clsLabel, int idx);  
22 - float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } 19 + void init(Representation *_representation, int _maxSampleCount);
  20 + void setImage(const Template &src, uchar clsLabel, int idx);
  21 + float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data[sampleIdx], featureIdx); }
23 22
24 int getNumFeatures() const { return representation->numFeatures(); } 23 int getNumFeatures() const { return representation->numFeatures(); }
25 int getMaxCatCount() const { return representation->maxCatCount(); } 24 int getMaxCatCount() const { return representation->maxCatCount(); }
@@ -27,7 +26,8 @@ struct FeatureEvaluator @@ -27,7 +26,8 @@ struct FeatureEvaluator
27 const cv::Mat& getCls() const { return cls; } 26 const cv::Mat& getCls() const { return cls; }
28 float getCls(int si) const { return cls.at<float>(si, 0); } 27 float getCls(int si) const { return cls.at<float>(si, 0); }
29 28
30 - cv::Mat data, cls; 29 + cv::Mat cls;
  30 + TemplateList data;
31 Representation *representation; 31 Representation *representation;
32 }; 32 };
33 33
openbr/core/eval.cpp
@@ -825,16 +825,25 @@ static QStringList computeDetectionResults(const QList&lt;ResolvedDetection&gt; &amp;detec @@ -825,16 +825,25 @@ static QStringList computeDetectionResults(const QList&lt;ResolvedDetection&gt; &amp;detec
825 if (prevFP / numImages < 0.1 && FP / numImages > 0.1 && discrete) { 825 if (prevFP / numImages < 0.1 && FP / numImages > 0.1 && discrete) {
826 qDebug("TAR @ FAR => %f : 0.1", TP / totalTrueDetections); 826 qDebug("TAR @ FAR => %f : 0.1", TP / totalTrueDetections);
827 qDebug("Confidence: %f", detection.confidence); 827 qDebug("Confidence: %f", detection.confidence);
  828 + qDebug("TP vs. FP: %f to %f", TP, FP);
828 } else if (prevFP / numImages < 0.01 && FP / numImages > 0.01 && discrete) { 829 } else if (prevFP / numImages < 0.01 && FP / numImages > 0.01 && discrete) {
829 qDebug("TAR @ FAR => %f : 0.01", TP / totalTrueDetections); 830 qDebug("TAR @ FAR => %f : 0.01", TP / totalTrueDetections);
830 qDebug("Confidence: %f", detection.confidence); 831 qDebug("Confidence: %f", detection.confidence);
  832 + qDebug("TP vs. FP: %f to %f", TP, FP);
  833 + } else if (prevFP / numImages < 0.001 && FP / numImages > 0.001 && discrete) {
  834 + qDebug("TAR @ FAR => %f : 0.001", TP / totalTrueDetections);
  835 + qDebug("Confidence: %f", detection.confidence);
  836 + qDebug("TP vs. FP: %f to %f", TP, FP);
831 } 837 }
  838 +
832 points.append(DetectionOperatingPoint(TP, FP, totalTrueDetections, numImages)); 839 points.append(DetectionOperatingPoint(TP, FP, totalTrueDetections, numImages));
833 prevFP = FP; 840 prevFP = FP;
834 } 841 }
835 } 842 }
836 } 843 }
837 844
  845 + if (discrete) qDebug("Total TP vs. FP: %f to %f", TP, FP);
  846 +
838 const int keep = qMin(points.size(), Max_Points); 847 const int keep = qMin(points.size(), Max_Points);
839 if (keep < 1) qFatal("Insufficient points."); 848 if (keep < 1) qFatal("Insufficient points.");
840 849
@@ -1336,7 +1345,7 @@ void readKNNTruth(size_t probeCount, QVector&lt; QList&lt;size_t&gt; &gt; &amp;groundTruth, cons @@ -1336,7 +1345,7 @@ void readKNNTruth(size_t probeCount, QVector&lt; QList&lt;size_t&gt; &gt; &amp;groundTruth, cons
1336 qFatal("Invalid ground truth file!"); 1345 qFatal("Invalid ground truth file!");
1337 } 1346 }
1338 1347
1339 -void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &iet) 1348 +void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &csv)
1340 { 1349 {
1341 qDebug("Evaluating k-NN of %s against %s", qPrintable(knnGraph), qPrintable(knnTruth)); 1350 qDebug("Evaluating k-NN of %s against %s", qPrintable(knnGraph), qPrintable(knnTruth));
1342 1351
@@ -1406,19 +1415,14 @@ void EvalKNN(const QString &amp;knnGraph, const QString &amp;knnTruth, const QString &amp;ie @@ -1406,19 +1415,14 @@ void EvalKNN(const QString &amp;knnGraph, const QString &amp;knnTruth, const QString &amp;ie
1406 if (numUnmatedSearches == 0) 1415 if (numUnmatedSearches == 0)
1407 qFatal("No unmated searches!"); 1416 qFatal("No unmated searches!");
1408 1417
1409 - printf("Rank-%i Return Rate: %g\n", 1, getCMC(firstGenuineReturns, 1, numMatedSearches)); 1418 +
  1419 + qDebug("Rank-%d Return Rate: %.3f", 1, getCMC(firstGenuineReturns, 1, numMatedSearches));
1410 if (k >=5) 1420 if (k >=5)
1411 - printf("Rank-%i Return Rate: %g\n", 5, getCMC(firstGenuineReturns, 5, numMatedSearches)); 1421 + qDebug("Rank-%d Return Rate: %.3f", 5, getCMC(firstGenuineReturns, 5, numMatedSearches));
1412 if (k >=10) 1422 if (k >=10)
1413 - printf("Rank-%i Return Rate: %g\n", 10, getCMC(firstGenuineReturns, 10, numMatedSearches));  
1414 -  
1415 - printf("Rank-%zu Return Rate: %g\n", k, double(numMatedSimilarities) / double(numMatedSearches)); 1423 + qDebug("Rank-%d Return Rate: %.3f", 10, getCMC(firstGenuineReturns, 10, numMatedSearches));
1416 1424
1417 - // Open the output file  
1418 - QFile ietFile(iet);  
1419 - if (!ietFile.open(QFile::WriteOnly | QFile::Text))  
1420 - qFatal("Failed to open IET file for writing!");  
1421 - ietFile.write("Threshold,FPIR,FNIR\n"); 1425 + qDebug("Rank-%zu Return Rate: %.3f", k, double(numMatedSimilarities) / double(numMatedSearches));
1422 1426
1423 /* 1427 /*
1424 * Iterate through the similarity scores highest-to-lowest, 1428 * Iterate through the similarity scores highest-to-lowest,
@@ -1447,10 +1451,28 @@ void EvalKNN(const QString &amp;knnGraph, const QString &amp;knnTruth, const QString &amp;ie @@ -1447,10 +1451,28 @@ void EvalKNN(const QString &amp;knnGraph, const QString &amp;knnTruth, const QString &amp;ie
1447 } 1451 }
1448 } 1452 }
1449 1453
1450 - foreach(const OperatingPoint &operatingPoint, operatingPoints)  
1451 - ietFile.write(qPrintable(QString::number(operatingPoint.score) + "," +  
1452 - QString::number(operatingPoint.FAR) + "," +  
1453 - QString::number(operatingPoint.TAR) + "\n")); 1454 + if (!csv.isEmpty()) {
  1455 + // Open the output file
  1456 + QFile ietFile(csv);
  1457 + if (!ietFile.open(QFile::WriteOnly | QFile::Text))
  1458 + qFatal("Failed to open IET file for writing!");
  1459 + ietFile.write("Plot,X,Y,Z\n");
  1460 + // Write CMC
  1461 + const int Max_Retrieval = min(200, (int)k);
  1462 + for (int i=1; i<=Max_Retrieval; i++) {
  1463 + const float retrievalRate = getCMC(firstGenuineReturns, i, numMatedSearches);
  1464 + ietFile.write(qPrintable(QString("CMC,%1,%2,0\n").arg(QString::number(i), QString::number(retrievalRate))));
  1465 + }
  1466 +
  1467 + foreach(const OperatingPoint &operatingPoint, operatingPoints)
  1468 + ietFile.write(qPrintable("IET," +
  1469 + QString::number(operatingPoint.FAR) + "," +
  1470 + QString::number(operatingPoint.TAR) + "," +
  1471 + QString::number(operatingPoint.score) + "\n"));
  1472 + }
  1473 +
  1474 + qDebug("FNIR @ FPIR = 0.1: %.3f", 1-getOperatingPointGivenFAR(operatingPoints, 0.1).TAR);
  1475 + qDebug("FNIR @ FPIR = 0.01: %.3f", 1-getOperatingPointGivenFAR(operatingPoints, 0.01).TAR);
1454 } 1476 }
1455 1477
1456 } // namespace br 1478 } // namespace br
openbr/core/eval.h
@@ -33,7 +33,7 @@ namespace br @@ -33,7 +33,7 @@ namespace br
33 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", bool normalize = false, int minSize = 0, int maxSize = 0); // Return average overlap 33 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", bool normalize = false, int minSize = 0, int maxSize = 0); // Return average overlap
34 float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", int normalizationIndexA = 0, int normalizationIndexB = 1, int sampleIndex = 0, int totalExamples = 5); // Return average error 34 float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", int normalizationIndexA = 0, int normalizationIndexB = 1, int sampleIndex = 0, int totalExamples = 5); // Return average error
35 void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = ""); 35 void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = "");
36 - void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &iet); 36 + void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &csv = "");
37 37
38 struct Candidate 38 struct Candidate
39 { 39 {
openbr/core/opencvutils.cpp
@@ -436,7 +436,7 @@ public: @@ -436,7 +436,7 @@ public:
436 }; 436 };
437 437
438 // TODO: Make sure case where no confidences are inputted works. 438 // TODO: Make sure case where no confidences are inputted works.
439 -void OpenCVUtils::group(QList<Rect> &rects, QList<float> &confidences, float confidenceThreshold, float epsilon) 439 +void OpenCVUtils::group(QList<Rect> &rects, QList<float> &confidences, float confidenceThreshold, int minNeighbors, float epsilon)
440 { 440 {
441 if (rects.isEmpty()) 441 if (rects.isEmpty())
442 return; 442 return;
@@ -450,7 +450,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -450,7 +450,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
450 vector<Rect> rrects(nClasses); 450 vector<Rect> rrects(nClasses);
451 451
452 // Total number of rects in each class 452 // Total number of rects in each class
453 - vector<int> rweights(nClasses, 0); 453 + vector<int> neighbors(nClasses, 0);
454 vector<float> rejectWeights(nClasses, -std::numeric_limits<float>::max()); 454 vector<float> rejectWeights(nClasses, -std::numeric_limits<float>::max());
455 455
456 for (size_t i = 0; i < labels.size(); i++) 456 for (size_t i = 0; i < labels.size(); i++)
@@ -460,7 +460,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -460,7 +460,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
460 rrects[cls].y += rects[i].y; 460 rrects[cls].y += rects[i].y;
461 rrects[cls].width += rects[i].width; 461 rrects[cls].width += rects[i].width;
462 rrects[cls].height += rects[i].height; 462 rrects[cls].height += rects[i].height;
463 - rweights[cls]++; 463 + neighbors[cls]++;
464 } 464 }
465 465
466 if (useConfidences) 466 if (useConfidences)
@@ -478,7 +478,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -478,7 +478,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
478 for (int i = 0; i < nClasses; i++) 478 for (int i = 0; i < nClasses; i++)
479 { 479 {
480 Rect r = rrects[i]; 480 Rect r = rrects[i];
481 - float s = 1.f/rweights[i]; 481 + float s = 1.f/neighbors[i];
482 rrects[i] = Rect(saturate_cast<int>(r.x*s), 482 rrects[i] = Rect(saturate_cast<int>(r.x*s),
483 saturate_cast<int>(r.y*s), 483 saturate_cast<int>(r.y*s),
484 saturate_cast<int>(r.width*s), 484 saturate_cast<int>(r.width*s),
@@ -488,7 +488,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -488,7 +488,7 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
488 rects.clear(); 488 rects.clear();
489 confidences.clear(); 489 confidences.clear();
490 490
491 - // Aggregate by comparing average rectangles against other average rectangels 491 + // Aggregate by comparing average rectangles against other average rectangles
492 for (int i = 0; i < nClasses; i++) 492 for (int i = 0; i < nClasses; i++)
493 { 493 {
494 // Average rectangle 494 // Average rectangle
@@ -496,19 +496,22 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -496,19 +496,22 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
496 496
497 // Used to eliminate rectangles with few neighbors in the case of no weights 497 // Used to eliminate rectangles with few neighbors in the case of no weights
498 // int n1 = levelWeights ? rejectLevels[i] : rweights[i]; 498 // int n1 = levelWeights ? rejectLevels[i] : rweights[i];
499 - float w1 = rejectWeights[i]; 499 + const float w1 = rejectWeights[i];
500 500
501 // Eliminate rectangle if it doesn't meet confidence criteria 501 // Eliminate rectangle if it doesn't meet confidence criteria
502 if (w1 <= confidenceThreshold) 502 if (w1 <= confidenceThreshold)
503 continue; 503 continue;
504 504
  505 + const int n1 = neighbors[i];
  506 + if (n1 < minNeighbors)
  507 + continue;
  508 +
505 // filter out small face rectangles inside large rectangles 509 // filter out small face rectangles inside large rectangles
506 int j; 510 int j;
507 for (j = 0; j < nClasses; j++) 511 for (j = 0; j < nClasses; j++)
508 { 512 {
509 - float w2 = rejectWeights[j];  
510 -  
511 - if (j == i) 513 + const int n2 = neighbors[j];
  514 + if (j == i || n2 < minNeighbors)
512 continue; 515 continue;
513 516
514 Rect r2 = rrects[j]; 517 Rect r2 = rrects[j];
@@ -516,13 +519,11 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -516,13 +519,11 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
516 int dx = saturate_cast<int>(r2.width * epsilon); 519 int dx = saturate_cast<int>(r2.width * epsilon);
517 int dy = saturate_cast<int>(r2.height * epsilon); 520 int dy = saturate_cast<int>(r2.height * epsilon);
518 521
  522 + float w2 = rejectWeights[j];
  523 +
519 // If, r1 is within the r2 AND 524 // If, r1 is within the r2 AND
520 - // the second rectangle reaches a later stage than the first  
521 - // where both the first and the second must have a stage greater than three OR  
522 - // the first doens't reach the third stage.  
523 - // Changeto: second rectangle has a higher confidence than the first OR  
524 - // the first has a low confidence.  
525 - // Then, eliminate the first rectangle. 525 + // r2 has a higher confidence than r1
  526 + // then, eliminate the r1
526 if(r1.x >= r2.x - dx && 527 if(r1.x >= r2.x - dx &&
527 r1.y >= r2.y - dy && 528 r1.y >= r2.y - dy &&
528 r1.x + r1.width <= r2.x + r2.width + dx && 529 r1.x + r1.width <= r2.x + r2.width + dx &&
@@ -531,7 +532,6 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con @@ -531,7 +532,6 @@ void OpenCVUtils::group(QList&lt;Rect&gt; &amp;rects, QList&lt;float&gt; &amp;confidences, float con
531 break; 532 break;
532 } 533 }
533 534
534 - // Need to return rects and confidences  
535 if( j == nClasses ) 535 if( j == nClasses )
536 { 536 {
537 rects.append(r1); 537 rects.append(r1);
openbr/core/opencvutils.h
@@ -102,7 +102,7 @@ namespace OpenCVUtils @@ -102,7 +102,7 @@ namespace OpenCVUtils
102 float overlap(const QRectF &rect1, const QRectF &rect2); 102 float overlap(const QRectF &rect1, const QRectF &rect2);
103 103
104 // Misc 104 // Misc
105 - void group(QList<cv::Rect> &rects, QList<float> &confidences, float confidenceThreshold, float epsilon); 105 + void group(QList<cv::Rect> &rects, QList<float> &confidences, float confidenceThreshold, int minNeighbors, float epsilon);
106 void flip(const br::Template &src, br::Template &dst, int axis, bool flipMat=true, bool flipPoints=true, bool flipRects=true); 106 void flip(const br::Template &src, br::Template &dst, int axis, bool flipMat=true, bool flipPoints=true, bool flipRects=true);
107 void flip(const br::TemplateList &src, br::TemplateList &dst, int axis, bool flipMat=true, bool flipPoints=true, bool flipRects=true); 107 void flip(const br::TemplateList &src, br::TemplateList &dst, int axis, bool flipMat=true, bool flipPoints=true, bool flipRects=true);
108 108
openbr/core/plot.cpp
@@ -346,4 +346,32 @@ bool PlotMetadata(const QStringList &amp;files, const QString &amp;columns, bool show) @@ -346,4 +346,32 @@ bool PlotMetadata(const QStringList &amp;files, const QString &amp;columns, bool show)
346 return p.finalize(show); 346 return p.finalize(show);
347 } 347 }
348 348
  349 +bool PlotKNN(const QStringList &files, const File &destination, bool show)
  350 +{
  351 + qDebug("Plotting %d k-NN file(s) to %s", files.size(), qPrintable(destination));
  352 + RPlot p(files, destination);
  353 + p.file.write("\nformatData(type=\"knn\")\n\n");
  354 +
  355 + QMap<QString,File> optMap;
  356 + optMap.insert("rocOptions", File(QString("[xTitle=False Positive Identification Rate (FPIR),yTitle=True Positive Identification Rate (TPIR),xLog=true,yLog=false]")));
  357 + optMap.insert("ietOptions", File(QString("[xTitle=False Positive Identification Rate (FPIR),yTitle=False Negative Identification Rate (FNIR),xLog=true,yLog=true]")));
  358 + optMap.insert("cmcOptions", File(QString("[xTitle=Rank,yTitle=Retrieval Rate,xLog=true,yLog=false,size=1,xLabels=(1,5,10,50,100),xBreaks=(1,5,10,50,100)]")));
  359 +
  360 + foreach (const QString &key, optMap.keys()) {
  361 + const QStringList options = destination.get<QStringList>(key, QStringList());
  362 + foreach (const QString &option, options) {
  363 + QStringList words = QtUtils::parse(option, '=');
  364 + QtUtils::checkArgsSize(words[0], words, 1, 2);
  365 + optMap[key].set(words[0], words[1]);
  366 + }
  367 + }
  368 +
  369 + QString plot = "plot <- plotLine(lineData=%1, options=list(%2), flipY=%3)\nplot\n";
  370 + p.file.write(qPrintable(QString(plot).arg("IET", toRList(optMap["rocOptions"]), "TRUE")));
  371 + p.file.write(qPrintable(QString(plot).arg("IET", toRList(optMap["ietOptions"]), "FALSE")));
  372 + p.file.write(qPrintable(QString(plot).arg("CMC", toRList(optMap["cmcOptions"]), "FALSE")));
  373 +
  374 + return p.finalize(show);
  375 +}
  376 +
349 } // namespace br 377 } // namespace br
openbr/core/plot.h
@@ -28,6 +28,7 @@ namespace br @@ -28,6 +28,7 @@ namespace br
28 bool PlotDetection(const QStringList &files, const File &destination, bool show = false); 28 bool PlotDetection(const QStringList &files, const File &destination, bool show = false);
29 bool PlotLandmarking(const QStringList &files, const File &destination, bool show = false); 29 bool PlotLandmarking(const QStringList &files, const File &destination, bool show = false);
30 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false); 30 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false);
  31 + bool PlotKNN(const QStringList &files, const File &destination, bool show = false);
31 } 32 }
32 33
33 #endif // BR_PLOT_H 34 #endif // BR_PLOT_H
openbr/openbr.cpp
@@ -145,9 +145,9 @@ void br_eval_regression(const char *predicted_gallery, const char *truth_gallery @@ -145,9 +145,9 @@ void br_eval_regression(const char *predicted_gallery, const char *truth_gallery
145 EvalRegression(predicted_gallery, truth_gallery, predicted_property, truth_property); 145 EvalRegression(predicted_gallery, truth_gallery, predicted_property, truth_property);
146 } 146 }
147 147
148 -void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *iet) 148 +void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *csv)
149 { 149 {
150 - EvalKNN(knnGraph, knnTruth, iet); 150 + EvalKNN(knnGraph, knnTruth, csv);
151 } 151 }
152 152
153 void br_finalize() 153 void br_finalize()
@@ -221,6 +221,11 @@ bool br_plot_metadata(int num_files, const char *files[], const char *columns, b @@ -221,6 +221,11 @@ bool br_plot_metadata(int num_files, const char *files[], const char *columns, b
221 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show); 221 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show);
222 } 222 }
223 223
  224 +bool br_plot_knn(int num_files, const char *files[], const char *destination, bool show)
  225 +{
  226 + return PlotKNN(QtUtils::toStringList(num_files, files), destination, show);
  227 +}
  228 +
224 float br_progress() 229 float br_progress()
225 { 230 {
226 return Globals->progress(); 231 return Globals->progress();
openbr/openbr.h
@@ -64,7 +64,7 @@ BR_EXPORT float br_eval_landmarking(const char *predicted_gallery, const char *t @@ -64,7 +64,7 @@ BR_EXPORT float br_eval_landmarking(const char *predicted_gallery, const char *t
64 64
65 BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property = "", const char *truth_property = ""); 65 BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property = "", const char *truth_property = "");
66 66
67 -BR_EXPORT void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *iet); 67 +BR_EXPORT void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *csv = "");
68 68
69 BR_EXPORT void br_finalize(); 69 BR_EXPORT void br_finalize();
70 70
@@ -93,6 +93,8 @@ BR_EXPORT bool br_plot_landmarking(int num_files, const char *files[], const cha @@ -93,6 +93,8 @@ BR_EXPORT bool br_plot_landmarking(int num_files, const char *files[], const cha
93 93
94 BR_EXPORT bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show = false); 94 BR_EXPORT bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show = false);
95 95
  96 +BR_EXPORT bool br_plot_knn(int num_files, const char *files[], const char *destination, bool show = false);
  97 +
96 BR_EXPORT float br_progress(); 98 BR_EXPORT float br_progress();
97 99
98 BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); 100 BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv);
openbr/openbr_plugin.h
@@ -882,13 +882,11 @@ public: @@ -882,13 +882,11 @@ public:
882 882
883 static Representation *make(QString str, QObject *parent); /*!< \brief Make a representation from a string. */ 883 static Representation *make(QString str, QObject *parent); /*!< \brief Make a representation from a string. */
884 884
885 - virtual void preprocess(const cv::Mat &src, cv::Mat &dst) const { dst = src; }  
886 - virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) { (void) images; (void)labels; }  
887 -  
888 - virtual float evaluate(const cv::Mat &image, int idx) const = 0;  
889 - // By convention, an empty indices list will result in all feature responses being calculated  
890 - // and returned.  
891 - virtual cv::Mat evaluate(const cv::Mat &image, const QList<int> &indices = QList<int>()) const = 0; 885 + virtual Template preprocess(const Template &src) const { return src; }
  886 + virtual void train(const TemplateList &data) { (void)data; }
  887 + virtual float evaluate(const Template &src, int idx) const = 0;
  888 + // By convention passing an empty list evaluates all features in the representation
  889 + virtual cv::Mat evaluate(const Template &src, const QList<int> &indices = QList<int>()) const = 0;
892 890
893 virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0; // dx and dy should indicate the change to the original window size after preprocessing 891 virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0; // dx and dy should indicate the change to the original window size after preprocessing
894 virtual int numChannels() const { return 1; } 892 virtual int numChannels() const { return 1; }
@@ -905,13 +903,13 @@ public: @@ -905,13 +903,13 @@ public:
905 903
906 static Classifier *make(QString str, QObject *parent); 904 static Classifier *make(QString str, QObject *parent);
907 905
908 - virtual void train(const QList<cv::Mat> &images, const QList<float> &labels) = 0;  
909 - virtual float classify(const cv::Mat &image, bool process = true, float *confidence = NULL) const = 0; 906 + virtual void train(const TemplateList &data) { (void)data; }
  907 + virtual float classify(const Template &src, bool process = true, float *confidence = NULL) const = 0;
910 908
911 // Slots for representations 909 // Slots for representations
912 - virtual cv::Mat preprocess(const cv::Mat &image) const = 0; 910 + virtual Template preprocess(const Template &src) const { return src; }
913 virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0; 911 virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0;
914 - virtual int numFeatures() const = 0; 912 + virtual int numFeatures() const { return 0; }
915 }; 913 };
916 914
917 915
openbr/plugins/classification/boostedforest.cpp
@@ -125,20 +125,20 @@ private: @@ -125,20 +125,20 @@ private:
125 QList<Node*> classifiers; 125 QList<Node*> classifiers;
126 float threshold; 126 float threshold;
127 127
128 - void train(const QList<Mat> &images, const QList<float> &labels) 128 + void train(const TemplateList &data)
129 { 129 {
130 - representation->train(images, labels); 130 + representation->train(data);
131 131
132 CascadeBoostParams params(type, minTAR, maxFAR, trimRate, maxDepth, maxWeakCount); 132 CascadeBoostParams params(type, minTAR, maxFAR, trimRate, maxDepth, maxWeakCount);
133 133
134 FeatureEvaluator featureEvaluator; 134 FeatureEvaluator featureEvaluator;
135 - featureEvaluator.init(representation, images.size(), representation->numChannels()); 135 + featureEvaluator.init(representation, data.size());
136 136
137 - for (int i = 0; i < images.size(); i++)  
138 - featureEvaluator.setImage(images[i], labels[i], i); 137 + for (int i = 0; i < data.size(); i++)
  138 + featureEvaluator.setImage(data[i], data[i].file.get<float>("Label"), i);
139 139
140 CascadeBoost boost; 140 CascadeBoost boost;
141 - boost.train(&featureEvaluator, images.size(), 1024, 1024, representation->numChannels(), params); 141 + boost.train(&featureEvaluator, data.size(), 1024, 1024, representation->numChannels(), params);
142 142
143 threshold = boost.getThreshold(); 143 threshold = boost.getThreshold();
144 144
@@ -149,13 +149,9 @@ private: @@ -149,13 +149,9 @@ private:
149 } 149 }
150 } 150 }
151 151
152 - float classify(const Mat &image, bool process, float *confidence) const 152 + float classify(const Template &src, bool process, float *confidence) const
153 { 153 {
154 - Mat m;  
155 - if (process)  
156 - m = preprocess(image);  
157 - else  
158 - m = image; 154 + Template t = process ? preprocess(src) : src;
159 155
160 float sum = 0; 156 float sum = 0;
161 for (int i = 0; i < classifiers.size(); i++) { 157 for (int i = 0; i < classifiers.size(); i++) {
@@ -163,10 +159,10 @@ private: @@ -163,10 +159,10 @@ private:
163 159
164 while (node->left) { 160 while (node->left) {
165 if (representation->maxCatCount() > 0) { 161 if (representation->maxCatCount() > 0) {
166 - int c = (int)representation->evaluate(m, node->featureIdx); 162 + int c = (int)representation->evaluate(t, node->featureIdx);
167 node = (node->subset[c >> 5] & (1 << (c & 31))) ? node->left : node->right; 163 node = (node->subset[c >> 5] & (1 << (c & 31))) ? node->left : node->right;
168 } else { 164 } else {
169 - double val = representation->evaluate(m, node->featureIdx); 165 + double val = representation->evaluate(t, node->featureIdx);
170 node = val <= node->threshold ? node->left : node->right; 166 node = val <= node->threshold ? node->left : node->right;
171 } 167 }
172 } 168 }
@@ -184,11 +180,9 @@ private: @@ -184,11 +180,9 @@ private:
184 return representation->numFeatures(); 180 return representation->numFeatures();
185 } 181 }
186 182
187 - Mat preprocess(const Mat &image) const 183 + Template preprocess(const Template &src) const
188 { 184 {
189 - Mat dst;  
190 - representation->preprocess(image, dst);  
191 - return dst; 185 + return representation->preprocess(src);
192 } 186 }
193 187
194 Size windowSize(int *dx, int *dy) const 188 Size windowSize(int *dx, int *dy) const
openbr/plugins/classification/cascade.cpp
1 #include <opencv2/imgproc/imgproc.hpp> 1 #include <opencv2/imgproc/imgproc.hpp>
2 -#include <opencv2/highgui/highgui.hpp> 2 +
3 #include <openbr/plugins/openbr_internal.h> 3 #include <openbr/plugins/openbr_internal.h>
4 #include <openbr/core/common.h> 4 #include <openbr/core/common.h>
  5 +#include "openbr/core/opencvutils.h"
5 6
6 #include <QtConcurrent> 7 #include <QtConcurrent>
7 8
@@ -37,7 +38,7 @@ struct Miner @@ -37,7 +38,7 @@ struct Miner
37 Mat mine(bool *newImg) 38 Mat mine(bool *newImg)
38 { 39 {
39 // Copy region of winSize region of img into m 40 // Copy region of winSize region of img into m
40 - Mat window(windowSize.height, windowSize.width, CV_8UC1, 41 + Mat window(windowSize.height, windowSize.width, CV_8U,
41 (void*)(scaledSrc.data + point.y * scaledSrc.step + point.x * scaledSrc.elemSize()), 42 (void*)(scaledSrc.data + point.y * scaledSrc.step + point.x * scaledSrc.elemSize()),
42 scaledSrc.step); 43 scaledSrc.step);
43 44
@@ -100,31 +101,30 @@ class CascadeClassifier : public Classifier @@ -100,31 +101,30 @@ class CascadeClassifier : public Classifier
100 BR_PROPERTY(bool, requireAllStages, false) 101 BR_PROPERTY(bool, requireAllStages, false)
101 102
102 QList<Classifier *> stages; 103 QList<Classifier *> stages;
103 - QList<Mat> posImages, negImages;  
104 - QList<Mat> posSamples, negSamples; 104 + TemplateList posImages, negImages;
  105 + TemplateList posSamples, negSamples;
105 106
106 QList<int> indices; 107 QList<int> indices;
107 int negIndex, posIndex, samplingRound; 108 int negIndex, posIndex, samplingRound;
108 109
109 - QMutex samplingMutex, miningMutex, passedMutex; 110 + QMutex samplingMutex, miningMutex;
110 111
111 void init() 112 void init()
112 { 113 {
113 negIndex = posIndex = samplingRound = 0; 114 negIndex = posIndex = samplingRound = 0;
114 } 115 }
115 116
116 - bool getPositive(Mat &img) 117 + bool getPositive(Template &img)
117 { 118 {
118 if (posIndex >= posImages.size()) 119 if (posIndex >= posImages.size())
119 return false; 120 return false;
120 -  
121 - posImages[indices[posIndex++]].copyTo(img); 121 + img = posImages[indices[posIndex++]];
122 return true; 122 return true;
123 } 123 }
124 124
125 - Mat getNegative(Point &offset) 125 + Template getNegative(Point &offset)
126 { 126 {
127 - Mat negative; 127 + Template negative;
128 128
129 const Size size = windowSize(); 129 const Size size = windowSize();
130 // Grab negative from list 130 // Grab negative from list
@@ -136,9 +136,9 @@ class CascadeClassifier : public Classifier @@ -136,9 +136,9 @@ class CascadeClassifier : public Classifier
136 samplingRound = samplingRound % (size.width * size.height); 136 samplingRound = samplingRound % (size.width * size.height);
137 negIndex %= count; 137 negIndex %= count;
138 138
139 - offset.x = qMin( (int)samplingRound % size.width, negative.cols - size.width);  
140 - offset.y = qMin( (int)samplingRound / size.width, negative.rows - size.height);  
141 - if (!negative.empty() && negative.type() == CV_8UC1 139 + offset.x = qMin( (int)samplingRound % size.width, negative.m().cols - size.width);
  140 + offset.y = qMin( (int)samplingRound / size.width, negative.m().rows - size.height);
  141 + if (!negative.m().empty() && negative.m().type() == CV_8U
142 && offset.x >= 0 && offset.y >= 0) 142 && offset.x >= 0 && offset.y >= 0)
143 break; 143 break;
144 } 144 }
@@ -146,35 +146,32 @@ class CascadeClassifier : public Classifier @@ -146,35 +146,32 @@ class CascadeClassifier : public Classifier
146 return negative; 146 return negative;
147 } 147 }
148 148
149 - int mine() 149 + uint64 mine()
150 { 150 {
151 - int passedNegatives = 0; 151 + uint64 passedNegatives = 0;
152 forever { 152 forever {
153 - Mat negative; 153 + Template negative;
154 Point offset; 154 Point offset;
155 - samplingMutex.lock(); 155 + QMutexLocker samplingLocker(&samplingMutex);
156 negative = getNegative(offset); 156 negative = getNegative(offset);
157 - samplingMutex.unlock(); 157 + samplingLocker.unlock();
158 158
159 - Miner miner(negative, windowSize(), offset); 159 + Miner miner(negative.m(), windowSize(), offset);
160 forever { 160 forever {
161 bool newImg; 161 bool newImg;
162 - Mat sample = miner.mine(&newImg); 162 + Template sample(negative.file, miner.mine(&newImg));
163 if (!newImg) { 163 if (!newImg) {
164 if (negSamples.size() >= numNegs) 164 if (negSamples.size() >= numNegs)
165 return passedNegatives; 165 return passedNegatives;
166 166
167 float confidence; 167 float confidence;
168 if (classify(sample, true, &confidence) != 0) { 168 if (classify(sample, true, &confidence) != 0) {
169 - miningMutex.lock();  
170 - if (negSamples.size() >= numNegs) {  
171 - miningMutex.unlock(); 169 + QMutexLocker miningLocker(&miningMutex);
  170 + if (negSamples.size() >= numNegs)
172 return passedNegatives; 171 return passedNegatives;
173 - }  
174 172
175 negSamples.append(sample); 173 negSamples.append(sample);
176 printf("Negative samples: %d\r", negSamples.size()); 174 printf("Negative samples: %d\r", negSamples.size());
177 - miningMutex.unlock();  
178 } 175 }
179 176
180 passedNegatives++; 177 passedNegatives++;
@@ -184,16 +181,16 @@ class CascadeClassifier : public Classifier @@ -184,16 +181,16 @@ class CascadeClassifier : public Classifier
184 } 181 }
185 } 182 }
186 183
187 - void train(const QList<Mat> &images, const QList<float> &labels) 184 + void train(const TemplateList &data)
188 { 185 {
189 - for (int i = 0; i < images.size(); i++)  
190 - labels[i] == 1 ? posImages.append(images[i]) : negImages.append(images[i]); 186 + foreach (const Template &t, data)
  187 + t.file.get<float>("Label") == 1.0f ? posImages.append(t) : negImages.append(t);
191 188
192 - qDebug() << "Total images:" << images.size() 189 + qDebug() << "Total images:" << data.size()
193 << "\nTotal positive images:" << posImages.size() 190 << "\nTotal positive images:" << posImages.size()
194 << "\nTotal negative images:" << negImages.size(); 191 << "\nTotal negative images:" << negImages.size();
195 192
196 - indices = Common::RandSample(posImages.size(),posImages.size(),true); 193 + indices = Common::RandSample(posImages.size(), posImages.size(), true);
197 194
198 stages.reserve(numStages); 195 stages.reserve(numStages);
199 for (int i = 0; i < numStages; i++) { 196 for (int i = 0; i < numStages; i++) {
@@ -212,27 +209,17 @@ class CascadeClassifier : public Classifier @@ -212,27 +209,17 @@ class CascadeClassifier : public Classifier
212 return; 209 return;
213 } 210 }
214 211
215 - QList<float> posLabels;  
216 - posLabels.reserve(posSamples.size());  
217 - for (int j=0; j<posSamples.size(); j++)  
218 - posLabels.append(1);  
219 -  
220 - QList<float> negLabels;  
221 - negLabels.reserve(negSamples.size());  
222 - for (int j=0; j<negSamples.size(); j++)  
223 - negLabels.append(0);  
224 -  
225 - stages[i]->train(posSamples+negSamples, posLabels+negLabels); 212 + stages[i]->train(posSamples + negSamples);
226 213
227 qDebug() << "END>"; 214 qDebug() << "END>";
228 } 215 }
229 } 216 }
230 217
231 - float classify(const Mat &image, bool process, float *confidence) const 218 + float classify(const Template &src, bool process, float *confidence) const
232 { 219 {
233 float stageConf = 0.0f; 220 float stageConf = 0.0f;
234 foreach (const Classifier *stage, stages) { 221 foreach (const Classifier *stage, stages) {
235 - float result = stage->classify(image, process, &stageConf); 222 + float result = stage->classify(src, process, &stageConf);
236 if (confidence) 223 if (confidence)
237 *confidence += stageConf; 224 *confidence += stageConf;
238 if (result == 0.0f) 225 if (result == 0.0f)
@@ -246,9 +233,9 @@ class CascadeClassifier : public Classifier @@ -246,9 +233,9 @@ class CascadeClassifier : public Classifier
246 return stages.first()->numFeatures(); 233 return stages.first()->numFeatures();
247 } 234 }
248 235
249 - Mat preprocess(const Mat &image) const 236 + Template preprocess(const Template &src) const
250 { 237 {
251 - return stages.first()->preprocess(image); 238 + return stages.first()->preprocess(src);
252 } 239 }
253 240
254 Size windowSize(int *dx = NULL, int *dy = NULL) const 241 Size windowSize(int *dx = NULL, int *dy = NULL) const
@@ -276,16 +263,13 @@ class CascadeClassifier : public Classifier @@ -276,16 +263,13 @@ class CascadeClassifier : public Classifier
276 private: 263 private:
277 float getSamples() 264 float getSamples()
278 { 265 {
279 - posSamples.clear();  
280 - posSamples.reserve(numPos);  
281 - negSamples.clear();  
282 - negSamples.reserve(numNegs); 266 + posSamples.clear(); posSamples.reserve(numPos);
  267 + negSamples.clear(); negSamples.reserve(numNegs);
283 posIndex = 0; 268 posIndex = 0;
284 269
285 float confidence; 270 float confidence;
286 while (posSamples.size() < numPos) { 271 while (posSamples.size() < numPos) {
287 - Mat pos(windowSize(), CV_8UC1);  
288 - 272 + Template pos;
289 if (!getPositive(pos)) 273 if (!getPositive(pos))
290 qFatal("Cannot get another positive sample!"); 274 qFatal("Cannot get another positive sample!");
291 275
@@ -297,13 +281,13 @@ private: @@ -297,13 +281,13 @@ private:
297 281
298 qDebug() << "POS count : consumed " << posSamples.size() << ":" << posIndex; 282 qDebug() << "POS count : consumed " << posSamples.size() << ":" << posIndex;
299 283
300 - QFutureSynchronizer<int> futures; 284 + QFutureSynchronizer<uint64> futures;
301 for (int i=0; i<QThread::idealThreadCount(); i++) 285 for (int i=0; i<QThread::idealThreadCount(); i++)
302 futures.addFuture(QtConcurrent::run(this, &CascadeClassifier::mine)); 286 futures.addFuture(QtConcurrent::run(this, &CascadeClassifier::mine));
303 futures.waitForFinished(); 287 futures.waitForFinished();
304 288
305 - int passedNegs = 0;  
306 - QList<QFuture<int> > results = futures.futures(); 289 + uint64 passedNegs = 0;
  290 + QList<QFuture<uint64> > results = futures.futures();
307 for (int i=0; i<results.size(); i++) 291 for (int i=0; i<results.size(); i++)
308 passedNegs += results[i].result(); 292 passedNegs += results[i].result();
309 293
openbr/plugins/classification/dlib.cpp
  1 +#include <opencv2/imgproc/imgproc.hpp>
1 #include <dlib/image_processing/frontal_face_detector.h> 2 #include <dlib/image_processing/frontal_face_detector.h>
2 #include <dlib/opencv.h> 3 #include <dlib/opencv.h>
3 4
@@ -45,14 +46,18 @@ private: @@ -45,14 +46,18 @@ private:
45 { 46 {
46 dst = src; 47 dst = src;
47 48
48 - shape_predictor *sp = shapeResource.acquire(); 49 + shape_predictor *const sp = shapeResource.acquire();
49 50
50 - cv_image<unsigned char> cimg(src.m()); 51 + cv::Mat cvImage = src.m();
  52 + if (cvImage.channels() == 3)
  53 + cv::cvtColor(cvImage, cvImage, CV_BGR2GRAY);
  54 +
  55 + cv_image<unsigned char> cimg(cvImage);
51 array2d<unsigned char> image; 56 array2d<unsigned char> image;
52 assign_image(image,cimg); 57 assign_image(image,cimg);
53 58
54 if (src.file.rects().isEmpty()) { //If the image has no rects assume the whole image is a face 59 if (src.file.rects().isEmpty()) { //If the image has no rects assume the whole image is a face
55 - rectangle r(0, 0, src.m().cols, src.m().rows); 60 + rectangle r(0, 0, cvImage.cols, cvImage.rows);
56 full_object_detection shape = (*sp)(image, r); 61 full_object_detection shape = (*sp)(image, r);
57 for (size_t i = 0; i < shape.num_parts(); i++) 62 for (size_t i = 0; i < shape.num_parts(); i++)
58 dst.file.appendPoint(QPointF(shape.part(i)(0),shape.part(i)(1))); 63 dst.file.appendPoint(QPointF(shape.part(i)(0),shape.part(i)(1)));
openbr/plugins/classification/liblinear.cpp
@@ -138,7 +138,7 @@ private: @@ -138,7 +138,7 @@ private:
138 param.weight = NULL; 138 param.weight = NULL;
139 } 139 }
140 140
141 - m = *train_svm(&prob, &param); 141 + //m = *train_svm(&prob, &param);
142 142
143 delete[] param.weight; 143 delete[] param.weight;
144 delete[] param.weight_label; 144 delete[] param.weight_label;
openbr/plugins/core/algorithms.cpp
@@ -39,7 +39,7 @@ class AlgorithmsInitializer : public Initializer @@ -39,7 +39,7 @@ class AlgorithmsInitializer : public Initializer
39 Globals->abbreviations.insert("FR_Mouth", "(CropFromLandmarks([59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76])+Resize(24,48))"); 39 Globals->abbreviations.insert("FR_Mouth", "(CropFromLandmarks([59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76])+Resize(24,48))");
40 Globals->abbreviations.insert("FR_Nose", "(CropFromLandmarks([16,17,18,19,20,21,22,23,24,25,26,27],padding=3)+Resize(36,36))"); 40 Globals->abbreviations.insert("FR_Nose", "(CropFromLandmarks([16,17,18,19,20,21,22,23,24,25,26,27],padding=3)+Resize(36,36))");
41 Globals->abbreviations.insert("FR_Face", "(Crop(24,24,88,88)+Resize(44,44))"); 41 Globals->abbreviations.insert("FR_Face", "(Crop(24,24,88,88)+Resize(44,44))");
42 - Globals->abbreviations.insert("FR_Detect", "(FaceDetection+Stasm+Rename(StasmLeftEye,Affine_1,true)+Rename(StasmRightEye,Affine_0,true)+Affine(136,136,0.35,0.35,warpPoints=true))"); 42 + Globals->abbreviations.insert("FR_Detect", "(Open+Cvt(Gray)+Cascade+Stasm+Rename(StasmLeftEye,Affine_1,true)+Rename(StasmRightEye,Affine_0,true)+Affine(136,136,0.35,0.35,warpPoints=true))");
43 Globals->abbreviations.insert("FR_Represent", "((DenseHOG/DenseLBP)+Cat+LDA(.98)+Normalize(L2))"); 43 Globals->abbreviations.insert("FR_Represent", "((DenseHOG/DenseLBP)+Cat+LDA(.98)+Normalize(L2))");
44 44
45 Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+FaceClassificationRegistration+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); 45 Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+FaceClassificationRegistration+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard");
openbr/plugins/distance/unit.cpp
@@ -76,12 +76,18 @@ class UnitDistance : public Distance @@ -76,12 +76,18 @@ class UnitDistance : public Distance
76 76
77 float compare(const Template &target, const Template &query) const 77 float compare(const Template &target, const Template &query) const
78 { 78 {
79 - return a * (distance->compare(target, query) - b); 79 + return normalize(distance->compare(target, query));
80 } 80 }
81 81
82 float compare(const cv::Mat &target, const cv::Mat &query) const 82 float compare(const cv::Mat &target, const cv::Mat &query) const
83 { 83 {
84 - return a * (distance->compare(target, query) - b); 84 + return normalize(distance->compare(target, query));
  85 + }
  86 +
  87 + float normalize(float score) const
  88 + {
  89 + if (!Globals->scoreNormalization) return score;
  90 + return a * (score - b);
85 } 91 }
86 }; 92 };
87 93
openbr/plugins/gallery/keyframes.cpp
@@ -26,6 +26,12 @@ extern &quot;C&quot; @@ -26,6 +26,12 @@ extern &quot;C&quot;
26 #include <libswscale/swscale.h> 26 #include <libswscale/swscale.h>
27 } 27 }
28 28
  29 +// http://stackoverflow.com/questions/24057248/ffmpeg-undefined-references-to-av-frame-alloc
  30 +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
  31 +#define av_frame_alloc avcodec_alloc_frame
  32 +#define av_frame_free avcodec_free_frame
  33 +#endif
  34 +
29 using namespace cv; 35 using namespace cv;
30 36
31 namespace br 37 namespace br
openbr/plugins/imgproc/equalizehist.cpp
@@ -18,6 +18,8 @@ @@ -18,6 +18,8 @@
18 18
19 #include <openbr/plugins/openbr_internal.h> 19 #include <openbr/plugins/openbr_internal.h>
20 20
  21 +using namespace cv;
  22 +
21 namespace br 23 namespace br
22 { 24 {
23 25
@@ -32,7 +34,20 @@ class EqualizeHistTransform : public UntrainableTransform @@ -32,7 +34,20 @@ class EqualizeHistTransform : public UntrainableTransform
32 34
33 void project(const Template &src, Template &dst) const 35 void project(const Template &src, Template &dst) const
34 { 36 {
35 - cv::equalizeHist(src, dst); 37 + if (src.m().channels() == 1) {
  38 + equalizeHist(src, dst);
  39 + } else if (src.m().channels() == 3) {
  40 + // http://stackoverflow.com/questions/15007304/histogram-equalization-not-working-on-color-image-opencv
  41 + Mat ycrcb;
  42 + cvtColor(src, ycrcb, CV_BGR2YCrCb);
  43 + vector<Mat> channels;
  44 + split(ycrcb, channels);
  45 + equalizeHist(channels[0], channels[0]);
  46 + merge(channels, ycrcb);
  47 + cvtColor(ycrcb, dst, CV_YCrCb2BGR);
  48 + } else {
  49 + qFatal("Invalid channel count!");
  50 + }
36 } 51 }
37 }; 52 };
38 53
openbr/plugins/imgproc/pad.cpp
  1 +#include <opencv2/imgproc/imgproc.hpp>
1 #include <openbr/plugins/openbr_internal.h> 2 #include <openbr/plugins/openbr_internal.h>
2 3
3 using namespace cv; 4 using namespace cv;
@@ -5,24 +6,36 @@ using namespace cv; @@ -5,24 +6,36 @@ using namespace cv;
5 namespace br 6 namespace br
6 { 7 {
7 8
  9 +/*!
  10 + * \ingroup transforms
  11 + * \brief Pads an image.
  12 + * \author Scott Klum \cite sklum
  13 + */
8 class PadTransform : public UntrainableTransform 14 class PadTransform : public UntrainableTransform
9 { 15 {
10 Q_OBJECT 16 Q_OBJECT
11 -  
12 - Q_PROPERTY(int padSize READ get_padSize WRITE set_padSize RESET reset_padSize STORED false)  
13 - Q_PROPERTY(int padValue READ get_padValue WRITE set_padValue RESET reset_padValue STORED false)  
14 - BR_PROPERTY(int, padSize, 0)  
15 - BR_PROPERTY(int, padValue, 0) 17 + Q_ENUMS(Method)
  18 +
  19 +public:
  20 + /*!< */
  21 + enum Border { Replicate = BORDER_REPLICATE,
  22 + Reflect = BORDER_REFLECT_101,
  23 + Constant = BORDER_CONSTANT};
  24 +
  25 +private:
  26 + Q_PROPERTY(Border border READ get_border WRITE set_border RESET reset_border STORED false)
  27 + Q_PROPERTY(float percent READ get_percent WRITE set_percent RESET reset_percent STORED false)
  28 + Q_PROPERTY(int value READ get_value WRITE set_value RESET reset_value STORED false)
  29 + BR_PROPERTY(Border, border, Replicate)
  30 + BR_PROPERTY(float, percent, .1)
  31 + BR_PROPERTY(float, value, 0)
16 32
17 void project(const Template &src, Template &dst) const 33 void project(const Template &src, Template &dst) const
18 { 34 {
19 - dst.file = src.file;  
20 -  
21 - foreach (const Mat &m, src) {  
22 - Mat padded = padValue * Mat::ones(m.rows + 2*padSize, m.cols + 2*padSize, m.type());  
23 - padded(Rect(padSize, padSize, padded.cols - padSize, padded.rows - padSize)) = m;  
24 - dst += padded;  
25 - } 35 + int top, bottom, left, right;
  36 + top = percent*src.m().rows; bottom = percent*src.m().rows;
  37 + left = percent*src.m().cols; right = percent*src.m().cols;
  38 + copyMakeBorder(src, dst, top, bottom, left, right, border, Scalar(value));
26 } 39 }
27 }; 40 };
28 41
openbr/plugins/imgproc/resize.cpp
@@ -55,9 +55,15 @@ private: @@ -55,9 +55,15 @@ private:
55 55
56 void project(const Template &src, Template &dst) const 56 void project(const Template &src, Template &dst) const
57 { 57 {
58 - if (!preserveAspect) 58 + if (!preserveAspect) {
59 resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method); 59 resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method);
60 - else { 60 + const float rowScaleFactor = (float)rows/src.m().rows;
  61 + const float colScaleFactor = (float)columns/src.m().cols;
  62 + QList<QPointF> points = src.file.points();
  63 + for (int i=0; i<points.size(); i++)
  64 + points[i] = QPointF(points[i].x() * colScaleFactor,points[i].y() * rowScaleFactor);
  65 + dst.file.setPoints(points);
  66 + } else {
61 float inRatio = (float) src.m().rows / src.m().cols; 67 float inRatio = (float) src.m().rows / src.m().cols;
62 float outRatio = (float) rows / columns; 68 float outRatio = (float) rows / columns;
63 dst = Mat::zeros(rows, columns, src.m().type()); 69 dst = Mat::zeros(rows, columns, src.m().type());
openbr/plugins/imgproc/rndrotate.cpp
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 16
17 #include <opencv2/imgproc/imgproc.hpp> 17 #include <opencv2/imgproc/imgproc.hpp>
18 #include <openbr/plugins/openbr_internal.h> 18 #include <openbr/plugins/openbr_internal.h>
  19 +#include <openbr/core/opencvutils.h>
19 20
20 using namespace cv; 21 using namespace cv;
21 22
@@ -32,12 +33,14 @@ class RndRotateTransform : public UntrainableTransform @@ -32,12 +33,14 @@ class RndRotateTransform : public UntrainableTransform
32 Q_OBJECT 33 Q_OBJECT
33 34
34 Q_PROPERTY(QList<int> range READ get_range WRITE set_range RESET reset_range STORED false) 35 Q_PROPERTY(QList<int> range READ get_range WRITE set_range RESET reset_range STORED false)
  36 + Q_PROPERTY(int center READ get_center WRITE set_center RESET reset_center STORED false)
35 BR_PROPERTY(QList<int>, range, QList<int>() << -15 << 15) 37 BR_PROPERTY(QList<int>, range, QList<int>() << -15 << 15)
  38 + BR_PROPERTY(int, center, -1)
36 39
37 void project(const Template &src, Template &dst) const { 40 void project(const Template &src, Template &dst) const {
38 int span = range.first() - range.last(); 41 int span = range.first() - range.last();
39 - int angle = (rand() % span) + range.first();  
40 - Mat rotMatrix = getRotationMatrix2D(Point2f(src.m().rows/2,src.m().cols/2),angle,1.0); 42 + int angle = span == 0 ? range.first() : (rand() % span) + range.first();
  43 + Mat rotMatrix = getRotationMatrix2D(center == -1 ? Point2f(src.m().rows/2,src.m().cols/2) : OpenCVUtils::toPoint(src.file.points()[center]),angle,1.0);
41 warpAffine(src,dst,rotMatrix,Size(src.m().cols,src.m().rows),INTER_LINEAR,BORDER_REFLECT_101); 44 warpAffine(src,dst,rotMatrix,Size(src.m().cols,src.m().rows),INTER_LINEAR,BORDER_REFLECT_101);
42 45
43 QList<QPointF> points = src.file.points(); 46 QList<QPointF> points = src.file.points();
openbr/plugins/imgproc/roi.cpp
@@ -34,8 +34,10 @@ class ROITransform : public UntrainableTransform @@ -34,8 +34,10 @@ class ROITransform : public UntrainableTransform
34 Q_OBJECT 34 Q_OBJECT
35 Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) 35 Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false)
36 Q_PROPERTY(bool copyOnCrop READ get_copyOnCrop WRITE set_copyOnCrop RESET reset_copyOnCrop STORED false) 36 Q_PROPERTY(bool copyOnCrop READ get_copyOnCrop WRITE set_copyOnCrop RESET reset_copyOnCrop STORED false)
  37 + Q_PROPERTY(int shiftPoints READ get_shiftPoints WRITE set_shiftPoints RESET reset_shiftPoints STORED false)
37 BR_PROPERTY(QString, propName, "") 38 BR_PROPERTY(QString, propName, "")
38 BR_PROPERTY(bool, copyOnCrop, false) 39 BR_PROPERTY(bool, copyOnCrop, false)
  40 + BR_PROPERTY(int, shiftPoints, -1)
39 41
40 void project(const Template &src, Template &dst) const 42 void project(const Template &src, Template &dst) const
41 { 43 {
@@ -55,6 +57,16 @@ class ROITransform : public UntrainableTransform @@ -55,6 +57,16 @@ class ROITransform : public UntrainableTransform
55 if (Globals->verbose) 57 if (Globals->verbose)
56 qWarning("No rects present in file."); 58 qWarning("No rects present in file.");
57 } 59 }
  60 +
  61 + if (shiftPoints != -1) {
  62 + // Shift the points to the rect with the index provided
  63 + QRectF rect = src.file.rects()[shiftPoints];
  64 + QList<QPointF> points = src.file.points();
  65 + for (int i=0; i<points.size(); i++)
  66 + points[i] -= rect.topLeft();
  67 + dst.file.setPoints(points);
  68 + }
  69 +
58 dst.file.clearRects(); 70 dst.file.clearRects();
59 71
60 if (copyOnCrop) 72 if (copyOnCrop)
openbr/plugins/imgproc/slidingwindow.cpp
@@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
17 #include <openbr/plugins/openbr_internal.h> 17 #include <openbr/plugins/openbr_internal.h>
18 #include <openbr/core/opencvutils.h> 18 #include <openbr/core/opencvutils.h>
19 #include <openbr/core/qtutils.h> 19 #include <openbr/core/qtutils.h>
20 -#include <opencv2/highgui/highgui.hpp>  
21 20
22 #include <opencv2/imgproc/imgproc.hpp> 21 #include <opencv2/imgproc/imgproc.hpp>
23 22
@@ -35,7 +34,6 @@ namespace br @@ -35,7 +34,6 @@ namespace br
35 * \br_property int minSize The smallest sized object to detect in pixels 34 * \br_property int minSize The smallest sized object to detect in pixels
36 * \br_property int maxSize The largest sized object to detect in pixels. A negative value will set maxSize == image size 35 * \br_property int maxSize The largest sized object to detect in pixels. A negative value will set maxSize == image size
37 * \br_property float scaleFactor The factor to scale the image by during each resize. 36 * \br_property float scaleFactor The factor to scale the image by during each resize.
38 - * \br_property int minNeighbors Parameter for non-maximum supression  
39 * \br_property float confidenceThreshold A threshold for positive detections. Positive detections returned by the classifier that have confidences below this threshold are considered negative detections. 37 * \br_property float confidenceThreshold A threshold for positive detections. Positive detections returned by the classifier that have confidences below this threshold are considered negative detections.
40 * \br_property float eps Parameter for non-maximum supression 38 * \br_property float eps Parameter for non-maximum supression
41 */ 39 */
@@ -50,6 +48,7 @@ class SlidingWindowTransform : public MetaTransform @@ -50,6 +48,7 @@ class SlidingWindowTransform : public MetaTransform
50 Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) 48 Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
51 Q_PROPERTY(float confidenceThreshold READ get_confidenceThreshold WRITE set_confidenceThreshold RESET reset_confidenceThreshold STORED false) 49 Q_PROPERTY(float confidenceThreshold READ get_confidenceThreshold WRITE set_confidenceThreshold RESET reset_confidenceThreshold STORED false)
52 Q_PROPERTY(float eps READ get_eps WRITE set_eps RESET reset_eps STORED false) 50 Q_PROPERTY(float eps READ get_eps WRITE set_eps RESET reset_eps STORED false)
  51 + Q_PROPERTY(float minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false)
53 52
54 BR_PROPERTY(br::Classifier*, classifier, NULL) 53 BR_PROPERTY(br::Classifier*, classifier, NULL)
55 BR_PROPERTY(int, minSize, 20) 54 BR_PROPERTY(int, minSize, 20)
@@ -57,10 +56,11 @@ class SlidingWindowTransform : public MetaTransform @@ -57,10 +56,11 @@ class SlidingWindowTransform : public MetaTransform
57 BR_PROPERTY(float, scaleFactor, 1.2) 56 BR_PROPERTY(float, scaleFactor, 1.2)
58 BR_PROPERTY(float, confidenceThreshold, 10) 57 BR_PROPERTY(float, confidenceThreshold, 10)
59 BR_PROPERTY(float, eps, 0.2) 58 BR_PROPERTY(float, eps, 0.2)
  59 + BR_PROPERTY(int, minNeighbors, 3)
60 60
61 void train(const TemplateList &data) 61 void train(const TemplateList &data)
62 { 62 {
63 - classifier->train(data.data(), File::get<float>(data, "Label", -1)); 63 + classifier->train(data);
64 } 64 }
65 65
66 void project(const Template &src, Template &dst) const 66 void project(const Template &src, Template &dst) const
@@ -123,15 +123,18 @@ class SlidingWindowTransform : public MetaTransform @@ -123,15 +123,18 @@ class SlidingWindowTransform : public MetaTransform
123 123
124 Mat scaledImage(scaledImageSize, CV_8U, imageBuffer.data); 124 Mat scaledImage(scaledImageSize, CV_8U, imageBuffer.data);
125 resize(m, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR); 125 resize(m, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR);
126 - Mat repImage = classifier->preprocess(scaledImage); 126 +
  127 + Template repImage(t.file, scaledImage);
  128 + repImage = classifier->preprocess(repImage);
127 129
128 int step = factor > 2. ? 1 : 2; 130 int step = factor > 2. ? 1 : 2;
129 for (int y = 0; y < processingRectSize.height; y += step) { 131 for (int y = 0; y < processingRectSize.height; y += step) {
130 for (int x = 0; x < processingRectSize.width; x += step) { 132 for (int x = 0; x < processingRectSize.width; x += step) {
131 - Mat window = repImage(Rect(Point(x, y), Size(originalWindowSize.width + dx, originalWindowSize.height + dy))).clone(); 133 + Mat window = repImage.m()(Rect(Point(x, y), Size(originalWindowSize.width + dx, originalWindowSize.height + dy))).clone();
  134 + Template t(window);
132 135
133 float confidence = 0; 136 float confidence = 0;
134 - int result = classifier->classify(window, false, &confidence); 137 + int result = classifier->classify(t, false, &confidence);
135 138
136 if (result == 1) { 139 if (result == 1) {
137 rects.append(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height)); 140 rects.append(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height));
@@ -146,7 +149,7 @@ class SlidingWindowTransform : public MetaTransform @@ -146,7 +149,7 @@ class SlidingWindowTransform : public MetaTransform
146 } 149 }
147 } 150 }
148 151
149 - OpenCVUtils::group(rects, confidences, confidenceThreshold, eps); 152 + OpenCVUtils::group(rects, confidences, confidenceThreshold, minNeighbors, eps);
150 153
151 if (!enrollAll && rects.empty()) { 154 if (!enrollAll && rects.empty()) {
152 rects.append(Rect(0, 0, m.cols, m.rows)); 155 rects.append(Rect(0, 0, m.cols, m.rows));
openbr/plugins/metadata/averagepoints.cpp
@@ -14,23 +14,14 @@ class AveragePointsTransform : public UntrainableMetadataTransform @@ -14,23 +14,14 @@ class AveragePointsTransform : public UntrainableMetadataTransform
14 Q_PROPERTY(QList<int> indices READ get_indices WRITE set_indices RESET reset_indices STORED false) 14 Q_PROPERTY(QList<int> indices READ get_indices WRITE set_indices RESET reset_indices STORED false)
15 Q_PROPERTY(QString metaName READ get_metaName WRITE set_metaName RESET reset_metaName STORED true) 15 Q_PROPERTY(QString metaName READ get_metaName WRITE set_metaName RESET reset_metaName STORED true)
16 Q_PROPERTY(bool append READ get_append WRITE set_append RESET reset_append STORED true) 16 Q_PROPERTY(bool append READ get_append WRITE set_append RESET reset_append STORED true)
17 - Q_PROPERTY(int nLandmarks READ get_nLandmarks WRITE set_nLandmarks RESET reset_nLandmarks STORED true)  
18 BR_PROPERTY(QList<int>, indices, QList<int>()) 17 BR_PROPERTY(QList<int>, indices, QList<int>())
19 BR_PROPERTY(QString, metaName, "") 18 BR_PROPERTY(QString, metaName, "")
20 BR_PROPERTY(bool, append, false) 19 BR_PROPERTY(bool, append, false)
21 - BR_PROPERTY(int, nLandmarks, 51)  
22 20
23 void projectMetadata(const File &src, File &dst) const 21 void projectMetadata(const File &src, File &dst) const
24 { 22 {
25 dst = src; 23 dst = src;
26 - if (src.points().size() != nLandmarks) {  
27 - if (Globals->verbose)  
28 - qDebug() << "Warning: Face has " << src.points().size() << "points; should be " << nLandmarks;  
29 - dst.fte = true;  
30 - return;  
31 - }  
32 - int x1 = 0,  
33 - y1 = 0; 24 + float x1 = 0, y1 = 0;
34 25
35 for (int i = 0; i < indices.size(); i++) { 26 for (int i = 0; i < indices.size(); i++) {
36 x1 += src.points()[indices[i]].x(); 27 x1 += src.points()[indices[i]].x();
openbr/plugins/metadata/cascade.cpp
@@ -202,7 +202,8 @@ class CascadeTransform : public MetaTransform @@ -202,7 +202,8 @@ class CascadeTransform : public MetaTransform
202 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) 202 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false)
203 Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false) 203 Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false)
204 Q_PROPERTY(bool ROCMode READ get_ROCMode WRITE set_ROCMode RESET reset_ROCMode STORED false) 204 Q_PROPERTY(bool ROCMode READ get_ROCMode WRITE set_ROCMode RESET reset_ROCMode STORED false)
205 - 205 + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
  206 +
206 // Training parameters 207 // Training parameters
207 Q_PROPERTY(int numStages READ get_numStages WRITE set_numStages RESET reset_numStages STORED false) 208 Q_PROPERTY(int numStages READ get_numStages WRITE set_numStages RESET reset_numStages STORED false)
208 Q_PROPERTY(int w READ get_w WRITE set_w RESET reset_w STORED false) 209 Q_PROPERTY(int w READ get_w WRITE set_w RESET reset_w STORED false)
@@ -227,7 +228,8 @@ class CascadeTransform : public MetaTransform @@ -227,7 +228,8 @@ class CascadeTransform : public MetaTransform
227 BR_PROPERTY(int, minSize, 64) 228 BR_PROPERTY(int, minSize, 64)
228 BR_PROPERTY(int, minNeighbors, 5) 229 BR_PROPERTY(int, minNeighbors, 5)
229 BR_PROPERTY(bool, ROCMode, false) 230 BR_PROPERTY(bool, ROCMode, false)
230 - 231 + BR_PROPERTY(float, scaleFactor, 1.2)
  232 +
231 // Training parameters - Default values provided trigger OpenCV defaults 233 // Training parameters - Default values provided trigger OpenCV defaults
232 BR_PROPERTY(int, numStages, -1) 234 BR_PROPERTY(int, numStages, -1)
233 BR_PROPERTY(int, w, -1) 235 BR_PROPERTY(int, w, -1)
@@ -410,8 +412,19 @@ class CascadeTransform : public MetaTransform @@ -410,8 +412,19 @@ class CascadeTransform : public MetaTransform
410 std::vector<Rect> rects; 412 std::vector<Rect> rects;
411 std::vector<int> rejectLevels; 413 std::vector<int> rejectLevels;
412 std::vector<double> levelWeights; 414 std::vector<double> levelWeights;
413 - if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, minNeighbors, flags | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true);  
414 - else cascade->detectMultiScale(m, rects, 1.2, minNeighbors, flags, Size(minSize, minSize)); 415 + if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, scaleFactor, minNeighbors, flags | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true);
  416 + else cascade->detectMultiScale(m, rects, scaleFactor, minNeighbors, flags, Size(minSize, minSize));
  417 +
  418 + // It appears that flags is ignored for new model files:
  419 + // http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html#cascadeclassifier-detectmultiscale
  420 + if ((flags == CASCADE_FIND_BIGGEST_OBJECT) && (rects.size() > 1)) {
  421 + Rect biggest = rects[0];
  422 + for (size_t j=0; j<rects.size(); j++)
  423 + if (rects[j].area() > biggest.area())
  424 + biggest = rects[j];
  425 + rects.clear();
  426 + rects.push_back(biggest);
  427 + }
415 428
416 bool empty = false; 429 bool empty = false;
417 if (!enrollAll && rects.empty()) { 430 if (!enrollAll && rects.empty()) {
@@ -426,7 +439,7 @@ class CascadeTransform : public MetaTransform @@ -426,7 +439,7 @@ class CascadeTransform : public MetaTransform
426 u.file.set("Confidence",-std::numeric_limits<float>::max()); 439 u.file.set("Confidence",-std::numeric_limits<float>::max());
427 } else if (rejectLevels.size() > j) 440 } else if (rejectLevels.size() > j)
428 u.file.set("Confidence", rejectLevels[j]*levelWeights[j]); 441 u.file.set("Confidence", rejectLevels[j]*levelWeights[j]);
429 - else 442 + else
430 u.file.set("Confidence", rects[j].area()); 443 u.file.set("Confidence", rects[j].area());
431 const QRectF rect = OpenCVUtils::fromRect(rects[j]); 444 const QRectF rect = OpenCVUtils::fromRect(rects[j]);
432 u.file.appendRect(rect); 445 u.file.appendRect(rect);
openbr/plugins/metadata/keytorect.cpp renamed to openbr/plugins/metadata/keytolandmark.cpp
@@ -24,28 +24,35 @@ namespace br @@ -24,28 +24,35 @@ namespace br
24 * \brief Convert values of key_X, key_Y, key_Width, key_Height to a rect. 24 * \brief Convert values of key_X, key_Y, key_Width, key_Height to a rect.
25 * \author Jordan Cheney \cite JordanCheney 25 * \author Jordan Cheney \cite JordanCheney
26 */ 26 */
27 -class KeyToRectTransform : public UntrainableMetadataTransform 27 +class KeyToLandmarkTransform : public UntrainableMetadataTransform
28 { 28 {
29 Q_OBJECT 29 Q_OBJECT
30 Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false) 30 Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false)
  31 + Q_PROPERTY(bool point READ get_point WRITE set_point RESET reset_point STORED false)
31 BR_PROPERTY(QString, key, "") 32 BR_PROPERTY(QString, key, "")
  33 + BR_PROPERTY(bool, point, false)
32 34
33 void projectMetadata(const File &src, File &dst) const 35 void projectMetadata(const File &src, File &dst) const
34 { 36 {
35 dst = src; 37 dst = src;
36 38
37 - if (src.contains(QStringList() << key + "_X" << key + "_Y" << key + "_Width" << key + "_Height"))  
38 - dst.appendRect(QRectF(src.get<int>(key + "_X"),  
39 - src.get<int>(key + "_Y"),  
40 - src.get<int>(key + "_Width"),  
41 - src.get<int>(key + "_Height"))); 39 + if (point) {
  40 + if (src.contains(QStringList() << key + "_X" << key + "_Y"))
  41 + dst.appendPoint(QPointF(src.get<float>(key + "_X"),
  42 + src.get<float>(key + "_Y")));
  43 + } else {
  44 + if (src.contains(QStringList() << key + "_X" << key + "_Y" << key + "_Width" << key + "_Height"))
  45 + dst.appendRect(QRectF(src.get<float>(key + "_X"),
  46 + src.get<float>(key + "_Y"),
  47 + src.get<float>(key + "_Width"),
  48 + src.get<float>(key + "_Height")));
  49 + }
42 50
43 } 51 }
44 -  
45 }; 52 };
46 53
47 -BR_REGISTER(Transform, KeyToRectTransform) 54 +BR_REGISTER(Transform, KeyToLandmarkTransform)
48 55
49 } // namespace br 56 } // namespace br
50 57
51 -#include "metadata/keytorect.moc" 58 +#include "metadata/keytolandmark.moc"
openbr/plugins/metadata/removetemplates.cpp
@@ -31,15 +31,22 @@ class RemoveTemplatesTransform : public UntrainableMetaTransform @@ -31,15 +31,22 @@ class RemoveTemplatesTransform : public UntrainableMetaTransform
31 Q_OBJECT 31 Q_OBJECT
32 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) 32 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false)
33 Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false) 33 Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false)
  34 + Q_PROPERTY(bool keep READ get_keep WRITE set_keep RESET reset_keep STORED false)
34 BR_PROPERTY(QString, regexp, "") 35 BR_PROPERTY(QString, regexp, "")
35 BR_PROPERTY(QString, key, "") 36 BR_PROPERTY(QString, key, "")
  37 + BR_PROPERTY(bool, keep, false)
36 38
37 void project(const Template &src, Template &dst) const 39 void project(const Template &src, Template &dst) const
38 { 40 {
39 - const QRegularExpression re(regexp);  
40 - const QRegularExpressionMatch match = re.match(key.isEmpty() ? src.file.suffix() : src.file.get<QString>(key));  
41 - if (match.hasMatch()) dst = Template();  
42 - else dst = src; 41 + dst = src;
  42 + QRegExp re(regexp);
  43 + re.setPatternSyntax(QRegExp::Wildcard);
  44 + bool match = re.exactMatch(key.isEmpty() ? src.file.suffix() : src.file.get<QString>(key));
  45 +
  46 + if (keep && !match)
  47 + dst.file.fte = true;
  48 + else if (!keep && match)
  49 + dst.file.fte = true;
43 } 50 }
44 }; 51 };
45 52
openbr/plugins/metadata/stasm4.cpp
1 #include <QString> 1 #include <QString>
2 -#include <stasm_lib.h>  
3 #include <stasmcascadeclassifier.h> 2 #include <stasmcascadeclassifier.h>
  3 +#include <stasm_lib.h>
  4 +#include <stasm.h>
4 #include <opencv2/opencv.hpp> 5 #include <opencv2/opencv.hpp>
5 6
6 #include <openbr/plugins/openbr_internal.h> 7 #include <openbr/plugins/openbr_internal.h>
@@ -56,18 +57,18 @@ BR_REGISTER(Initializer, StasmInitializer) @@ -56,18 +57,18 @@ BR_REGISTER(Initializer, StasmInitializer)
56 * \brief Wraps STASM key point detector 57 * \brief Wraps STASM key point detector
57 * \author Scott Klum \cite sklum 58 * \author Scott Klum \cite sklum
58 */ 59 */
59 -class StasmTransform : public UntrainableTransform 60 +class StasmTransform : public UntrainableMetaTransform
60 { 61 {
61 Q_OBJECT 62 Q_OBJECT
62 63
63 Q_PROPERTY(bool stasm3Format READ get_stasm3Format WRITE set_stasm3Format RESET reset_stasm3Format STORED false) 64 Q_PROPERTY(bool stasm3Format READ get_stasm3Format WRITE set_stasm3Format RESET reset_stasm3Format STORED false)
64 BR_PROPERTY(bool, stasm3Format, false) 65 BR_PROPERTY(bool, stasm3Format, false)
65 - Q_PROPERTY(bool clearLandmarks READ get_clearLandmarks WRITE set_clearLandmarks RESET reset_clearLandmarks STORED false)  
66 - BR_PROPERTY(bool, clearLandmarks, false)  
67 Q_PROPERTY(QList<float> pinPoints READ get_pinPoints WRITE set_pinPoints RESET reset_pinPoints STORED false) 66 Q_PROPERTY(QList<float> pinPoints READ get_pinPoints WRITE set_pinPoints RESET reset_pinPoints STORED false)
68 BR_PROPERTY(QList<float>, pinPoints, QList<float>()) 67 BR_PROPERTY(QList<float>, pinPoints, QList<float>())
69 Q_PROPERTY(QStringList pinLabels READ get_pinLabels WRITE set_pinLabels RESET reset_pinLabels STORED false) 68 Q_PROPERTY(QStringList pinLabels READ get_pinLabels WRITE set_pinLabels RESET reset_pinLabels STORED false)
70 BR_PROPERTY(QStringList, pinLabels, QStringList()) 69 BR_PROPERTY(QStringList, pinLabels, QStringList())
  70 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  71 + BR_PROPERTY(QString, inputVariable, "FrontalFace")
71 72
72 Resource<StasmCascadeClassifier> stasmCascadeResource; 73 Resource<StasmCascadeClassifier> stasmCascadeResource;
73 74
@@ -77,86 +78,119 @@ class StasmTransform : public UntrainableTransform @@ -77,86 +78,119 @@ class StasmTransform : public UntrainableTransform
77 stasmCascadeResource.setResourceMaker(new StasmResourceMaker()); 78 stasmCascadeResource.setResourceMaker(new StasmResourceMaker());
78 } 79 }
79 80
80 - void project(const Template &src, Template &dst) const 81 + QList<QPointF> convertLandmarks(int nLandmarks, float *landmarks) const
81 { 82 {
82 - Mat stasmSrc(src);  
83 - if (src.m().channels() == 3)  
84 - cvtColor(src, stasmSrc, CV_BGR2GRAY);  
85 - else if (src.m().channels() != 1)  
86 - qFatal("Stasm expects single channel matrices.");  
87 -  
88 - if (!stasmSrc.isContinuous())  
89 - qFatal("Stasm expects continuous matrix data.");  
90 - dst = src;  
91 -  
92 - int foundFace = 0;  
93 - int nLandmarks = stasm_NLANDMARKS;  
94 - float landmarks[2 * stasm_NLANDMARKS];  
95 -  
96 - bool searchPinned = false;  
97 -  
98 - QPointF rightEye, leftEye;  
99 - /* Two use cases are accounted for:  
100 - * 1. Pin eyes without normalization: in this case the string list should contain the KEYS for right then left eyes, respectively.  
101 - * 2. Pin eyes with normalization: in this case the string list should contain the COORDINATES of the right then left eyes, respectively.  
102 - * Currently, we only support normalization with a transformation such that the src file contains Affine_0 and Affine_1. Checking for  
103 - * these keys prevents us from pinning eyes on a face that wasn't actually transformed (see AffineTransform).  
104 - * If both cases fail, we default to stasm_search_single. */  
105 -  
106 - if (!pinPoints.isEmpty() && src.file.contains("Affine_0") && src.file.contains("Affine_1")) {  
107 - rightEye = QPointF(pinPoints.at(0), pinPoints.at(1));  
108 - leftEye = QPointF(pinPoints.at(2), pinPoints.at(3));  
109 - searchPinned = true;  
110 - } else if (!pinLabels.isEmpty()) {  
111 - rightEye = src.file.get<QPointF>(pinLabels.at(0), QPointF());  
112 - leftEye = src.file.get<QPointF>(pinLabels.at(1), QPointF());  
113 - searchPinned = true;  
114 - }  
115 -  
116 - if (searchPinned) {  
117 - float pins[2 * stasm_NLANDMARKS];  
118 -  
119 - for (int i = 0; i < nLandmarks; i++) {  
120 - if (i == 38) /* Stasm Right Eye */ { pins[2*i] = rightEye.x(); pins[2*i+1] = rightEye.y(); }  
121 - else if (i == 39) /* Stasm Left Eye */ { pins[2*i] = leftEye.x(); pins[2*i+1] = leftEye.y(); }  
122 - else { pins[2*i] = 0; pins[2*i+1] = 0; }  
123 - } 83 + if (stasm3Format)
  84 + stasm_convert_shape(landmarks, 76);
124 85
125 - stasm_search_pinned(landmarks, pins, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, NULL);  
126 -  
127 - // The ASM in Stasm is guaranteed to converge in this case  
128 - foundFace = 1; 86 + QList<QPointF> points;
  87 + for (int i = 0; i < nLandmarks; i++) {
  88 + QPointF point(landmarks[2 * i], landmarks[2 * i + 1]);
  89 + points.append(point);
129 } 90 }
130 91
131 - if (!foundFace) {  
132 - StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire();  
133 - stasm_search_single(&foundFace, landmarks, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, *stasmCascade, NULL, NULL);  
134 - stasmCascadeResource.release(stasmCascade);  
135 - } 92 + return points;
  93 + }
136 94
137 - if (stasm3Format) {  
138 - nLandmarks = 76;  
139 - stasm_convert_shape(landmarks, nLandmarks);  
140 - } 95 + void project(const Template &src, Template &dst) const
  96 + {
  97 + TemplateList temp;
  98 + project(TemplateList() << src, temp);
  99 + if (!temp.isEmpty()) dst = temp.first();
  100 + }
141 101
142 - // For convenience, if these are the only points/rects we want to deal with as the algorithm progresses  
143 - if (clearLandmarks) {  
144 - dst.file.clearPoints();  
145 - dst.file.clearRects();  
146 - } 102 + void project(const TemplateList &src, TemplateList &dst) const
  103 + {
  104 + foreach (const Template &t, src) {
  105 + Mat stasmSrc(t);
  106 + if (t.m().channels() == 3)
  107 + cvtColor(t, stasmSrc, CV_BGR2GRAY);
  108 + else if (t.m().channels() != 1)
  109 + qFatal("Stasm expects single channel matrices.");
  110 +
  111 + if (!stasmSrc.isContinuous())
  112 + qFatal("Stasm expects continuous matrix data.");
  113 +
  114 + int foundFace = 0;
  115 + int nLandmarks = stasm_NLANDMARKS;
  116 + float landmarks[2 * stasm_NLANDMARKS];
  117 +
  118 + bool searchPinned = false;
  119 +
  120 + QPointF rightEye, leftEye;
  121 + /* Two use cases are accounted for:
  122 + * 1. Pin eyes without normalization: in this case the string list should contain the KEYS for right then left eyes, respectively.
  123 + * 2. Pin eyes with normalization: in this case the string list should contain the COORDINATES of the right then left eyes, respectively.
  124 + * Currently, we only support normalization with a transformation such that the src file contains Affine_0 and Affine_1. Checking for
  125 + * these keys prevents us from pinning eyes on a face that wasn't actually transformed (see AffineTransform).
  126 + * If both cases fail, we default to stasm_search_single. */
  127 +
  128 + if (!pinPoints.isEmpty() && t.file.contains("Affine_0") && t.file.contains("Affine_1")) {
  129 + rightEye = QPointF(pinPoints.at(0), pinPoints.at(1));
  130 + leftEye = QPointF(pinPoints.at(2), pinPoints.at(3));
  131 + searchPinned = true;
  132 + } else if (!pinLabels.isEmpty()) {
  133 + rightEye = t.file.get<QPointF>(pinLabels.at(0), QPointF());
  134 + leftEye = t.file.get<QPointF>(pinLabels.at(1), QPointF());
  135 + searchPinned = true;
  136 + }
  137 +
  138 + if (searchPinned) {
  139 + float pins[2 * stasm_NLANDMARKS];
  140 +
  141 + for (int i = 0; i < nLandmarks; i++) {
  142 + if (i == 38) /* Stasm Right Eye */ { pins[2*i] = rightEye.x(); pins[2*i+1] = rightEye.y(); }
  143 + else if (i == 39) /* Stasm Left Eye */ { pins[2*i] = leftEye.x(); pins[2*i+1] = leftEye.y(); }
  144 + else { pins[2*i] = 0; pins[2*i+1] = 0; }
  145 + }
  146 +
  147 + stasm_search_pinned(landmarks, pins, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, NULL);
  148 +
  149 + // The ASM in Stasm is guaranteed to converge in this case
  150 + foundFace = 1;
  151 + Template u(t.file, t.m());
  152 + QList<QPointF> points = convertLandmarks(nLandmarks, landmarks);
  153 + u.file.set("StasmRightEye", points[38]);
  154 + u.file.set("StasmLeftEye", points[39]);
  155 + u.file.appendPoints(points);
  156 + dst.append(u);
  157 + }
147 158
148 - if (!foundFace) {  
149 - if (Globals->verbose) qWarning("No face found in %s.", qPrintable(src.file.fileName()));  
150 - dst.file.fte = true;  
151 - } else {  
152 - QList<QPointF> points;  
153 - for (int i = 0; i < nLandmarks; i++) {  
154 - QPointF point(landmarks[2 * i], landmarks[2 * i + 1]);  
155 - points.append(point); 159 + if (!foundFace) {
  160 + StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire();
  161 + foundFace = 1;
  162 + stasm::FaceDet detection;
  163 +
  164 + QList<QRectF> rects = t.file.contains(inputVariable) ? QList<QRectF>() << t.file.get<QRectF>(inputVariable) : t.file.rects();
  165 + if (!rects.isEmpty()) detection.iface_ = 0;
  166 + for (int i=0; i<rects.size(); i++) {
  167 + Rect rect = OpenCVUtils::toRect(rects[i]);
  168 + stasm::DetPar detpar;
  169 + detpar.x = rect.x + rect.width / 2.;
  170 + detpar.y = rect.y + rect.height / 2.;
  171 + detpar.width = double(rect.width);
  172 + detpar.height = double(rect.height);
  173 + detpar.yaw = 0;
  174 + detpar.eyaw = stasm::EYAW00;
  175 + detection.detpars_.push_back(detpar);
  176 + }
  177 +
  178 + while (foundFace) {
  179 + stasm_search_auto(&foundFace, landmarks, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, *stasmCascade, detection);
  180 + if (foundFace) {
  181 + Template u(t.file, t.m());
  182 + QList<QPointF> points = convertLandmarks(nLandmarks, landmarks);
  183 + u.file.set("StasmRightEye", points[38]);
  184 + u.file.set("StasmLeftEye", points[39]);
  185 + u.file.appendPoints(points);
  186 + dst.append(u);
  187 + }
  188 +
  189 + if (!Globals->enrollAll)
  190 + break;
  191 + }
  192 + stasmCascadeResource.release(stasmCascade);
156 } 193 }
157 - dst.file.set("StasmRightEye", points[38]);  
158 - dst.file.set("StasmLeftEye", points[39]);  
159 - dst.file.appendPoints(points);  
160 } 194 }
161 } 195 }
162 }; 196 };
openbr/plugins/output/knn.cpp
@@ -6,44 +6,80 @@ @@ -6,44 +6,80 @@
6 namespace br 6 namespace br
7 { 7 {
8 8
  9 +typedef QPair<float,int> Pair;
  10 +
9 /*! 11 /*!
10 * \ingroup outputs 12 * \ingroup outputs
11 * \brief Outputs the k-Nearest Neighbors from the gallery for each probe. 13 * \brief Outputs the k-Nearest Neighbors from the gallery for each probe.
12 * \author Ben Klein \cite bhklein 14 * \author Ben Klein \cite bhklein
13 */ 15 */
14 -class knnOutput : public MatrixOutput 16 +class knnOutput : public Output
15 { 17 {
16 Q_OBJECT 18 Q_OBJECT
17 19
  20 + int rowBlock, columnBlock;
  21 + size_t headerSize, k;
  22 + cv::Mat blockScores;
  23 +
18 ~knnOutput() 24 ~knnOutput()
19 { 25 {
20 - size_t num_probes = (size_t)queryFiles.size();  
21 - if (targetFiles.isEmpty() || queryFiles.isEmpty()) return;  
22 - size_t k = file.get<size_t>("k", 20); 26 + writeBlock();
  27 + }
23 28
24 - if ((size_t)targetFiles.size() < k)  
25 - qFatal("Gallery size %s is smaller than k = %s.", qPrintable(QString::number(targetFiles.size())), qPrintable(QString::number(k))); 29 + void setBlock(int rowBlock, int columnBlock)
  30 + {
  31 + if ((rowBlock == 0) && (columnBlock == 0)) {
  32 + k = file.get<size_t>("k", 20);
  33 + QFile f(file);
  34 + if (!f.open(QFile::WriteOnly))
  35 + qFatal("Unable to open %s for writing.", qPrintable(file));
  36 + size_t querySize = (size_t)queryFiles.size();
  37 + f.write((const char*) &querySize, sizeof(size_t));
  38 + f.write((const char*) &k, sizeof(size_t));
  39 + headerSize = 2 * sizeof(size_t);
  40 + } else {
  41 + writeBlock();
  42 + }
26 43
27 - QFile f(file);  
28 - if (!f.open(QFile::WriteOnly))  
29 - qFatal("Unable to open %s for writing.", qPrintable(file));  
30 - f.write((const char*) &num_probes, sizeof(size_t));  
31 - f.write((const char*) &k, sizeof(size_t)); 44 + this->rowBlock = rowBlock;
  45 + this->columnBlock = columnBlock;
  46 +
  47 + int matrixRows = std::min(queryFiles.size()-rowBlock*this->blockRows, blockRows);
  48 + int matrixCols = std::min(targetFiles.size()-columnBlock*this->blockCols, blockCols);
  49 +
  50 + blockScores = cv::Mat(matrixRows, matrixCols, CV_32FC1);
  51 + }
32 52
33 - QVector<Candidate> neighbors; neighbors.reserve(num_probes*k); 53 + void setRelative(float value, int i, int j)
  54 + {
  55 + blockScores.at<float>(i,j) = value;
  56 + }
  57 +
  58 + void set(float value, int i, int j)
  59 + {
  60 + (void) value; (void) i; (void) j;
  61 + qFatal("Logic error.");
  62 + }
  63 +
  64 + void writeBlock()
  65 + {
  66 + QFile f(file);
  67 + if (!f.open(QFile::ReadWrite))
  68 + qFatal("Unable to open %s for modifying.", qPrintable(file));
  69 + QVector<Candidate> neighbors; neighbors.reserve(k * blockScores.rows);
34 70
35 - for (size_t i=0; i<num_probes; i++) {  
36 - typedef QPair<float,int> Pair; 71 + for (int i=0; i<blockScores.rows; i++) {
37 size_t rank = 0; 72 size_t rank = 0;
38 - foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true)) {  
39 - if (QString(targetFiles[pair.second]) != QString(queryFiles[i])) { 73 + foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(blockScores.row(i)), true)) {
  74 + if (QString(targetFiles[pair.second]) != QString(queryFiles[rowBlock*this->blockRows+i])) {
40 Candidate candidate((size_t)pair.second, pair.first); 75 Candidate candidate((size_t)pair.second, pair.first);
41 neighbors.push_back(candidate); 76 neighbors.push_back(candidate);
42 if (++rank >= k) break; 77 if (++rank >= k) break;
43 } 78 }
44 } 79 }
45 } 80 }
46 - f.write((const char*) neighbors.data(), num_probes * k * sizeof(Candidate)); 81 + f.seek(headerSize + sizeof(Candidate)*quint64(rowBlock*this->blockRows)*k);
  82 + f.write((const char*) neighbors.data(), blockScores.rows * k * sizeof(Candidate));
47 f.close(); 83 f.close();
48 } 84 }
49 }; 85 };
openbr/plugins/representation/haar.cpp
@@ -80,23 +80,25 @@ class HaarRepresentation : public Representation @@ -80,23 +80,25 @@ class HaarRepresentation : public Representation
80 } 80 }
81 } 81 }
82 82
83 - void preprocess(const Mat &src, Mat &dst) const 83 + Template preprocess(const Template &src) const
84 { 84 {
  85 + Template dst;
85 integral(src, dst); 86 integral(src, dst);
  87 + return dst;
86 } 88 }
87 89
88 - float evaluate(const Mat &image, int idx) const 90 + float evaluate(const Template &src, int idx) const
89 { 91 {
90 - return (float)features[idx].calc(image); 92 + return (float)features[idx].calc(src.m());
91 } 93 }
92 94
93 - Mat evaluate(const Mat &image, const QList<int> &indices) const 95 + Mat evaluate(const Template &src, const QList<int> &indices) const
94 { 96 {
95 int size = indices.empty() ? numFeatures() : indices.size(); 97 int size = indices.empty() ? numFeatures() : indices.size();
96 98
97 Mat result(1, size, CV_32FC1); 99 Mat result(1, size, CV_32FC1);
98 for (int i = 0; i < size; i++) 100 for (int i = 0; i < size; i++)
99 - result.at<float>(i) = evaluate(image, indices.empty() ? i : indices[i]); 101 + result.at<float>(i) = evaluate(src, indices.empty() ? i : indices[i]);
100 return result; 102 return result;
101 } 103 }
102 104
openbr/plugins/representation/mblbp.cpp
@@ -39,32 +39,36 @@ class MBLBPRepresentation : public Representation @@ -39,32 +39,36 @@ class MBLBPRepresentation : public Representation
39 39
40 void init() 40 void init()
41 { 41 {
42 - int offset = winWidth + 1;  
43 - for (int x = 0; x < winWidth; x++ )  
44 - for (int y = 0; y < winHeight; y++ )  
45 - for (int w = 1; w <= winWidth / 3; w++ )  
46 - for (int h = 1; h <= winHeight / 3; h++ )  
47 - if ((x+3*w <= winWidth) && (y+3*h <= winHeight) )  
48 - features.append(Feature(offset, x, y, w, h ) ); 42 + if (features.isEmpty()) {
  43 + int offset = winWidth + 1;
  44 + for (int x = 0; x < winWidth; x++ )
  45 + for (int y = 0; y < winHeight; y++ )
  46 + for (int w = 1; w <= winWidth / 3; w++ )
  47 + for (int h = 1; h <= winHeight / 3; h++ )
  48 + if ((x+3*w <= winWidth) && (y+3*h <= winHeight) )
  49 + features.append(Feature(offset, x, y, w, h ) );
  50 + }
49 } 51 }
50 52
51 - void preprocess(const Mat &src, Mat &dst) const 53 + Template preprocess(const Template &src) const
52 { 54 {
  55 + Template dst;
53 integral(src, dst); 56 integral(src, dst);
  57 + return dst;
54 } 58 }
55 59
56 - float evaluate(const Mat &image, int idx) const 60 + float evaluate(const Template &src, int idx) const
57 { 61 {
58 - return (float)features[idx].calc(image); 62 + return (float)features[idx].calc(src.m());
59 } 63 }
60 64
61 - Mat evaluate(const Mat &image, const QList<int> &indices) const 65 + Mat evaluate(const Template &src, const QList<int> &indices) const
62 { 66 {
63 int size = indices.empty() ? numFeatures() : indices.size(); 67 int size = indices.empty() ? numFeatures() : indices.size();
64 68
65 Mat result(1, size, CV_32FC1); 69 Mat result(1, size, CV_32FC1);
66 for (int i = 0; i < size; i++) 70 for (int i = 0; i < size; i++)
67 - result.at<float>(i) = evaluate(image, indices.empty() ? i : indices[i]); 71 + result.at<float>(i) = evaluate(src, indices.empty() ? i : indices[i]);
68 return result; 72 return result;
69 } 73 }
70 74
openbr/plugins/representation/npd.cpp
@@ -16,23 +16,25 @@ class NPDRepresentation : public Representation @@ -16,23 +16,25 @@ class NPDRepresentation : public Representation
16 16
17 void init() 17 void init()
18 { 18 {
19 - for (int p1 = 0; p1 < (winWidth * winHeight); p1++)  
20 - for (int p2 = p1; p2 < (winWidth * winHeight); p2++)  
21 - features.append(Feature(p1, p2)); 19 + if (features.isEmpty()) {
  20 + for (int p1 = 0; p1 < (winWidth * winHeight); p1++)
  21 + for (int p2 = p1; p2 < (winWidth * winHeight); p2++)
  22 + features.append(Feature(p1, p2));
  23 + }
22 } 24 }
23 25
24 - float evaluate(const Mat &image, int idx) const 26 + float evaluate(const Template &src, int idx) const
25 { 27 {
26 - return features[idx].calc(image); 28 + return features[idx].calc(src.m());
27 } 29 }
28 30
29 - Mat evaluate(const Mat &image, const QList<int> &indices) const 31 + Mat evaluate(const Template &src, const QList<int> &indices) const
30 { 32 {
31 int size = indices.empty() ? numFeatures() : indices.size(); 33 int size = indices.empty() ? numFeatures() : indices.size();
32 34
33 Mat result(1, size, CV_32FC1); 35 Mat result(1, size, CV_32FC1);
34 for (int i = 0; i < size; i++) 36 for (int i = 0; i < size; i++)
35 - result.at<float>(i) = evaluate(image, indices.empty() ? i : indices[i]); 37 + result.at<float>(i) = evaluate(src, indices.empty() ? i : indices[i]);
36 return result; 38 return result;
37 } 39 }
38 40
@@ -49,10 +51,10 @@ class NPDRepresentation : public Representation @@ -49,10 +51,10 @@ class NPDRepresentation : public Representation
49 struct Feature 51 struct Feature
50 { 52 {
51 Feature() {} 53 Feature() {}
52 - Feature(int p1, int p2) { p[0] = p1; p[1] = p2; } 54 + Feature(int p0, int p1) : p0(p0), p1(p1) {}
53 float calc(const Mat &image) const; 55 float calc(const Mat &image) const;
54 56
55 - int p[2]; 57 + int p0, p1;
56 }; 58 };
57 QList<Feature> features; 59 QList<Feature> features;
58 }; 60 };
@@ -61,9 +63,9 @@ BR_REGISTER(Representation, NPDRepresentation) @@ -61,9 +63,9 @@ BR_REGISTER(Representation, NPDRepresentation)
61 63
62 inline float NPDRepresentation::Feature::calc(const Mat &image) const 64 inline float NPDRepresentation::Feature::calc(const Mat &image) const
63 { 65 {
64 - const int *ptr = image.ptr<int>();  
65 - int v1 = ptr[p[0]], v2 = ptr[p[1]];  
66 - return v1 == 0 && v2 == 0 ? 0 : ((float)(v1 - v2)) / (v1 + v2); 66 + const uchar *ptr = image.ptr();
  67 + int v1 = (int)ptr[p0], v2 = (int)ptr[p1];
  68 + return (v1 + v2) == 0 ? 0 : (1.0 * (v1 - v2)) / (v1 + v2);
67 } 69 }
68 70
69 } // namespace br 71 } // namespace br
openbr/plugins/representation/random.cpp
@@ -28,9 +28,9 @@ class RandomRepresentation : public Representation @@ -28,9 +28,9 @@ class RandomRepresentation : public Representation
28 28
29 QList<int> features; 29 QList<int> features;
30 30
31 - void train(const QList<Mat> &images, const QList<float> &labels) 31 + void train(const TemplateList &data)
32 { 32 {
33 - representation->train(images, labels); 33 + representation->train(data);
34 34
35 const int nFeatures = representation->numFeatures(); 35 const int nFeatures = representation->numFeatures();
36 36
@@ -40,17 +40,17 @@ class RandomRepresentation : public Representation @@ -40,17 +40,17 @@ class RandomRepresentation : public Representation
40 features = Common::RandSample(count,nFeatures,0,true); 40 features = Common::RandSample(count,nFeatures,0,true);
41 } 41 }
42 42
43 - void preprocess(const Mat &src, Mat &dst) const 43 + Template preprocess(const Template &src) const
44 { 44 {
45 - representation->preprocess(src,dst); 45 + return representation->preprocess(src);
46 } 46 }
47 47
48 - float evaluate(const Mat &image, int idx) const 48 + float evaluate(const Template &src, int idx) const
49 { 49 {
50 - return representation->evaluate(image,features[idx]); 50 + return representation->evaluate(src, features[idx]);
51 } 51 }
52 52
53 - Mat evaluate(const Mat &image, const QList<int> &indices) const 53 + Mat evaluate(const Template &src, const QList<int> &indices) const
54 { 54 {
55 QList<int> newIndices; 55 QList<int> newIndices;
56 if (indices.empty()) 56 if (indices.empty())
@@ -59,7 +59,7 @@ class RandomRepresentation : public Representation @@ -59,7 +59,7 @@ class RandomRepresentation : public Representation
59 for (int i = 0; i < indices.size(); i++) 59 for (int i = 0; i < indices.size(); i++)
60 newIndices.append(features[indices[i]]); 60 newIndices.append(features[indices[i]]);
61 61
62 - return representation->evaluate(image,newIndices); 62 + return representation->evaluate(src, newIndices);
63 } 63 }
64 64
65 int numFeatures() const 65 int numFeatures() const
@@ -108,6 +108,3 @@ BR_REGISTER(Representation, RandomRepresentation) @@ -108,6 +108,3 @@ BR_REGISTER(Representation, RandomRepresentation)
108 } // namespace br 108 } // namespace br
109 109
110 #include "representation/random.moc" 110 #include "representation/random.moc"
111 -  
112 -  
113 -  
scripts/face_cluster_viz.py renamed to scripts/brpy/face_cluster_viz.py
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 -from PIL import Image  
4 import csv, sys, json, argparse 3 import csv, sys, json, argparse
  4 +from brpy.html_viz import crop_to_bb
5 5
6 parser = argparse.ArgumentParser(description='Visualize face cluster results in an HTML page.') 6 parser = argparse.ArgumentParser(description='Visualize face cluster results in an HTML page.')
7 parser.add_argument('input_file', type=str, help='Results from clustering (in csv format)') 7 parser.add_argument('input_file', type=str, help='Results from clustering (in csv format)')
@@ -16,24 +16,15 @@ clustmap = dict() @@ -16,24 +16,15 @@ clustmap = dict()
16 with open(args.input_file) as f: 16 with open(args.input_file) as f:
17 for line in csv.DictReader(f): 17 for line in csv.DictReader(f):
18 c = int(line[args.cluster_key]) 18 c = int(line[args.cluster_key])
  19 + if c not in clustmap:
  20 + clustmap[c] = []
19 x,y,width,height = [ float(line[k]) for k in ('Face_X','Face_Y','Face_Width','Face_Height') ] 21 x,y,width,height = [ float(line[k]) for k in ('Face_X','Face_Y','Face_Width','Face_Height') ]
20 imname = '%s/%s' % (args.img_loc, line['File']) 22 imname = '%s/%s' % (args.img_loc, line['File'])
21 try: 23 try:
22 - img = Image.open(imname)  
23 - imwidth, imheight = img.size 24 + html = crop_to_bb(x,y,width,height,imname,maxheight=400)
24 except IOError: 25 except IOError:
25 print('problem with %s' % imname) 26 print('problem with %s' % imname)
26 continue 27 continue
27 - ratio = maxheight / height  
28 - # note for future me:  
29 - # image is cropped with div width/height + overflow:hidden,  
30 - # resized with img height,  
31 - # and positioned with img margin  
32 - html = '<div style="overflow:hidden;display:inline-block;width:%ipx;height:%ipx;">' % (width*ratio, maxheight)  
33 - html += '<img src="%s" style="height:%ipx;margin:-%ipx 0 0 -%ipx;"/>' % (imname, imheight*ratio, y*ratio, x*ratio)  
34 - html += '</div>'  
35 - if c not in clustmap:  
36 - clustmap[c] = []  
37 clustmap[c].append(html) 28 clustmap[c].append(html)
38 29
39 # browsers crash for a DOM with this many img tags, 30 # browsers crash for a DOM with this many img tags,
scripts/brpy/html_viz.py 0 โ†’ 100644
  1 +'''
  2 +Some funcs to generate HTML visualizations.
  3 +Run from the folder you intend to save the HTML page so
  4 +the relative paths in the HTML file are correct and PIL can find the images on disk.
  5 +Requires local images, but should be pretty easy to set up an apache server (or whatev)
  6 +and host them as long as the relative paths remain the same on ya serva.
  7 +'''
  8 +
  9 +from PIL import Image
  10 +
  11 +def crop_to_bb(x, y, width, height, imname, maxheight=None):
  12 + '''
  13 + Generates an HTML string that crops to a given bounding box and resizes to maxheight pixels.
  14 + A maxheight of None will keep the original size (default).
  15 + When two crops are put next to each other, they will be inline. To make each crop its own line, wrap it in a div.
  16 + '''
  17 + img = Image.open(imname)
  18 + imwidth, imheight = img.size
  19 + if not maxheight:
  20 + maxheight = height
  21 + ratio = maxheight / height
  22 + # note for future me:
  23 + # image is cropped with div width/height + overflow:hidden,
  24 + # resized with img height,
  25 + # and positioned with img margin
  26 + html = '<div style="overflow:hidden; display:inline-block; width:%ipx; height:%ipx;">' % (width*ratio, maxheight)
  27 + html += '<img src="%s" style="height:%ipx; margin:-%ipx 0 0 -%ipx;"/>' % (imname, imheight*ratio, y*ratio, x*ratio)
  28 + html += '</div>'
  29 + return html
  30 +
  31 +def bbs_for_image(imname, bbs, maxheight=None, colors=None):
  32 + '''
  33 + Generates an HTML string for an image with bounding boxes.
  34 + bbs: iterable of (x,y,width,height) bounding box tuples
  35 + '''
  36 + img = Image.open(imname)
  37 + imwidth, imheight = img.size
  38 + if not maxheight:
  39 + maxheight = imheight
  40 + ratio = maxheight/imheight
  41 + html = [
  42 + '<div style="position:relative">',
  43 + '<img src="%s" style="height:%ipx" />' % (imname, maxheight)
  44 + ]
  45 + if not colors:
  46 + colors = ['green']*len(bbs)
  47 + html.extend([ bb(*box, ratio=ratio, color=color) for color,box in zip(colors,bbs) ])
  48 + html.append('</div>')
  49 + return '\n'.join(html)
  50 +
  51 +
  52 +def bb(x, y, width, height, ratio=1.0, color='green'):
  53 + '''
  54 + Generates an HTML string bounding box.
  55 + '''
  56 + html = '<div style="position:absolute; border:2px solid %s; color:%s; left:%ipx; top:%ipx; width:%ipx; height:%ipx;"></div>'
  57 + return html % (color, color, x*ratio, y*ratio, width*ratio, height*ratio)
share/openbr/cmake/InstallDependencies.cmake
@@ -86,12 +86,14 @@ endfunction() @@ -86,12 +86,14 @@ endfunction()
86 function(install_qt_platforms) 86 function(install_qt_platforms)
87 if(${BR_INSTALL_DEPENDENCIES}) 87 if(${BR_INSTALL_DEPENDENCIES})
88 if(CMAKE_HOST_WIN32) 88 if(CMAKE_HOST_WIN32)
89 - #TODO 89 + install(FILES ${_qt5Core_install_prefix}/plugins/platforms/qwindows.dll
  90 + DESTINATION bin/platforms)
90 elseif(CMAKE_HOST_APPLE) 91 elseif(CMAKE_HOST_APPLE)
91 install(FILES ${_qt5Core_install_prefix}/plugins/platforms/libqcocoa.dylib 92 install(FILES ${_qt5Core_install_prefix}/plugins/platforms/libqcocoa.dylib
92 DESTINATION bin/platforms) 93 DESTINATION bin/platforms)
93 else() 94 else()
94 - #TODO 95 + install(FILES ${_qt5Core_install_prefix}/plugins/platforms/libqlinuxfb.so
  96 + DESTINATION bin/platforms)
95 endif() 97 endif()
96 endif() 98 endif()
97 endfunction() 99 endfunction()
share/openbr/plotting/plot_utils.R
@@ -217,6 +217,12 @@ formatData &lt;- function(type=&quot;eval&quot;) { @@ -217,6 +217,12 @@ formatData &lt;- function(type=&quot;eval&quot;) {
217 NormLength <<- data[grep("NormLength",data$Plot),-c(1)] 217 NormLength <<- data[grep("NormLength",data$Plot),-c(1)]
218 sample <<- readImageData(Sample) 218 sample <<- readImageData(Sample)
219 rows <<- sample[[1]]$value 219 rows <<- sample[[1]]$value
  220 + } else if (type == "knn") {
  221 + # Split data into individual plots
  222 + IET <<- data[grep("IET",data$Plot),-c(1)]
  223 + IET$Y <<- as.numeric(as.character(IET$Y))
  224 + CMC <<- data[grep("CMC",data$Plot),-c(1)]
  225 + CMC$Y <<- as.numeric(as.character(CMC$Y))
220 } 226 }
221 } 227 }
222 228