Commit ab502f60a54e382312888c9fd2947371f5ac51a5

Authored by Brendan Klare
2 parents a9fbb83e 5b3c7a8e

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

CHANGELOG.md
1 0.4.0 - ??/??/?? 1 0.4.0 - ??/??/??
2 ================ 2 ================
  3 +* Added -evalLandmarking and -plotLandmarking for evaluating and plotting landmarking accuracy (#9)
3 * Added -evalDetection and -plotDetection for evaluating and plotting object detection accuracy (#9) 4 * Added -evalDetection and -plotDetection for evaluating and plotting object detection accuracy (#9)
4 * Deprecated Transform::backProject 5 * Deprecated Transform::backProject
5 6
app/br/br.cpp
@@ -146,6 +146,9 @@ public: @@ -146,6 +146,9 @@ public:
146 } else if (!strcmp(fun, "plotDetection")) { 146 } else if (!strcmp(fun, "plotDetection")) {
147 check(parc >= 2, "Incorrect parameter count for 'plotDetection'."); 147 check(parc >= 2, "Incorrect parameter count for 'plotDetection'.");
148 br_plot_detection(parc-1, parv, parv[parc-1], true); 148 br_plot_detection(parc-1, parv, parv[parc-1], true);
  149 + } else if (!strcmp(fun, "plotLandmarking")) {
  150 + check(parc >= 2, "Incorrect parameter count for 'plotLandmarking'.");
  151 + br_plot_landmarking(parc-1, parv, parv[parc-1], true);
149 } else if (!strcmp(fun, "plotMetadata")) { 152 } else if (!strcmp(fun, "plotMetadata")) {
150 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); 153 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
151 br_plot_metadata(parc-1, parv, parv[parc-1], true); 154 br_plot_metadata(parc-1, parv, parv[parc-1], true);
@@ -224,6 +227,7 @@ private: @@ -224,6 +227,7 @@ private:
224 "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>]]\n" 227 "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>]]\n"
225 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n" 228 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n"
226 "-plotDetection <file> ... <file> {destination}\n" 229 "-plotDetection <file> ... <file> {destination}\n"
  230 + "-plotLandmarking <file> ... <file> {destination}\n"
227 "-plotMetadata <file> ... <file> <columns>\n" 231 "-plotMetadata <file> ... <file> <columns>\n"
228 "-getHeader <matrix>\n" 232 "-getHeader <matrix>\n"
229 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n" 233 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n"
openbr/core/plot.cpp
@@ -228,7 +228,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -228,7 +228,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
228 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + 228 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
229 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) + 229 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
230 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 230 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
231 - QString(" + scale_x_log10(labels=percent) + scale_y_continuous(labels=percent) + annotation_logticks(sides=\"b\")\n\n"))); 231 + QString(" + scale_x_log10(labels=percent, limits=c(min(DET$X),1)) + scale_y_continuous(labels=percent) + annotation_logticks(sides=\"b\")\n\n")));
232 232
233 p.file.write(qPrintable(QString("qplot(X, Y, data=DET%1").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"") + 233 p.file.write(qPrintable(QString("qplot(X, Y, data=DET%1").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"") +
234 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) + 234 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
@@ -236,7 +236,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -236,7 +236,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
236 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") + 236 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") +
237 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) + 237 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
238 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 238 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
239 - QString(" + scale_x_log10(labels=percent) + scale_y_log10(labels=percent) + annotation_logticks()\n\n"))); 239 + QString(" + scale_x_log10(labels=percent, limits=c(min(DET$X),1)) + scale_y_log10(labels=percent) + annotation_logticks()\n\n")));
240 240
241 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + 241 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") +
242 QString(", xlab=\"Score%1\"").arg((p.flip ? p.major.size : p.minor.size) > 1 ? " / " + (p.flip ? p.major.header : p.minor.header) : QString()) + 242 QString(", xlab=\"Score%1\"").arg((p.flip ? p.major.size : p.minor.size) > 1 ? " / " + (p.flip ? p.major.header : p.minor.header) : QString()) +
@@ -302,7 +302,6 @@ bool filesHaveSinglePoint(const QStringList &amp;files) { @@ -302,7 +302,6 @@ bool filesHaveSinglePoint(const QStringList &amp;files) {
302 bool PlotDetection(const QStringList &files, const File &destination, bool show) 302 bool PlotDetection(const QStringList &files, const File &destination, bool show)
303 { 303 {
304 qDebug("Plotting %d detection file(s) to %s", files.size(), qPrintable(destination)); 304 qDebug("Plotting %d detection file(s) to %s", files.size(), qPrintable(destination));
305 -  
306 RPlot p(files, destination, false); 305 RPlot p(files, destination, false);
307 306
308 p.file.write("# Split data into individual plots\n" 307 p.file.write("# Split data into individual plots\n"
@@ -345,6 +344,27 @@ bool PlotDetection(const QStringList &amp;files, const File &amp;destination, bool show) @@ -345,6 +344,27 @@ bool PlotDetection(const QStringList &amp;files, const File &amp;destination, bool show)
345 return p.finalize(show); 344 return p.finalize(show);
346 } 345 }
347 346
  347 +bool PlotLandmarking(const QStringList &files, const File &destination, bool show)
  348 +{
  349 + qDebug("Plotting %d landmarking file(s) to %s", files.size(), qPrintable(destination));
  350 + RPlot p(files, destination, false);
  351 +
  352 + p.file.write("# Split data into individual plots\n"
  353 + "plot_index = which(names(data)==\"Plot\")\n"
  354 + "Box <- data[grep(\"Box\",data$Plot),-c(1)]\n"
  355 + "rm(data)\n"
  356 + "\n");
  357 +
  358 + p.file.write(qPrintable(QString("ggplot(Box, aes(Y,%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
  359 + QString(" + annotation_logticks(sides=\"b\") + stat_ecdf() + scale_x_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10)) + scale_y_continuous(\"Cumulative Density\", label=percent) + theme_minimal()\n\n")));
  360 + p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
  361 + QString("+ annotation_logticks(sides=\"l\") + geom_boxplot(alpha=0.5) + geom_jitter(size=1, alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.01,0.1,1,10)) + theme_minimal()\n\n")));
  362 + p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
  363 + QString("+ annotation_logticks(sides=\"l\") + geom_violin(alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10))\n\n")));
  364 +
  365 + return p.finalize(show);
  366 +}
  367 +
348 bool PlotMetadata(const QStringList &files, const QString &columns, bool show) 368 bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
349 { 369 {
350 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns)); 370 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns));
openbr/core/plot.h
@@ -26,6 +26,7 @@ namespace br @@ -26,6 +26,7 @@ namespace br
26 { 26 {
27 bool Plot(const QStringList &files, const File &destination, bool show = false); 27 bool Plot(const QStringList &files, const File &destination, bool show = false);
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 PlotMetadata(const QStringList &files, const QString &destination, bool show = false); 30 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false);
30 } 31 }
31 32
openbr/core/resource.h
@@ -40,6 +40,9 @@ class DefaultResourceMaker : public ResourceMaker&lt;T&gt; @@ -40,6 +40,9 @@ class DefaultResourceMaker : public ResourceMaker&lt;T&gt;
40 T *make() const { return new T(); } 40 T *make() const { return new T(); }
41 }; 41 };
42 42
  43 +// Manage multiple copies of a limited resource in a thread-safe manner.
  44 +// TimeVaryingTransform makes a strong assumption that ResourceMaker::Make
  45 +// is only called in acquire, not in the constructor.
43 template <typename T> 46 template <typename T>
44 class Resource 47 class Resource
45 { 48 {
openbr/openbr.cpp
@@ -182,6 +182,11 @@ bool br_plot_detection(int num_files, const char *files[], const char *destinati @@ -182,6 +182,11 @@ bool br_plot_detection(int num_files, const char *files[], const char *destinati
182 return PlotDetection(QtUtils::toStringList(num_files, files), destination, show); 182 return PlotDetection(QtUtils::toStringList(num_files, files), destination, show);
183 } 183 }
184 184
  185 +bool br_plot_landmarking(int num_files, const char *files[], const char *destination, bool show)
  186 +{
  187 + return PlotLandmarking(QtUtils::toStringList(num_files, files), destination, show);
  188 +}
  189 +
185 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show) 190 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show)
186 { 191 {
187 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show); 192 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show);
openbr/openbr.h
@@ -265,6 +265,12 @@ BR_EXPORT const char *br_objects(const char *abstractions = &quot;.*&quot;, const char *im @@ -265,6 +265,12 @@ BR_EXPORT const char *br_objects(const char *abstractions = &quot;.*&quot;, const char *im
265 * - <i>destination</i><tt>.R</tt> which is the auto-generated R script used to render the figures. 265 * - <i>destination</i><tt>.R</tt> which is the auto-generated R script used to render the figures.
266 * - <i>destination</i><tt>.pdf</tt> which has all of the figures in one file multi-page file. 266 * - <i>destination</i><tt>.pdf</tt> which has all of the figures in one file multi-page file.
267 * 267 *
  268 + * OpenBR uses file and folder names to automatically determine the plot legend.
  269 + * For example, let's consider the case where three algorithms (<tt>A</tt>, <tt>B</tt>, & <tt>C</tt>) were each evaluated on two datasets (<tt>Y</tt> & <tt>Z</tt>).
  270 + * The suggested way to plot these experiments on the same graph is to create a folder named <tt>Algorithm_Dataset</tt> that contains the six <tt>.csv</tt> files produced by \ref br_eval: <tt>A_Y.csv</tt>, <tt>A_Z.csv</tt>, <tt>B_Y.csv</tt>, <tt>B_Z.csv</tt>, <tt>C_Y.csv</tt>, & <tt>C_Z.csv</tt>.
  271 + * The '<tt>_</tt>' character plays a special role in determining the legend title(s) and value(s).
  272 + * In this case, <tt>A</tt>, <tt>B</tt>, & <tt>C</tt> will be identified as different values of type <tt>Algorithm</tt>, and each will be assigned its own color; <tt>Y</tt> & <tt>Z</tt> will be identified as different values of type Dataset, and each will be assigned its own line style.
  273 + *
268 * \param num_files Number of <tt>.csv</tt> files. 274 * \param num_files Number of <tt>.csv</tt> files.
269 * \param files <tt>.csv</tt> files created using \ref br_eval. 275 * \param files <tt>.csv</tt> files created using \ref br_eval.
270 * \param destination Basename for the resulting figures. 276 * \param destination Basename for the resulting figures.
@@ -295,6 +301,20 @@ BR_EXPORT bool br_plot(int num_files, const char *files[], const char *destinati @@ -295,6 +301,20 @@ BR_EXPORT bool br_plot(int num_files, const char *files[], const char *destinati
295 BR_EXPORT bool br_plot_detection(int num_files, const char *files[], const char *destination, bool show = false); 301 BR_EXPORT bool br_plot_detection(int num_files, const char *files[], const char *destination, bool show = false);
296 302
297 /*! 303 /*!
  304 + * \brief Renders landmarking performance figures for a set of <tt>.csv</tt> files created by \ref br_eval_landmarking.
  305 + *
  306 + * In order of their output, the figures are:
  307 + * -# Cumulative landmarks less than normalized error (CD)
  308 + * -# Normalized error box and whisker plots (Box)
  309 + * -# Normalized error violin plots (Violin)
  310 + *
  311 + * Landmarking error is normalized against the distance between two predifined points, usually inter-ocular distance (IOD).
  312 + *
  313 + * \see br_plot
  314 + */
  315 +BR_EXPORT bool br_plot_landmarking(int num_files, const char *files[], const char *destination, bool show = false);
  316 +
  317 +/*!
298 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns. 318 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns.
299 * 319 *
300 * Several files will be created: 320 * Several files will be created:
openbr/openbr_plugin.cpp
@@ -387,7 +387,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery) @@ -387,7 +387,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
387 387
388 const int crossValidate = gallery.get<int>("crossValidate"); 388 const int crossValidate = gallery.get<int>("crossValidate");
389 389
390 - if (gallery.getBool("leaveOneOut")) { 390 + if (gallery.getBool("leaveOneImageOut")) {
391 QStringList labels; 391 QStringList labels;
392 for (int i=newTemplates.size()-1; i>=0; i--) { 392 for (int i=newTemplates.size()-1; i>=0; i--) {
393 newTemplates[i].file.set("Index", i+templates.size()); 393 newTemplates[i].file.set("Index", i+templates.size());
@@ -406,11 +406,11 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery) @@ -406,11 +406,11 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
406 // Extend the gallery for each partition 406 // Extend the gallery for each partition
407 for (int j=0; j<labelIndices.size(); j++) { 407 for (int j=0; j<labelIndices.size(); j++) {
408 for (int k=0; k<crossValidate; k++) { 408 for (int k=0; k<crossValidate; k++) {
409 - Template leaveOneOutTemplate = newTemplates[labelIndices[j]];  
410 - if (k!=leaveOneOutTemplate.file.get<int>("Partition")) {  
411 - leaveOneOutTemplate.file.set("Partition", k);  
412 - leaveOneOutTemplate.file.set("testOnly", true);  
413 - newTemplates.insert(i+1,leaveOneOutTemplate); 409 + Template leaveOneImageOutTemplate = newTemplates[labelIndices[j]];
  410 + if (k!=leaveOneImageOutTemplate.file.get<int>("Partition")) {
  411 + leaveOneImageOutTemplate.file.set("Partition", k);
  412 + leaveOneImageOutTemplate.file.set("testOnly", true);
  413 + newTemplates.insert(i+1,leaveOneImageOutTemplate);
414 } 414 }
415 } 415 }
416 } 416 }
openbr/plugins/algorithms.cpp
@@ -50,9 +50,9 @@ class AlgorithmsInitializer : public Initializer @@ -50,9 +50,9 @@ class AlgorithmsInitializer : public Initializer
50 Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); 50 Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)");
51 Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); 51 Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)");
52 52
53 - Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+KeyPointDetector(SIFT)+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");  
54 - Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+KeyPointDetector(SIFT)+AggregateFrames(2)+OpticalFlow+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");  
55 - Globals->abbreviations.insert("HOGHOF", "Stream(DropFrames(5)+KeyPointDetector(SIFT)+AggregateFrames(2)+(OpticalFlow++ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); 53 + Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
  54 + Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");
  55 + Globals->abbreviations.insert("HOGHOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+(OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
56 56
57 // Generic Image Processing 57 // Generic Image Processing
58 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); 58 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
openbr/plugins/crop.cpp
@@ -69,6 +69,31 @@ BR_REGISTER(Transform, ROITransform) @@ -69,6 +69,31 @@ BR_REGISTER(Transform, ROITransform)
69 69
70 /*! 70 /*!
71 * \ingroup transforms 71 * \ingroup transforms
  72 + * \brief Crops the rectangular regions of interest from given points and sizes.
  73 + * \author Austin Blanton \cite imaus10
  74 + */
  75 +class ROIFromPtsTransform : public UntrainableTransform
  76 +{
  77 + Q_OBJECT
  78 + Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false)
  79 + Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false)
  80 + BR_PROPERTY(int, width, 1)
  81 + BR_PROPERTY(int, height, 1)
  82 +
  83 + void project(const Template &src, Template &dst) const
  84 + {
  85 + foreach (const QPointF &pt, src.file.points()) {
  86 + int x = pt.x() - (width/2);
  87 + int y = pt.y() - (height/2);
  88 + dst += src.m()(Rect(x, y, width, height));
  89 + }
  90 + }
  91 +};
  92 +
  93 +BR_REGISTER(Transform, ROIFromPtsTransform)
  94 +
  95 +/*!
  96 + * \ingroup transforms
72 * \brief Resize the template 97 * \brief Resize the template
73 * \author Josh Klontz \cite jklontz 98 * \author Josh Klontz \cite jklontz
74 * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement. 99 * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement.
openbr/plugins/eigen3.cpp
@@ -253,9 +253,7 @@ class DFFSTransform : public Transform @@ -253,9 +253,7 @@ class DFFSTransform : public Transform
253 { 253 {
254 Q_OBJECT 254 Q_OBJECT
255 Q_PROPERTY(float keep READ get_keep WRITE set_keep RESET reset_keep STORED false) 255 Q_PROPERTY(float keep READ get_keep WRITE set_keep RESET reset_keep STORED false)
256 - Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform STORED false)  
257 BR_PROPERTY(float, keep, 0.95) 256 BR_PROPERTY(float, keep, 0.95)
258 - BR_PROPERTY(br::Transform*, transform, NULL)  
259 257
260 PCATransform pca; 258 PCATransform pca;
261 Transform *cvtFloat; 259 Transform *cvtFloat;
openbr/plugins/fst3.cmake deleted
1 -set(BR_WITH_FST3 OFF CACHE BOOL "Build with Feature Selection Toolbox 3")  
2 -  
3 -if(${BR_WITH_FST3})  
4 - find_package(FST3 REQUIRED)  
5 - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} plugins/fst3.cpp ${FST3_SRC})  
6 -  
7 - find_package(Boost REQUIRED)  
8 - include_directories(${Boost_INCLUDE_DIRS})  
9 - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} boost_thread)  
10 -  
11 - find_package(LibSVM REQUIRED)  
12 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${LibSVM_SRC})  
13 -endif()  
openbr/plugins/fst3.cpp deleted
1 -#include <QMap>  
2 -#include <QString>  
3 -#include <QStringList>  
4 -#include <QTime>  
5 -#include <opencv2/core/core.hpp>  
6 -#include <opencv2/imgproc/imgproc.hpp>  
7 -#include <mm_plugin.h>  
8 -  
9 -#include "model.h"  
10 -#include "common/opencvutils.h"  
11 -#include "common/qtutils.h"  
12 -#include "plugins/meta.h"  
13 -#include "plugins/regions.h"  
14 -  
15 -//#ifdef MM_SDK_TRAINABLE  
16 -#include <boost/smart_ptr.hpp>  
17 -#include <exception>  
18 -#include <iostream>  
19 -#include <cstdlib>  
20 -#include <sstream>  
21 -#include <string>  
22 -#include <vector>  
23 -  
24 -#include <error.hpp>  
25 -#include <global.hpp>  
26 -#include <subset.hpp>  
27 -#include <data_intervaller.hpp>  
28 -#include <data_splitter.hpp>  
29 -#include <data_splitter_5050.hpp>  
30 -#include <data_splitter_cv.hpp>  
31 -#include <data_splitter_resub.hpp>  
32 -#include <data_scaler.hpp>  
33 -#include <data_scaler_void.hpp>  
34 -#include <data_accessor_splitting_mem.hpp>  
35 -#include <criterion_wrapper.hpp>  
36 -#include <distance_euclid.hpp>  
37 -#include <classifier_knn.hpp>  
38 -#include <seq_step_straight_threaded.hpp>  
39 -#include <search_seq_dos.hpp>  
40 -#include <search_seq_sfs.hpp>  
41 -#include <search_seq_sffs.hpp>  
42 -#include <search_monte_carlo_threaded.hpp>  
43 -  
44 -using namespace FST;  
45 -//#endif // MM_SDK_TRAINABLE  
46 -  
47 -using namespace mm;  
48 -  
49 -enum DimensionStatus {  
50 - On,  
51 - Off,  
52 - Ignore  
53 -};  
54 -  
55 -//#ifdef MM_SDK_TRAINABLE  
56 -template<typename DATATYPE, typename IDXTYPE, class INTERVALCONTAINER>  
57 -class FST3Data_Accessor_Splitting_MemMM : public Data_Accessor_Splitting_Mem<DATATYPE,IDXTYPE,INTERVALCONTAINER>  
58 -{  
59 - QList<MatrixList> mll;  
60 - QList<DimensionStatus> dsl;  
61 - int features;  
62 - QMap<int, int> labelCounts;  
63 -  
64 -public:  
65 - typedef Data_Accessor_Splitting_Mem<DATATYPE,IDXTYPE,INTERVALCONTAINER> DASM;  
66 - typedef boost::shared_ptr<Data_Scaler<DATATYPE> > PScaler;  
67 - typedef typename DASM::PSplitters PSplitters;  
68 -  
69 - FST3Data_Accessor_Splitting_MemMM(const QList<MatrixList> &_mll, const QList<DimensionStatus> &_dsl, const PSplitters _dsp, const PScaler _dsc)  
70 - : Data_Accessor_Splitting_Mem<DATATYPE,IDXTYPE,INTERVALCONTAINER>("MM", _dsp, _dsc), mll(_mll), dsl(_dsl)  
71 - {  
72 - features = 0;  
73 - foreach (DimensionStatus ds, dsl)  
74 - if (ds != Ignore) features++;  
75 - labelCounts = mll.first().labelCounts();  
76 - }  
77 -  
78 - FST3Data_Accessor_Splitting_MemMM(const MatrixList &_ml, const PSplitters _dsp, const PScaler _dsc)  
79 - : Data_Accessor_Splitting_Mem<DATATYPE,IDXTYPE,INTERVALCONTAINER>("MM", _dsp, _dsc)  
80 - {  
81 - mll.append(_ml);  
82 - features = _ml.first().total() * _ml.first().channels();  
83 - for (int i=0; i<features; i++)  
84 - dsl.append(Off);  
85 - labelCounts = _ml.labelCounts();  
86 - }  
87 -  
88 - FST3Data_Accessor_Splitting_MemMM* sharing_clone() const;  
89 - virtual std::ostream& print(std::ostream& os) const;  
90 -  
91 -protected:  
92 - FST3Data_Accessor_Splitting_MemMM(const Data_Accessor_Splitting_MemMM &damt, int x)  
93 - : Data_Accessor_Splitting_Mem<DATATYPE,IDXTYPE,INTERVALCONTAINER>(damt, x)  
94 - {} // weak (referencing) copy-constructor to be used in sharing_clone()  
95 -  
96 - virtual void initial_data_read(); //!< \note off-limits in shared_clone  
97 - virtual void initial_file_prepare() {}  
98 -  
99 -public:  
100 - virtual unsigned int file_getNoOfClasses() const { return labelCounts.size(); }  
101 - virtual unsigned int file_getNoOfFeatures() const { return features; }  
102 - virtual IDXTYPE file_getClassSize(unsigned int cls) const { return labelCounts[cls]; }  
103 -};  
104 -  
105 -template<typename DATATYPE, typename IDXTYPE, class INTERVALCONTAINER>  
106 -void FST3Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER>::initial_data_read() //!< \note off-limits in shared_clone  
107 -{  
108 - if (Clonable::is_sharing_clone()) throw fst_error("Data_Accessor_Splitting_MemMM()::initial_data_read() called from shared_clone instance.");  
109 - IDXTYPE idx=0;  
110 -  
111 - // TODO: Assert that ml data type is DATATYPE  
112 - const QList<float> labels = mll.first().labels();  
113 - foreach (int label, labelCounts.keys()) {  
114 - for (int i=0; i<labels.size(); i++) {  
115 - if (labels[i] == label) {  
116 - int dslIndex = 0;  
117 - foreach (const MatrixList &ml, mll) {  
118 - const Matrix &m = ml[i];  
119 - const int dims = m.total() * m.channels();  
120 - for (int j=0; j<dims; j++)  
121 - if (dsl[dslIndex++] != Ignore)  
122 - this->data[idx++] = reinterpret_cast<float*>(m.data)[j];  
123 - }  
124 - }  
125 - }  
126 - }  
127 -}  
128 -  
129 -/*template<typename DATATYPE, typename IDXTYPE, class INTERVALCONTAINER>  
130 -Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER>* Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER>::sharing_clone() const  
131 -{  
132 - Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER> *clone=new Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER>(*this, (int)0);  
133 - clone->set_sharing_cloned();  
134 - return clone;  
135 -}  
136 -  
137 -template<typename DATATYPE, typename IDXTYPE, class INTERVALCONTAINER>  
138 -std::ostream& Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALCONTAINER>::print(std::ostream& os) const  
139 -{  
140 - DASM::print(os);  
141 - os << std::endl << "Data_Accessor_Splitting_MemMM()";  
142 - return os;  
143 -}*/  
144 -  
145 -//#endif // MM_SDK_TRAINABLE  
146 -  
147 -  
148 -class FST3DOS : public Feature  
149 -{  
150 - friend class Maker<DOS,true>;  
151 -  
152 - int delta;  
153 -  
154 - mm::Remap remap;  
155 -  
156 - DOS(int delta = 1)  
157 - {  
158 - this->delta = delta;  
159 - }  
160 -  
161 - static QString args()  
162 - {  
163 - return "delta = 1";  
164 - }  
165 -  
166 - static DOS *make(const QString &args)  
167 - {  
168 - QStringList words = QtUtils::parse(args);  
169 - if (words.size() > 1) qFatal("DOS::make invalid argument count.");  
170 -  
171 - int delta = 1;  
172 -  
173 - bool ok;  
174 - switch (words.size()) {  
175 - case 1:  
176 - delta = words[0].toInt(&ok); if (!ok) qFatal("DOS::make expected integer delta.");  
177 - }  
178 -  
179 - return new DOS(delta);  
180 - }  
181 -  
182 - QSharedPointer<Feature> clone() const  
183 - {  
184 - return QSharedPointer<Feature>(new DOS(delta));  
185 - }  
186 -  
187 - void train(const MatrixList &data, Matrix &metadata)  
188 - {  
189 - (void) metadata;  
190 - //#ifdef MM_SDK_TRAINABLE  
191 - try {  
192 - typedef float RETURNTYPE; typedef float DATATYPE; typedef float REALTYPE;  
193 - typedef unsigned int IDXTYPE; typedef unsigned int DIMTYPE; typedef int BINTYPE;  
194 - typedef Subset<BINTYPE, DIMTYPE> SUBSET;  
195 - typedef Data_Intervaller<std::vector<Data_Interval<IDXTYPE> >,IDXTYPE> INTERVALLER;  
196 - typedef boost::shared_ptr<Data_Splitter<INTERVALLER,IDXTYPE> > PSPLITTER;  
197 - typedef Data_Splitter_CV<INTERVALLER,IDXTYPE> SPLITTERCV;  
198 - typedef Data_Splitter_5050<INTERVALLER,IDXTYPE> SPLITTER5050;  
199 - typedef Data_Splitter_Resub<INTERVALLER,IDXTYPE> SPLITTERRESUB;  
200 - typedef Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALLER> DATAACCESSOR;  
201 - typedef Distance_Euclid<DATATYPE,DIMTYPE,SUBSET> DISTANCE;  
202 - typedef Classifier_kNN<RETURNTYPE,DATATYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR,DISTANCE> CLASSIFIERKNN;  
203 - typedef Criterion_Wrapper<RETURNTYPE,SUBSET,CLASSIFIERKNN,DATAACCESSOR> WRAPPERKNN;  
204 - typedef Sequential_Step_Straight_Threaded<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,24> EVALUATOR;  
205 -  
206 - // Initialize dataset  
207 - PSPLITTER dsp_outer(new SPLITTER5050()); // keep second half of data for independent testing of final classification performance  
208 - PSPLITTER dsp_inner(new SPLITTERCV(3)); // in the course of search use the first half of data by 3-fold cross-validation in wrapper FS criterion evaluation  
209 - boost::shared_ptr<Data_Scaler<DATATYPE> > dsc(new Data_Scaler_void<DATATYPE>()); // do not scale data  
210 - boost::shared_ptr<std::vector<PSPLITTER> > splitters(new std::vector<PSPLITTER>); // set-up data access  
211 - splitters->push_back(dsp_outer); //splitters->push_back(dsp_inner);  
212 - boost::shared_ptr<DATAACCESSOR> da(new DATAACCESSOR(data, splitters, dsc));  
213 - da->initialize();  
214 - da->setSplittingDepth(0); if(!da->getFirstSplit()) throw fst_error("50/50 data split failed.");  
215 - //da->setSplittingDepth(1); if(!da->getFirstSplit()) throw fst_error("3-fold cross-validation failure.");  
216 - boost::shared_ptr<SUBSET> sub(new SUBSET(da->getNoOfFeatures())); // initiate the storage for subset to-be-selected  
217 - //sub->select_all();  
218 -  
219 - // Run search  
220 - boost::shared_ptr<CLASSIFIERKNN> cknn(new CLASSIFIERKNN); cknn->set_k(1);  
221 - boost::shared_ptr<WRAPPERKNN> wknn(new WRAPPERKNN);  
222 - wknn->initialize(cknn,da);  
223 - boost::shared_ptr<EVALUATOR> eval(new EVALUATOR); // set-up the standard sequential search step object (option: hybrid, ensemble, etc.)  
224 - //Search_DOS<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,EVALUATOR> srch(eval); // set-up Sequential Forward Floating Selection search procedure  
225 - //srch.set_delta(delta);  
226 -  
227 - //FST::Search_SFFS<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,EVALUATOR> srch(eval);  
228 - //srch.set_search_direction(FST::BACKWARD);  
229 -  
230 - //FST::Search_SFS<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,EVALUATOR> srch(eval);  
231 - //srch.set_search_direction(FST::FORWARD);  
232 -  
233 - FST::Search_Monte_Carlo_Threaded<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,24> srch;  
234 - srch.set_cardinality_randomization(0.5); // probability of inclusion of each particular feature (~implies also the expected subset size)  
235 - srch.set_stopping_condition(0/*max trials*/,30/*seconds*/); // one or both values must have positive value  
236 -  
237 - RETURNTYPE critval_train;  
238 - if(!srch.search(0,critval_train,sub,wknn,std::cout)) throw fst_error("Search not finished.");  
239 -  
240 - // Create map matrix  
241 - const int dims = sub->get_d_raw();  
242 - cv::Mat xMap(1, dims, CV_16SC1),  
243 - yMap(1, dims, CV_16SC1);  
244 - int index = 0;  
245 - for (int i=0; i<dims; i++) {  
246 - if (sub->selected_raw(i)) {  
247 - xMap.at<short>(0, index) = i;  
248 - yMap.at<short>(0, index) = 0;  
249 - index++;  
250 - }  
251 - }  
252 -  
253 - remap = Remap(xMap, yMap, cv::INTER_NEAREST);  
254 - }  
255 - catch (fst_error &e) { qFatal("FST ERROR: %s, code=%d", e.what(), e.code()); }  
256 - catch (std::exception &e) { qFatal("non-FST ERROR: %s", e.what()); }  
257 - metadata >> remap;  
258 - //#else // MM_SDK_TRAINABLE  
259 - //qFatal("StreamwiseFS::train not supported.");  
260 - //#endif // MM_SDK_TRAINABLE  
261 - }  
262 -  
263 - void project(const Matrix &src, Matrix &dst) const  
264 - {  
265 - dst = src;  
266 - dst >> remap;  
267 - }  
268 -  
269 - void store(QDataStream &stream) const  
270 - {  
271 - stream << remap;  
272 - }  
273 -  
274 - void load(QDataStream &stream)  
275 - {  
276 - stream >> remap;  
277 - }  
278 -};  
279 -  
280 -MM_REGISTER(Feature, FST3DOS, true)  
281 -  
282 -  
283 -class FST3StreamwiseFS : public Feature  
284 -{  
285 - friend class Maker<StreamwiseFS,true>;  
286 -  
287 - QSharedPointer<Feature> weakLearnerTemplate;  
288 - int time;  
289 -  
290 - mm::Dup dup;  
291 - mm::Remap remap;  
292 -  
293 - StreamwiseFS(const QSharedPointer<Feature> &weakLearnerTemplate, int time)  
294 - : dup(weakLearnerTemplate, 1)  
295 - {  
296 - this->weakLearnerTemplate = weakLearnerTemplate;  
297 - this->time = time;  
298 - }  
299 -  
300 - static QString args()  
301 - {  
302 - return "<feature> weakLearnerTemplate, int time";  
303 - }  
304 -  
305 - static StreamwiseFS *make(const QString &args)  
306 - {  
307 - QStringList words = QtUtils::parse(args);  
308 - if (words.size() != 2) qFatal("StreamwiseFS::make invalid argument count.");  
309 -  
310 - QSharedPointer<Feature> weakLearnerTemplate = Feature::make(words[0]);  
311 - bool ok;  
312 - int time = words[1].toInt(&ok); assert(ok);  
313 -  
314 - return new StreamwiseFS(weakLearnerTemplate, time);  
315 - }  
316 -  
317 - QSharedPointer<Feature> clone() const  
318 - {  
319 - return QSharedPointer<Feature>(new StreamwiseFS(weakLearnerTemplate, time));  
320 - }  
321 -  
322 - void train(const MatrixList &data, Matrix &metadata)  
323 - {  
324 - QList< QSharedPointer<Feature> > weakLearners;  
325 - QList<MatrixList> projectedDataList;  
326 - QList<int> weakLearnerDimsList;  
327 - QList<DimensionStatus> dimStatusList;  
328 -  
329 - QTime timer; timer.start();  
330 - while (timer.elapsed() / 1000 < time) {  
331 - // Construct a new weak learner  
332 - QSharedPointer<Feature> newWeakLearner = weakLearnerTemplate->clone();  
333 - Matrix metadataCopy(metadata);  
334 - newWeakLearner->train(data, metadataCopy);  
335 - weakLearners.append(newWeakLearner);  
336 -  
337 - MatrixList projectedData = data;  
338 - projectedData >> *newWeakLearner;  
339 - projectedDataList.append(projectedData);  
340 - weakLearnerDimsList.append(projectedData.first().total() * projectedData.first().channels());  
341 - for (int i=0; i<weakLearnerDimsList.last(); i++) dimStatusList.append(Off);  
342 -  
343 - //#ifdef MM_SDK_TRAINABLE  
344 - try  
345 - {  
346 - typedef float RETURNTYPE; typedef float DATATYPE; typedef float REALTYPE;  
347 - typedef unsigned int IDXTYPE; typedef unsigned int DIMTYPE; typedef int BINTYPE;  
348 - typedef Subset<BINTYPE, DIMTYPE> SUBSET;  
349 - typedef Data_Intervaller<std::vector<Data_Interval<IDXTYPE> >,IDXTYPE> INTERVALLER;  
350 - typedef boost::shared_ptr<Data_Splitter<INTERVALLER,IDXTYPE> > PSPLITTER;  
351 - typedef Data_Splitter_CV<INTERVALLER,IDXTYPE> SPLITTERCV;  
352 - typedef Data_Splitter_5050<INTERVALLER,IDXTYPE> SPLITTER5050;  
353 - typedef Data_Accessor_Splitting_MemMM<DATATYPE,IDXTYPE,INTERVALLER> DATAACCESSOR;  
354 - typedef Distance_Euclid<DATATYPE,DIMTYPE,SUBSET> DISTANCE;  
355 - typedef Classifier_kNN<RETURNTYPE,DATATYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR,DISTANCE> CLASSIFIERKNN;  
356 - typedef Criterion_Wrapper<RETURNTYPE,SUBSET,CLASSIFIERKNN,DATAACCESSOR> WRAPPERKNN;  
357 - typedef Sequential_Step_Straight_Threaded<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,24> EVALUATOR;  
358 -  
359 - // Initialize dataset  
360 - PSPLITTER dsp_outer(new SPLITTER5050()); // keep second half of data for independent testing of final classification performance  
361 - PSPLITTER dsp_inner(new SPLITTERCV(3)); // in the course of search use the first half of data by 3-fold cross-validation in wrapper FS criterion evaluation  
362 - boost::shared_ptr<Data_Scaler<DATATYPE> > dsc(new Data_Scaler_void<DATATYPE>()); // do not scale data  
363 - boost::shared_ptr<std::vector<PSPLITTER> > splitters(new std::vector<PSPLITTER>); // set-up data access  
364 - splitters->push_back(dsp_outer); splitters->push_back(dsp_inner);  
365 - boost::shared_ptr<DATAACCESSOR> da(new DATAACCESSOR(projectedDataList, dimStatusList, splitters, dsc));  
366 - da->initialize();  
367 - da->setSplittingDepth(0); if(!da->getFirstSplit()) throw fst_error("50/50 data split failed.");  
368 - da->setSplittingDepth(1); if(!da->getFirstSplit()) throw fst_error("3-fold cross-validation failure.");  
369 - boost::shared_ptr<SUBSET> sub(new SUBSET(da->getNoOfFeatures())); // initiate the storage for subset to-be-selected  
370 -  
371 - { // Initialize subset from previous iteration results  
372 - sub->deselect_all();  
373 - int index = 0;  
374 - for (int i=0; i<dimStatusList.size(); i++) {  
375 - if (dimStatusList[i] == On) sub->select(index);  
376 - if (dimStatusList[i] != Ignore) index++;  
377 - }  
378 - }  
379 -  
380 - // Run search  
381 - boost::shared_ptr<CLASSIFIERKNN> cknn(new CLASSIFIERKNN); cknn->set_k(3); // set-up 3-Nearest Neighbor classifier based on Euclidean distances  
382 - boost::shared_ptr<WRAPPERKNN> wknn(new WRAPPERKNN); // wrap the 3-NN classifier to enable its usage as FS criterion (criterion value will be estimated by 3-fold cross-val.)  
383 - wknn->initialize(cknn,da);  
384 - boost::shared_ptr<EVALUATOR> eval(new EVALUATOR); // set-up the standard sequential search step object (option: hybrid, ensemble, etc.)  
385 - Search_DOS<RETURNTYPE,DIMTYPE,SUBSET,WRAPPERKNN,EVALUATOR> srch(eval); // set-up Sequential Forward Floating Selection search procedure  
386 - srch.set_delta(1);  
387 - RETURNTYPE critval_train;  
388 - if(!srch.search(0,critval_train,sub,wknn,std::cout)) throw fst_error("Search not finished.");  
389 -  
390 - { // Update results  
391 - int dslIndex = dimStatusList.size() - 1;  
392 - int subIndex = da->getNoOfFeatures() - 1;  
393 - for (int wlIndex = weakLearnerDimsList.size()-1; wlIndex >= 0; wlIndex--) {  
394 - const int weakLearnerDims = weakLearnerDimsList[wlIndex];  
395 - int numSelectedDims = 0;  
396 - for (int i=0; i<weakLearnerDims; i++) {  
397 - if (dimStatusList[dslIndex] != Ignore)  
398 - dimStatusList[dslIndex] = sub->selected_raw(subIndex--) ? numSelectedDims++, On : Ignore;  
399 - dslIndex--;  
400 - }  
401 -  
402 - if (numSelectedDims == 0) {  
403 - for (int j=0; j<weakLearnerDims; j++)  
404 - dimStatusList.removeAt(dslIndex+1);  
405 - weakLearnerDimsList.removeAt(wlIndex);  
406 - projectedDataList.removeAt(wlIndex);  
407 - weakLearners.removeAt(wlIndex);  
408 - }  
409 - }  
410 - }  
411 - }  
412 - catch (fst_error &e) { qFatal("FST ERROR: %s, code=%d", e.what(), e.code()); }  
413 - catch (std::exception &e) { qFatal("non-FST ERROR: %s", e.what()); }  
414 - //#else // MM_SDK_TRAINABLE  
415 - //qFatal("StreamwiseFS::train not supported.");  
416 - //#endif // MM_SDK_TRAINABLE  
417 - }  
418 -  
419 - dup = Dup(weakLearners);  
420 -  
421 - // Create map matrix  
422 - int dims = 0;  
423 - foreach (DimensionStatus ds, dimStatusList) if (ds == On) dims++;  
424 - cv::Mat xMap(1, dims, CV_16SC1),  
425 - yMap(1, dims, CV_16SC1);  
426 - int index = 0;  
427 - for (int i=0; i<dimStatusList.size(); i++) {  
428 - if (dimStatusList[i] == On) {  
429 - xMap.at<short>(0, index) = i;  
430 - yMap.at<short>(0, index) = 0;  
431 - index++;  
432 - }  
433 - }  
434 -  
435 - remap = Remap(xMap, yMap, cv::INTER_NEAREST);  
436 - }  
437 -  
438 - void project(const Matrix &src, Matrix &dst) const  
439 - {  
440 - dst = src;  
441 - dst >> dup >> mm::Cat >> remap;  
442 - }  
443 -  
444 - void store(QDataStream &stream) const  
445 - {  
446 - stream << dup << remap;  
447 - }  
448 -  
449 - void load(QDataStream &stream)  
450 - {  
451 - stream >> dup >> remap;  
452 - }  
453 -};  
454 -  
455 -MM_REGISTER(Feature, FST3StreamwiseFS, true)  
openbr/plugins/gui.cpp
@@ -5,6 +5,11 @@ @@ -5,6 +5,11 @@
5 #include <QMutex> 5 #include <QMutex>
6 #include <QMouseEvent> 6 #include <QMouseEvent>
7 #include <QPainter> 7 #include <QPainter>
  8 +#include <QMainWindow>
  9 +#include <QPushButton>
  10 +#include <QHBoxLayout>
  11 +#include <QFormLayout>
  12 +#include <QLineEdit>
8 13
9 #include <opencv2/imgproc/imgproc.hpp> 14 #include <opencv2/imgproc/imgproc.hpp>
10 #include "openbr_internal.h" 15 #include "openbr_internal.h"
@@ -65,6 +70,7 @@ public: @@ -65,6 +70,7 @@ public:
65 70
66 DisplayWindow(QWidget * parent = NULL) : QLabel(parent) 71 DisplayWindow(QWidget * parent = NULL) : QLabel(parent)
67 { 72 {
  73 + setFixedSize(200,200);
68 QApplication::instance()->installEventFilter(this); 74 QApplication::instance()->installEventFilter(this);
69 } 75 }
70 76
@@ -75,7 +81,13 @@ public slots: @@ -75,7 +81,13 @@ public slots:
75 81
76 show(); 82 show();
77 setPixmap(pixmap); 83 setPixmap(pixmap);
78 - setFixedSize(input.size()); 84 +
  85 + // We appear to get a warning on windows if we set window width < 104. This is of course not
  86 + // reflected in the Qt min size settings, and I don't know how to query it.
  87 + QSize temp = input.size();
  88 + if (temp.width() < 104)
  89 + temp.setWidth(104);
  90 + setFixedSize(temp);
79 } 91 }
80 92
81 93
@@ -188,6 +200,85 @@ private: @@ -188,6 +200,85 @@ private:
188 200
189 }; 201 };
190 202
  203 +class DisplayGUI : public QMainWindow
  204 +{
  205 + Q_OBJECT
  206 +
  207 +public:
  208 +
  209 + DisplayGUI(QWidget * parent = NULL) : QMainWindow(parent)
  210 + {
  211 + centralWidget = new QWidget();
  212 + layout = new QHBoxLayout();
  213 + inputLayout = new QVBoxLayout();
  214 +
  215 + button.setText("Set Template Metadata");
  216 +
  217 + layout->addWidget(&label);
  218 +
  219 + inputLayout->addWidget(&button);
  220 + layout->addLayout(inputLayout);
  221 +
  222 + centralWidget->setLayout(layout);
  223 +
  224 + setCentralWidget(centralWidget);
  225 +
  226 + connect(&button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
  227 + }
  228 +
  229 +public slots:
  230 + void showImage(const QPixmap & input)
  231 + {
  232 + pixmap = input;
  233 + foreach(const QString& label, keys) {
  234 + QLineEdit *edit = new QLineEdit;
  235 + fields.append(edit);
  236 + QFormLayout *form = new QFormLayout;
  237 + form->addRow(label, edit);
  238 + inputLayout->addLayout(form);
  239 + }
  240 +
  241 + show();
  242 + label.setPixmap(pixmap);
  243 + label.setFixedSize(input.size());
  244 + }
  245 +
  246 + QStringList waitForButtonPress()
  247 + {
  248 + QMutexLocker locker(&lock);
  249 + wait.wait(&lock);
  250 +
  251 + QStringList values;
  252 + for(int i = 0; i<fields.size(); i++) values.append(fields.at(i)->text());
  253 + return values;
  254 + }
  255 +
  256 +public slots:
  257 +
  258 + void buttonPressed()
  259 + {
  260 + wait.wakeAll();
  261 + }
  262 +
  263 + void setKeys(const QStringList& k)
  264 + {
  265 + keys = k;
  266 + }
  267 +
  268 +private:
  269 +
  270 + QWidget *centralWidget;
  271 + QStringList keys;
  272 + QList<QLineEdit*> fields;
  273 + QPushButton button;
  274 + QMutex lock;
  275 + QWaitCondition wait;
  276 + QPixmap pixmap;
  277 + QLabel label;
  278 + QHBoxLayout *layout;
  279 + QVBoxLayout *inputLayout;
  280 +
  281 +};
191 282
192 // I want a template class that doesn't look like a template class 283 // I want a template class that doesn't look like a template class
193 class NominalCreation 284 class NominalCreation
@@ -298,7 +389,7 @@ public: @@ -298,7 +389,7 @@ public:
298 { 389 {
299 dst = src; 390 dst = src;
300 391
301 - if (src.empty() || !Globals->useGui) 392 + if (src.empty())
302 return; 393 return;
303 394
304 foreach (const Template & t, src) { 395 foreach (const Template & t, src) {
@@ -427,6 +518,104 @@ public: @@ -427,6 +518,104 @@ public:
427 518
428 BR_REGISTER(Transform, ManualTransform) 519 BR_REGISTER(Transform, ManualTransform)
429 520
  521 +/*!
  522 + * \ingroup transforms
  523 + * \brief Elicits metadata for templates in a pretty GUI
  524 + * \author Scott Klum \cite sklum
  525 + */
  526 +class ElicitTransform : public TimeVaryingTransform
  527 +{
  528 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  529 + BR_PROPERTY(QStringList, keys, QStringList())
  530 +
  531 + Q_OBJECT
  532 +
  533 + MainThreadCreator creator;
  534 + DisplayGUI *gui;
  535 + QImage qImageBuffer;
  536 + QPixmap *displayBuffer;
  537 +
  538 +public:
  539 + ElicitTransform() : TimeVaryingTransform(false, false)
  540 + {
  541 + displayBuffer = NULL;
  542 + gui = NULL;
  543 + }
  544 +
  545 + ~ElicitTransform()
  546 + {
  547 + delete displayBuffer;
  548 + delete gui;
  549 + }
  550 +
  551 + void train(const TemplateList &data) { (void) data; }
  552 +
  553 + void project(const TemplateList &src, TemplateList &dst) const
  554 + {
  555 + Transform * non_const = (ElicitTransform *) this;
  556 + non_const->projectUpdate(src,dst);
  557 + }
  558 +
  559 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  560 + {
  561 + dst = src;
  562 +
  563 + if (src.empty()) return;
  564 +
  565 + for (int i = 0; i < dst.size(); i++) {
  566 + foreach(const cv::Mat &m, dst[i]) {
  567 + qImageBuffer = toQImage(m);
  568 + displayBuffer->convertFromImage(qImageBuffer);
  569 +
  570 + emit updateImage(displayBuffer->copy(displayBuffer->rect()));
  571 +
  572 + QStringList metadata = gui->waitForButtonPress();
  573 + for(int j = 0; j < keys.size(); j++) dst[i].file.set(keys[j],metadata[j]);
  574 + }
  575 + }
  576 + }
  577 +
  578 + void finalize(TemplateList & output)
  579 + {
  580 + (void) output;
  581 + emit hideWindow();
  582 + }
  583 +
  584 + void init()
  585 + {
  586 + initActual<DisplayGUI>();
  587 + }
  588 +
  589 + template<typename GUIType>
  590 + void initActual()
  591 + {
  592 + if (!Globals->useGui)
  593 + return;
  594 +
  595 + TimeVaryingTransform::init();
  596 +
  597 + if (displayBuffer)
  598 + delete displayBuffer;
  599 +
  600 + displayBuffer = new QPixmap();
  601 +
  602 + if (gui)
  603 + delete gui;
  604 +
  605 + gui = creator.getItem<GUIType>();
  606 + gui->setKeys(keys);
  607 + // Connect our signals to the window's slots
  608 + connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap)));
  609 + connect(this, SIGNAL(hideWindow()), gui, SLOT(hide()));
  610 + }
  611 +
  612 +signals:
  613 +
  614 + void updateImage(const QPixmap & input);
  615 + void hideWindow();
  616 +
  617 +};
  618 +BR_REGISTER(Transform, ElicitTransform)
430 619
431 /*! 620 /*!
432 * \ingroup transforms 621 * \ingroup transforms
openbr/plugins/keypoint.cpp
@@ -222,9 +222,9 @@ class GridTransform : public UntrainableTransform @@ -222,9 +222,9 @@ class GridTransform : public UntrainableTransform
222 QList<QPointF> landmarks; 222 QList<QPointF> landmarks;
223 const float row_step = 1.f * src.m().rows / rows; 223 const float row_step = 1.f * src.m().rows / rows;
224 const float column_step = 1.f * src.m().cols / columns; 224 const float column_step = 1.f * src.m().cols / columns;
225 - for (float i=row_step/2; i<src.m().rows; i+=row_step)  
226 - for (float j=column_step/2; j<src.m().cols; j+=column_step)  
227 - landmarks.append(QPointF(i,j)); 225 + for (float y=row_step/2; y<src.m().rows; y+=row_step)
  226 + for (float x=column_step/2; x<src.m().cols; x+=column_step)
  227 + landmarks.append(QPointF(x,y));
228 dst = src; 228 dst = src;
229 dst.file.setPoints(landmarks); 229 dst.file.setPoints(landmarks);
230 } 230 }
openbr/plugins/meta.cpp
@@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform @@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform
264 264
265 virtual void project(const TemplateList &src, TemplateList &dst) const 265 virtual void project(const TemplateList &src, TemplateList &dst) const
266 { 266 {
267 - //dst = Expanded(src);  
268 if (src.empty()) return; 267 if (src.empty()) return;
269 Template out; 268 Template out;
270 269
@@ -682,8 +681,10 @@ public: @@ -682,8 +681,10 @@ public:
682 681
683 void init() 682 void init()
684 { 683 {
685 - if (transform && transform->timeVarying())  
686 - transform = new br::TimeInvariantWrapperTransform(transform); 684 + if (!transform)
  685 + return;
  686 +
  687 + trainable = transform->trainable;
687 } 688 }
688 689
689 }; 690 };
openbr/plugins/misc.cpp
@@ -332,57 +332,6 @@ class AnonymizeTransform : public UntrainableMetaTransform @@ -332,57 +332,6 @@ class AnonymizeTransform : public UntrainableMetaTransform
332 332
333 BR_REGISTER(Transform, AnonymizeTransform) 333 BR_REGISTER(Transform, AnonymizeTransform)
334 334
335 -// TODO: Use a global Mutex to prevent concurrent reads from stdin  
336 -#if 0  
337 -/*!  
338 - * \ingroup transforms  
339 - * \brief Name a point  
340 - * \author Scott Klum \cite sklum  
341 - */  
342 -class ElicitMetadataTransform : public UntrainableMetaTransform  
343 -{  
344 - Q_OBJECT  
345 -  
346 - Q_PROPERTY(QStringList metadata READ get_metadata WRITE set_metadata RESET reset_metadata STORED false)  
347 - BR_PROPERTY(QStringList, metadata, QStringList())  
348 -  
349 - void init()  
350 - {  
351 - Globals->setProperty("parallelism", "0"); // Can only work in single threaded mode  
352 - }  
353 -  
354 - void project(const Template &src, Template &dst) const  
355 - {  
356 - dst = src;  
357 -  
358 - QTextStream stream(stdin);  
359 -  
360 - foreach (const QString &key, metadata) {  
361 - qDebug() << "Specify a value for key: " << key;  
362 - QString value = stream.readLine();  
363 - if (value[0] == '(') {  
364 - QStringList values = value.split(',');  
365 - if (values.size() == 2) /* QPointF */ {  
366 - values[1].chop(1);  
367 - QPointF point(values[0].mid(1).toFloat(), values[1].toFloat());  
368 - if (key != "Points") dst.file.set(key, point);  
369 - else dst.file.appendPoint(point);  
370 - }  
371 - else /* QRectF */ {  
372 - values[3].chop(1);  
373 - QRectF rect(values[0].mid(1).toFloat(), values[1].toFloat(), values[2].toFloat(), values[3].toFloat());  
374 - if (key != "Rects") dst.file.set(key, rect);  
375 - else dst.file.appendRect(rect);  
376 - }  
377 - }  
378 - else dst.file.set(key, value);  
379 - }  
380 - }  
381 -};  
382 -  
383 -BR_REGISTER(Transform, ElicitMetadataTransform)  
384 -#endif  
385 -  
386 /*! 335 /*!
387 * \ingroup transforms 336 * \ingroup transforms
388 * \brief Change the br::Template::file extension 337 * \brief Change the br::Template::file extension
@@ -405,27 +354,31 @@ BR_REGISTER(Transform, AsTransform) @@ -405,27 +354,31 @@ BR_REGISTER(Transform, AsTransform)
405 354
406 /*! 355 /*!
407 * \ingroup transforms 356 * \ingroup transforms
408 - * \brief Change the template subject using a regular expresion matched to the file's base name.  
409 - * \author Josh Klontz \cite jklontz 357 + * \brief Apply the input regular expression to the value of inputProperty, store the matched portion in outputProperty.
  358 + * \author Charles Otto \cite caotto
410 */ 359 */
411 -class SubjectTransform : public UntrainableMetaTransform 360 +class RegexPropertyTransform : public UntrainableMetaTransform
412 { 361 {
413 Q_OBJECT 362 Q_OBJECT
414 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) 363 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false)
  364 + Q_PROPERTY(QString inputProperty READ get_inputProperty WRITE set_inputProperty RESET reset_inputProperty STORED false)
  365 + Q_PROPERTY(QString outputProperty READ get_outputProperty WRITE set_outputProperty RESET reset_outputProperty STORED false)
415 BR_PROPERTY(QString, regexp, "(.*)") 366 BR_PROPERTY(QString, regexp, "(.*)")
  367 + BR_PROPERTY(QString, inputProperty, "name")
  368 + BR_PROPERTY(QString, outputProperty, "Label")
416 369
417 void project(const Template &src, Template &dst) const 370 void project(const Template &src, Template &dst) const
418 { 371 {
419 dst = src; 372 dst = src;
420 QRegularExpression re(regexp); 373 QRegularExpression re(regexp);
421 - QRegularExpressionMatch match = re.match(dst.file.baseName()); 374 + QRegularExpressionMatch match = re.match(dst.file.get<QString>(inputProperty));
422 if (!match.hasMatch()) 375 if (!match.hasMatch())
423 - qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.baseName()));  
424 - dst.file.set("Subject", match.captured(match.lastCapturedIndex())); 376 + qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.get<QString>(inputProperty)));
  377 + dst.file.set(outputProperty, match.captured(match.lastCapturedIndex()));
425 } 378 }
426 }; 379 };
427 380
428 -BR_REGISTER(Transform, SubjectTransform) 381 +BR_REGISTER(Transform, RegexPropertyTransform)
429 382
430 /*! 383 /*!
431 * \ingroup transforms 384 * \ingroup transforms
@@ -521,6 +474,73 @@ class RestoreMatTransform : public UntrainableMetaTransform @@ -521,6 +474,73 @@ class RestoreMatTransform : public UntrainableMetaTransform
521 BR_REGISTER(Transform, RestoreMatTransform) 474 BR_REGISTER(Transform, RestoreMatTransform)
522 475
523 476
  477 +/*!
  478 + * \ingroup transforms
  479 + * \brief Incrementally output templates received to a gallery, based on the current filename
  480 + * When a template is received in projectUpdate for the first time since a finalize, open a new gallery based on the
  481 + * template's filename, and the galleryFormat property.
  482 + * Templates received in projectUpdate will be output to the gallery with a filename combining their original filename and
  483 + * their FrameNumber property, with the file extension specified by the fileFormat property.
  484 + * \author Charles Otto \cite caotto
  485 + */
  486 +class IncrementalOutputTransform : public TimeVaryingTransform
  487 +{
  488 + Q_OBJECT
  489 +
  490 + Q_PROPERTY(QString galleryFormat READ get_galleryFormat WRITE set_galleryFormat RESET reset_galleryFormat STORED false)
  491 + Q_PROPERTY(QString fileFormat READ get_fileFormat WRITE set_fileFormat RESET reset_fileFormat STORED false)
  492 + BR_PROPERTY(QString, galleryFormat, "")
  493 + BR_PROPERTY(QString, fileFormat, ".png")
  494 +
  495 + bool galleryUp;
  496 +
  497 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  498 + {
  499 + if (src.empty())
  500 + return;
  501 +
  502 + if (!galleryUp) {
  503 + QFileInfo finfo(src[0].file.name);
  504 + QString galleryName = finfo.baseName() + galleryFormat;
  505 +
  506 + writer = QSharedPointer<Gallery> (Factory<Gallery>::make(galleryName));
  507 + galleryUp = true;
  508 + }
  509 +
  510 + dst = src;
  511 + foreach(const Template & t, src) {
  512 + if (t.empty())
  513 + continue;
  514 +
  515 + // Build the output filename for this template
  516 + QFileInfo finfo(t.file.name);
  517 + QString outputName = finfo.baseName() +"_" + t.file.get<QString>("FrameNumber") + fileFormat;
  518 +
  519 + Template out = t;
  520 + out.file.name = outputName;
  521 + writer->write(out);
  522 + }
  523 + }
  524 +
  525 + void train(const TemplateList& data)
  526 + {
  527 + (void) data;
  528 + }
  529 +
  530 + // Drop the current gallery.
  531 + void finalize(TemplateList & data)
  532 + {
  533 + (void) data;
  534 + galleryUp = false;
  535 + }
  536 +
  537 + QSharedPointer<Gallery> writer;
  538 +public:
  539 + IncrementalOutputTransform() : TimeVaryingTransform(false,false) {galleryUp = false;}
  540 +};
  541 +
  542 +BR_REGISTER(Transform, IncrementalOutputTransform)
  543 +
524 class EventTransform : public UntrainableMetaTransform 544 class EventTransform : public UntrainableMetaTransform
525 { 545 {
526 Q_OBJECT 546 Q_OBJECT
openbr/plugins/openbr_internal.h
@@ -24,81 +24,27 @@ private: @@ -24,81 +24,27 @@ private:
24 }; 24 };
25 25
26 /*! 26 /*!
27 - * \brief A br::MetaTransform that does not require training data. 27 + * \brief A br::Transform expecting multiple matrices per template.
28 */ 28 */
29 -class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform 29 +class BR_EXPORT MetaTransform : public Transform
30 { 30 {
31 Q_OBJECT 31 Q_OBJECT
32 32
33 protected: 33 protected:
34 - UntrainableMetaTransform() : UntrainableTransform(false) {}  
35 -};  
36 -  
37 -/*!  
38 - * \brief A br::Transform for which the results of project may change due to prior calls to project  
39 - */  
40 -class BR_EXPORT TimeVaryingTransform : public Transform  
41 -{  
42 - Q_OBJECT  
43 -  
44 -public:  
45 - virtual bool timeVarying() const { return true; }  
46 -  
47 - virtual void project(const Template &src, Template &dst) const  
48 - {  
49 - qFatal("No const project defined for time-varying transform");  
50 - (void) dst; (void) src;  
51 - }  
52 -  
53 - virtual void project(const TemplateList &src, TemplateList &dst) const  
54 - {  
55 - qFatal("No const project defined for time-varying transform");  
56 - (void) dst; (void) src;  
57 - }  
58 -  
59 - // Get a compile failure if this isn't here to go along with the other  
60 - // projectUpdate, no idea why  
61 - virtual void projectUpdate(const Template & src, Template & dst)  
62 - {  
63 - (void) src; (void) dst;  
64 - qFatal("do something useful");  
65 - }  
66 -  
67 - virtual void projectUpdate(const TemplateList &src, TemplateList &dst)  
68 - {  
69 - foreach (const Template & src_part, src) {  
70 - Template out;  
71 - projectUpdate(src_part, out);  
72 - dst.append(out);  
73 - }  
74 - }  
75 -  
76 - /*!  
77 - *\brief For transforms that don't do any training, this default implementation  
78 - * which creates a new copy of the Transform from its description string is sufficient.  
79 - */  
80 - virtual Transform * smartCopy()  
81 - {  
82 - return this->clone();  
83 - }  
84 -  
85 -  
86 -protected:  
87 - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} 34 + MetaTransform() : Transform(false) {}
88 }; 35 };
89 36
90 /*! 37 /*!
91 - * \brief A br::Transform expecting multiple matrices per template. 38 + * \brief A br::MetaTransform that does not require training data.
92 */ 39 */
93 -class BR_EXPORT MetaTransform : public Transform 40 +class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform
94 { 41 {
95 Q_OBJECT 42 Q_OBJECT
96 43
97 protected: 44 protected:
98 - MetaTransform() : Transform(false) {} 45 + UntrainableMetaTransform() : UntrainableTransform(false) {}
99 }; 46 };
100 47
101 -  
102 class TransformCopier : public ResourceMaker<Transform> 48 class TransformCopier : public ResourceMaker<Transform>
103 { 49 {
104 public: 50 public:
@@ -151,6 +97,63 @@ private: @@ -151,6 +97,63 @@ private:
151 Transform * baseTransform; 97 Transform * baseTransform;
152 }; 98 };
153 99
  100 +/*!
  101 + * \brief A br::Transform for which the results of project may change due to prior calls to project
  102 + */
  103 +class BR_EXPORT TimeVaryingTransform : public Transform
  104 +{
  105 + Q_OBJECT
  106 +
  107 +public:
  108 +
  109 + virtual bool timeVarying() const { return true; }
  110 +
  111 + virtual void project(const Template &src, Template &dst) const
  112 + {
  113 + timeInvariantAlias.project(src,dst);
  114 + }
  115 +
  116 + virtual void project(const TemplateList &src, TemplateList &dst) const
  117 + {
  118 + timeInvariantAlias.project(src,dst);
  119 + }
  120 +
  121 + // Get a compile failure if this isn't here to go along with the other
  122 + // projectUpdate, no idea why
  123 + virtual void projectUpdate(const Template & src, Template & dst)
  124 + {
  125 + (void) src; (void) dst;
  126 + qFatal("do something useful");
  127 + }
  128 +
  129 + virtual void projectUpdate(const TemplateList &src, TemplateList &dst)
  130 + {
  131 + foreach (const Template & src_part, src) {
  132 + Template out;
  133 + projectUpdate(src_part, out);
  134 + dst.append(out);
  135 + }
  136 + }
  137 +
  138 + /*!
  139 + *\brief For transforms that don't do any training, this default implementation
  140 + * which creates a new copy of the Transform from its description string is sufficient.
  141 + */
  142 + virtual Transform * smartCopy()
  143 + {
  144 + return this->clone();
  145 + }
  146 +
  147 +protected:
  148 + // Since copies aren't actually made until project is called, we can set up
  149 + // timeInvariantAlias in the constructor.
  150 + TimeInvariantWrapperTransform timeInvariantAlias;
  151 + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable), timeInvariantAlias(this)
  152 + {
  153 + //
  154 + }
  155 +};
  156 +
154 157
155 /*! 158 /*!
156 * \brief A MetaTransform that aggregates some sub-transforms 159 * \brief A MetaTransform that aggregates some sub-transforms
@@ -165,15 +168,17 @@ public: @@ -165,15 +168,17 @@ public:
165 168
166 virtual void project(const Template &src, Template &dst) const 169 virtual void project(const Template &src, Template &dst) const
167 { 170 {
168 - if (timeVarying()) qFatal("No const project defined for time-varying transform"); 171 + if (timeVarying()) {
  172 + timeInvariantAlias.project(src,dst);
  173 + return;
  174 + }
169 _project(src, dst); 175 _project(src, dst);
170 } 176 }
171 177
172 virtual void project(const TemplateList &src, TemplateList &dst) const 178 virtual void project(const TemplateList &src, TemplateList &dst) const
173 { 179 {
174 if (timeVarying()) { 180 if (timeVarying()) {
175 - CompositeTransform * non_const = const_cast<CompositeTransform *>(this);  
176 - non_const->projectUpdate(src,dst); 181 + timeInvariantAlias.project(src,dst);
177 return; 182 return;
178 } 183 }
179 _project(src, dst); 184 _project(src, dst);
openbr/plugins/phash.cmake deleted
1 -set(BR_WITH_PHASH OFF CACHE BOOL "Build with pHash")  
2 -  
3 -if(${BR_WITH_PHASH})  
4 - find_package(pHash REQUIRED)  
5 - find_package(CImg REQUIRED)  
6 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/phash.cpp ${PHASH_SRC})  
7 -endif()  
openbr/plugins/phash.cpp deleted
1 -#include <opencv2/core/core.hpp>  
2 -#include <pHash.h>  
3 -#include <mm_plugin.h>  
4 -  
5 -using namespace mm;  
6 -  
7 -/**** PHASH ****/  
8 -class pHashEnroll : public UntrainableFeature  
9 -{  
10 - void project(const Matrix &src, Matrix &dst) const  
11 - {  
12 - CImg<uint8_t> cImg(src.data, src.cols, src.rows, 1, src.channels());  
13 - cv::Mat m(1, sizeof(ulong64), CV_8UC1);  
14 - ulong64 hash;  
15 - if (ph_dct_imagehash(cImg, hash) == -1)  
16 - qFatal("pHashEnroll::project ph_dct_imagehash failure for file %s.", qPrintable(src.metadata.fileName));  
17 - memcpy(m.data, &hash, sizeof(ulong64));  
18 - dst = Matrix(m, src.metadata);  
19 - }  
20 -  
21 - /*** Taken from pHash, modified to take in a CImg instead of a file. ***/  
22 - static CImg<float>* ph_dct_matrix(const int N){  
23 - CImg<float> *ptr_matrix = new CImg<float>(N,N,1,1,1/sqrt((float)N));  
24 - const float c1 = sqrt(2.0/N);  
25 - for (int x=0;x<N;x++){  
26 - for (int y=1;y<N;y++){  
27 - *ptr_matrix->data(x,y) = c1*cos((cimg::PI/2/N)*y*(2*x+1));  
28 - }  
29 - }  
30 - return ptr_matrix;  
31 - }  
32 -  
33 - static int ph_dct_imagehash(CImg<uint8_t> src, ulong64 &hash)  
34 - {  
35 - CImg<float> meanfilter(7,7,1,1,1);  
36 - CImg<float> img;  
37 - if (src.spectrum() == 3){  
38 - img = src.RGBtoYCbCr().channel(0).get_convolve(meanfilter);  
39 - } else if (src.spectrum() == 4){  
40 - int width = img.width();  
41 - int height = img.height();  
42 - int depth = img.depth();  
43 - img = src.crop(0,0,0,0,width-1,height-1,depth-1,2).RGBtoYCbCr().channel(0).get_convolve(meanfilter);  
44 - } else {  
45 - img = src.channel(0).get_convolve(meanfilter);  
46 - }  
47 -  
48 - img.resize(32,32);  
49 - CImg<float> *C = ph_dct_matrix(32);  
50 - CImg<float> Ctransp = C->get_transpose();  
51 -  
52 - CImg<float> dctImage = (*C)*img*Ctransp;  
53 -  
54 - CImg<float> subsec = dctImage.crop(1,1,8,8).unroll('x');;  
55 -  
56 - float median = subsec.median();  
57 - ulong64 one = 0x0000000000000001;  
58 - hash = 0x0000000000000000;  
59 - for (int i=0;i< 64;i++){  
60 - float current = subsec(i);  
61 - if (current > median)  
62 - hash |= one;  
63 - one = one << 1;  
64 - }  
65 -  
66 - delete C;  
67 -  
68 - return 0;  
69 - }  
70 -};  
71 -  
72 -MM_REGISTER(Feature, pHashEnroll, false)  
73 -  
74 -  
75 -/**** PHASH_COMPARE ****/  
76 -class pHashCompare : public ComparerBase  
77 -{  
78 - float compare(const cv::Mat &a, const cv::Mat &b) const  
79 - {  
80 - return 1.f - 1.f * ph_hamming_distance(*reinterpret_cast<ulong64*>(a.data), *reinterpret_cast<ulong64*>(b.data)) / 64;  
81 - }  
82 -};  
83 -  
84 -MM_REGISTER(Comparer, pHashCompare, false)  
85 -  
86 -  
87 -/**** PHASH ****/  
88 -class pHash : public Algorithm  
89 -{  
90 - QString algorithm() const  
91 - {  
92 - return "Open+pHashEnroll:Identity:pHashCompare";  
93 - }  
94 -};  
95 -  
96 -MM_REGISTER(Algorithm, pHash, false)  
openbr/plugins/pp4.cmake deleted
1 -set(BR_WITH_PP4 OFF CACHE BOOL "Build with PittPatt 4")  
2 -  
3 -if(${BR_WITH_PP4})  
4 - find_package(PP4 REQUIRED)  
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp)  
6 - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS})  
7 - install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib)  
8 - install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4)  
9 -endif()  
openbr/plugins/pp4.cpp deleted
1 -#include <QThreadPool>  
2 -#include <pittpatt_errors.h>  
3 -#include <pittpatt_nc_sdk.h>  
4 -#include <pittpatt_raw_image_io.h>  
5 -#include <pittpatt_license.h>  
6 -#include <mm_plugin.h>  
7 -  
8 -#define TRY(CC) \  
9 -{ \  
10 - if ((CC) != PPR_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_error_message(CC)); \  
11 -}  
12 -  
13 -#define TRY_VIDEO(CC) \  
14 -{ \  
15 - if ((CC) != PPR_VIDEO_IO_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_video_io_error_message(CC)); \  
16 -}  
17 -  
18 -#define TRY_RAW_IMAGE(CC) \  
19 -{ \  
20 - if ((CC) != PPR_RAW_IMAGE_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_raw_image_error_message(CC)); \  
21 -}  
22 -  
23 -using namespace mm;  
24 -  
25 -/*!  
26 - * \brief PittPatt 4 context  
27 - * \author Josh Klontz \cite jklontz  
28 - * \warning Needs a maintainer.  
29 - */  
30 -struct PP4Context  
31 -{  
32 - static ppr_context_type context;  
33 -  
34 - static void createRawImage(const cv::Mat &src, ppr_raw_image_type &dst)  
35 - {  
36 - ppr_raw_image_create(&dst, src.cols, src.rows, PPR_RAW_IMAGE_BGR24);  
37 - assert((src.type() == CV_8UC3) && src.isContinuous());  
38 - memcpy(dst.data, src.data, 3*src.rows*src.cols);  
39 - }  
40 -  
41 - static void createMat(const ppr_template_type &src, cv::Mat &dst)  
42 - {  
43 - ppr_flat_template_type flat_template;  
44 - TRY(ppr_flatten_template(context,src,&flat_template))  
45 - dst = cv::Mat(1, flat_template.num_bytes, CV_8UC1, flat_template.data).clone();  
46 - ppr_free_flat_template(flat_template);  
47 - }  
48 -  
49 - static void createTemplate(const cv::Mat &src, ppr_template_type *dst)  
50 - {  
51 - ppr_flat_template_type flat_template;  
52 - flat_template.num_bytes = src.cols;  
53 - flat_template.data = src.data;  
54 - TRY(ppr_unflatten_template(context, flat_template, dst))  
55 - }  
56 -  
57 - static QString toString(const ppr_landmark_category_type &category)  
58 - {  
59 - switch (category) {  
60 - case PPR_LANDMARK_LEFT_EYE:  
61 - return "Left_Eye";  
62 - case PPR_LANDMARK_RIGHT_EYE:  
63 - return "Right_Eye";  
64 - case PPR_LANDMARK_NOSE_BASE:  
65 - return "Nose_Base";  
66 - case PPR_LANDMARK_NOSE_BRIDGE:  
67 - return "Nose_Bridge";  
68 - case PPR_LANDMARK_NOSE_TIP:  
69 - return "Nose_Tip";  
70 - case PPR_LANDMARK_NOSE_TOP:  
71 - return "Nose_Top";  
72 - case PPR_LANDMARK_EYE_NOSE:  
73 - return "Eye_Nose";  
74 - case PPR_LANDMARK_MOUTH:  
75 - return "Mouth";  
76 - }  
77 -  
78 - return "Unknown";  
79 - }  
80 -  
81 - static File toMetadata(const ppr_object_type &object)  
82 - {  
83 - File metadata;  
84 - metadata.insert("PP4_Object_X", object.position.x - object.dimensions.width/2);  
85 - metadata.insert("PP4_Object_Y", object.position.y - object.dimensions.height/2);  
86 - metadata.insert("PP4_Object_Width", object.dimensions.width);  
87 - metadata.insert("PP4_Object_Height", object.dimensions.height);  
88 - metadata.insert("PP4_Object_Confidence", object.confidence);  
89 - metadata.insert("PP4_Object_Roll", object.rotation.roll);  
90 - metadata.insert("PP4_Object_Pitch", object.rotation.pitch);  
91 - metadata.insert("PP4_Object_Yaw", object.rotation.yaw);  
92 - metadata.insert("PP4_Object_Precision", object.rotation.precision);  
93 - metadata.insert("PP4_Object_ModelID", object.model_id);  
94 - metadata.insert("PP4_Object_NumLandmarks", object.num_landmarks);  
95 - metadata.insert("PP4_Object_Size", object.size);  
96 -  
97 - QList<ppr_landmark_category_type> categories;  
98 - categories << PPR_LANDMARK_RIGHT_EYE  
99 - << PPR_LANDMARK_LEFT_EYE  
100 - << PPR_LANDMARK_NOSE_BASE  
101 - << PPR_LANDMARK_NOSE_BRIDGE  
102 - << PPR_LANDMARK_NOSE_TIP  
103 - << PPR_LANDMARK_NOSE_TOP  
104 - << PPR_LANDMARK_EYE_NOSE  
105 - << PPR_LANDMARK_MOUTH;  
106 -  
107 - for (int i=0; i<categories.size(); i++) {  
108 - ppr_landmark_category_type category = categories[i];  
109 - QString metadataString = QString("PP4_Landmark%1_%2").arg(QString::number(i), toString(category));  
110 -  
111 - bool found = false;  
112 - for (int j=0; j<object.num_landmarks; j++) {  
113 - ppr_landmark_type &landmark = object.landmarks[j];  
114 - if (landmark.category != category) continue;  
115 -  
116 - metadata.insert(metadataString+"_X", landmark.position.x);  
117 - metadata.insert(metadataString+"_Y", landmark.position.y);  
118 - metadata.insert(metadataString+"_Category", landmark.category);  
119 - metadata.insert(metadataString+"_ModelID", landmark.model_id);  
120 - metadata.insert(metadataString+"_Index", j);  
121 - found = true;  
122 - break;  
123 - }  
124 -  
125 - if (!found) {  
126 - metadata.insert(metadataString+"_X", -1);  
127 - metadata.insert(metadataString+"_Y", -1);  
128 - metadata.insert(metadataString+"_Category", -1);  
129 - metadata.insert(metadataString+"_ModelID", -1);  
130 - metadata.insert(metadataString+"_Index", -1);  
131 - }  
132 - }  
133 -  
134 - return metadata;  
135 - }  
136 -  
137 - static ppr_object_type fromMetadata(const File &metadata)  
138 - {  
139 - ppr_object_type object;  
140 -  
141 - object.position.x = metadata.value("PP4_Object_X").toFloat() + metadata.value("PP4_Object_Width").toFloat()/2;  
142 - object.position.y = metadata.value("PP4_Object_Y").toFloat() + metadata.value("PP4_Object_Height").toFloat()/2;  
143 - object.dimensions.width = metadata.value("PP4_Object_Width").toFloat();  
144 - object.dimensions.height = metadata.value("PP4_Object_Height").toFloat();  
145 - object.confidence = metadata.value("PP4_Object_Confidence").toFloat();  
146 - object.rotation.roll = metadata.value("PP4_Object_Roll").toFloat();  
147 - object.rotation.pitch = metadata.value("PP4_Object_Pitch").toFloat();  
148 - object.rotation.yaw = metadata.value("PP4_Object_Yaw").toFloat();  
149 - object.rotation.precision = (ppr_precision_type) metadata.value("PP4_Object_Precision").toFloat();  
150 - object.model_id = metadata.value("PP4_Object_ModelID").toInt();  
151 - object.num_landmarks = metadata.value("PP4_Object_NumLandmarks").toInt();  
152 - object.size = metadata.value("PP4_Object_Size").toFloat();  
153 -  
154 - QStringList landmarkNames = QStringList(metadata.keys()).filter(QRegExp("(.*)_Category")).replaceInStrings("_Category", "");  
155 - object.landmarks = new ppr_landmark_type[object.num_landmarks];  
156 - for (int j=0; j<landmarkNames.size(); j++) {  
157 - int landmarkIndex = metadata.value(landmarkNames[j]+"_Index").toInt();  
158 - if (landmarkIndex == -1) continue;  
159 - object.landmarks[landmarkIndex].position.x = metadata.value(landmarkNames[j]+"_X").toFloat();  
160 - object.landmarks[landmarkIndex].position.y = metadata.value(landmarkNames[j]+"_Y").toFloat();  
161 - object.landmarks[landmarkIndex].category = (ppr_landmark_category_type)metadata.value(landmarkNames[j]+"_Category").toInt();  
162 - object.landmarks[landmarkIndex].model_id = metadata.value(landmarkNames[j]+"_ModelID").toInt();  
163 - landmarkIndex++;  
164 - }  
165 -  
166 - return object;  
167 - }  
168 -  
169 - static void freeObject(ppr_object_type &object)  
170 - {  
171 - delete[] object.landmarks;  
172 - object.landmarks = NULL;  
173 - object.num_landmarks = 0;  
174 - }  
175 -};  
176 -  
177 -ppr_context_type PP4Context::context;  
178 -  
179 -/*!  
180 - * \ingroup initializers  
181 - * \brief Initialize PittPatt 4  
182 - * \author Josh Klontz \cite jklontz  
183 - * \warning Needs a maintainer.  
184 - */  
185 -class PP4Initializer : public Initializer  
186 - , public PP4Context  
187 -{  
188 - Q_OBJECT  
189 -  
190 - void initialize() const  
191 - {  
192 - context = ppr_get_context();  
193 - TRY(ppr_enable_recognition(context))  
194 - TRY(ppr_set_license(context, my_license_id, my_license_key))  
195 - TRY(ppr_set_models_path(context, qPrintable(Globals->SDKPath + "/models/pp4")))  
196 - TRY(ppr_set_num_recognition_threads(context, QThreadPool::globalInstance()->maxThreadCount()))  
197 - TRY(ppr_set_num_detection_threads(context, 1))  
198 - TRY(ppr_set_detection_precision(context, PPR_FINE_PRECISION))  
199 - TRY(ppr_set_landmark_detector_type(context, PPR_DUAL_MULTI_POSE_LANDMARK_DETECTOR, PPR_AUTOMATIC_LANDMARKS))  
200 - TRY(ppr_set_min_size(context, 4))  
201 - TRY(ppr_set_frontal_yaw_constraint(context, PPR_FRONTAL_YAW_CONSTRAINT_PERMISSIVE))  
202 - TRY(ppr_set_template_extraction_type(context, PPR_EXTRACT_DOUBLE))  
203 - TRY(ppr_initialize_context(context))  
204 - Globals->Abbreviations.insert("PP4", "Open+PP4Detect!PP4Enroll:PP4Compare");  
205 - }  
206 -  
207 - void finalize() const  
208 - {  
209 - TRY(ppr_release_context(context))  
210 - ppr_finalize_sdk();  
211 - }  
212 -};  
213 -  
214 -MM_REGISTER(Initializer, PP4Initializer, "")  
215 -  
216 -/*!  
217 - * \ingroup transforms  
218 - * \brief Detect a face in PittPatt 4  
219 - * \author Josh Klontz \cite jklontz  
220 - * \warning Needs a maintainer.  
221 - */  
222 -class PP4Detect : public UntrainableMetaFeature  
223 - , public PP4Context  
224 -{  
225 - Q_OBJECT  
226 -  
227 - void project(const Template &src, Template &dst) const  
228 - {  
229 - dst.file = src.file;  
230 -  
231 - foreach (const cv::Mat &matrix, src) {  
232 - ppr_raw_image_type raw_image;  
233 - createRawImage(matrix, raw_image);  
234 - ppr_image_type image;  
235 - TRY(ppr_create_image(raw_image, &image))  
236 - ppr_object_list_type object_list;  
237 - TRY(ppr_detect_objects(context, image, &object_list))  
238 -  
239 - QList<ppr_object_type> objects;  
240 - if (src.file.getBool("ForceEnrollment")) objects = getBestObject(object_list);  
241 - else objects = getAllObjects(object_list);  
242 -  
243 - foreach (const ppr_object_type &object, objects) {  
244 - dst.file.append(toMetadata(object));  
245 - dst += matrix;  
246 - }  
247 -  
248 - ppr_free_object_list(object_list);  
249 - ppr_free_image(image);  
250 - ppr_raw_image_free(raw_image);  
251 - }  
252 -  
253 - if (src.file.getBool("ForceEnrollment") && dst.isEmpty()) dst += cv::Mat();  
254 - }  
255 -  
256 -private:  
257 - QList<ppr_object_type> getBestObject(ppr_object_list_type object_list) const  
258 - {  
259 - int best_index = -1;  
260 - float best_confidence = 0;  
261 - for (int i=0; i<object_list.num_objects; i++) {  
262 - ppr_object_type object = object_list.objects[i];  
263 - ppr_object_suitability_type suitability;  
264 - TRY(ppr_is_object_suitable_for_recognition(context, object, &suitability))  
265 - if (suitability != PPR_OBJECT_SUITABLE_FOR_RECOGNITION) continue;  
266 - if ((object.confidence > best_confidence) ||  
267 - (best_index == -1)) {  
268 - best_confidence = object.confidence;  
269 - best_index = i;  
270 - }  
271 - }  
272 -  
273 - QList<ppr_object_type> objects;  
274 - if (best_index != -1) objects.append(object_list.objects[best_index]);  
275 - return objects;  
276 - }  
277 -  
278 - QList<ppr_object_type> getAllObjects(ppr_object_list_type object_list) const  
279 - {  
280 - QList<ppr_object_type> objects;  
281 - for (int i=0; i<object_list.num_objects; i++)  
282 - objects.append(object_list.objects[i]);  
283 - return objects;  
284 - }  
285 -};  
286 -  
287 -MM_REGISTER(Feature, PP4Detect, "")  
288 -  
289 -/*!  
290 - * \ingroup transforms  
291 - * \brief Enroll face in PittPatt 4  
292 - * \author Josh Klontz \cite jklontz  
293 - * \warning Needs a maintainer.  
294 - */  
295 -class PP4Enroll : public UntrainableMetaFeature  
296 - , public PP4Context  
297 -{  
298 - Q_OBJECT  
299 -  
300 - void project(const Template &src, Template &dst) const  
301 - {  
302 - if (!src.m().data) {  
303 - dst += cv::Mat();  
304 - return;  
305 - }  
306 -  
307 - ppr_raw_image_type raw_image;  
308 - createRawImage(src, raw_image);  
309 - ppr_image_type image;  
310 - TRY(ppr_create_image(raw_image, &image))  
311 -  
312 - ppr_object_type object = fromMetadata(src.file);  
313 -  
314 - ppr_template_type curr_template;  
315 - TRY(ppr_extract_template_from_object(context, image, object, &curr_template))  
316 -  
317 - freeObject(object);  
318 -  
319 - cv::Mat m;  
320 - createMat(curr_template, m);  
321 - dst += m;  
322 -  
323 - ppr_free_template(curr_template);  
324 - ppr_free_image(image);  
325 - ppr_raw_image_free(raw_image);  
326 - }  
327 -};  
328 -  
329 -MM_REGISTER(Feature, PP4Enroll, "")  
330 -  
331 -  
332 -class PP4Compare : public Comparer,  
333 - public PP4Context  
334 -{  
335 - Q_OBJECT  
336 -  
337 - void compare(const TemplateList &target, const TemplateList &query, Output *output) const  
338 - {  
339 - ppr_gallery_type target_gallery, query_gallery;  
340 - ppr_create_gallery(context, &target_gallery);  
341 - ppr_create_gallery(context, &query_gallery);  
342 - QList<int> target_template_ids, query_template_ids;  
343 - enroll(target, &target_gallery, target_template_ids);  
344 - enroll(query, &query_gallery, query_template_ids);  
345 -  
346 - ppr_similarity_matrix_type similarity_matrix;  
347 - TRY(ppr_compare_galleries(context, query_gallery, target_gallery, &similarity_matrix))  
348 -  
349 - for (int i=0; i<query_template_ids.size(); i++) {  
350 - int query_template_id = query_template_ids[i];  
351 - for (int j=0; j<target_template_ids.size(); j++) {  
352 - int target_template_id = target_template_ids[j];  
353 - float score = -std::numeric_limits<float>::max();  
354 - if ((query_template_id != -1) && (target_template_id != -1)) {  
355 - TRY(ppr_get_similarity_matrix_element(context, similarity_matrix, query_template_id, target_template_id, &score))  
356 - }  
357 - output->setData(score, i, j);  
358 - }  
359 - }  
360 -  
361 - ppr_free_similarity_matrix(similarity_matrix);  
362 - ppr_free_gallery(target_gallery);  
363 - ppr_free_gallery(query_gallery);  
364 - }  
365 -  
366 - void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &template_ids) const  
367 - {  
368 - foreach (const Template &t, templates) {  
369 - if (t.m().data) {  
370 - ppr_template_type u;  
371 - createTemplate(t.m(), &u);  
372 - int template_id;  
373 - TRY(ppr_copy_template_to_gallery(context, gallery, u, &template_id))  
374 - template_ids.append(template_id);  
375 - ppr_free_template(u);  
376 - } else {  
377 - template_ids.append(-1);  
378 - }  
379 - }  
380 - }  
381 -};  
382 -  
383 -MM_REGISTER(Comparer, PP4Compare, "")  
384 -  
385 -#include "plugins/pp4.moc"  
openbr/plugins/regions.cpp
@@ -141,13 +141,15 @@ class CatColsTransform : public UntrainableMetaTransform @@ -141,13 +141,15 @@ class CatColsTransform : public UntrainableMetaTransform
141 141
142 void project(const Template &src, Template &dst) const 142 void project(const Template &src, Template &dst) const
143 { 143 {
  144 + int half = src.size()/2;
  145 + for (int i=0; i<half; i++) {
  146 + Mat first = src[i];
  147 + Mat second = src[half+i];
  148 + Mat both;
  149 + hconcat(first, second, both);
  150 + dst.append(both);
  151 + }
144 dst.file = src.file; 152 dst.file = src.file;
145 - Mat m = OpenCVUtils::toMatByRow(src);  
146 - // right now this just splits src in half and joins them horizontally  
147 - // TODO: add partitions parameter for more than a single split  
148 - Mat first = m.rowRange(Range(0, m.rows/2));  
149 - Mat second = m.rowRange(Range(m.rows/2, m.rows));  
150 - hconcat(first, second, dst);  
151 } 153 }
152 }; 154 };
153 155
openbr/plugins/stasm4.cpp
@@ -54,6 +54,9 @@ class StasmTransform : public UntrainableTransform @@ -54,6 +54,9 @@ class StasmTransform : public UntrainableTransform
54 { 54 {
55 Q_OBJECT 55 Q_OBJECT
56 56
  57 + Q_PROPERTY(bool stasm3Format READ get_stasm3Format WRITE set_stasm3Format RESET reset_stasm3Format STORED false)
  58 + BR_PROPERTY(bool, stasm3Format, false)
  59 +
57 Resource<StasmCascadeClassifier> stasmCascadeResource; 60 Resource<StasmCascadeClassifier> stasmCascadeResource;
58 61
59 void init() 62 void init()
@@ -69,14 +72,20 @@ class StasmTransform : public UntrainableTransform @@ -69,14 +72,20 @@ class StasmTransform : public UntrainableTransform
69 StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire(); 72 StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire();
70 73
71 int foundface; 74 int foundface;
  75 + int nLandmarks = stasm_NLANDMARKS;
72 float landmarks[2 * stasm_NLANDMARKS]; 76 float landmarks[2 * stasm_NLANDMARKS];
73 stasm_search_single(&foundface, landmarks, reinterpret_cast<const char*>(src.m().data), src.m().cols, src.m().rows, *stasmCascade, NULL, NULL); 77 stasm_search_single(&foundface, landmarks, reinterpret_cast<const char*>(src.m().data), src.m().cols, src.m().rows, *stasmCascade, NULL, NULL);
74 78
  79 + if (stasm3Format) {
  80 + nLandmarks = 76;
  81 + stasm_convert_shape(landmarks, nLandmarks);
  82 + }
  83 +
75 stasmCascadeResource.release(stasmCascade); 84 stasmCascadeResource.release(stasmCascade);
76 85
77 if (!foundface) qWarning("No face found in %s", qPrintable(src.file.fileName())); 86 if (!foundface) qWarning("No face found in %s", qPrintable(src.file.fileName()));
78 else { 87 else {
79 - for (int i = 0; i < stasm_NLANDMARKS; i++) 88 + for (int i = 0; i < nLandmarks; i++)
80 dst.file.appendPoint(QPointF(landmarks[2 * i], landmarks[2 * i + 1])); 89 dst.file.appendPoint(QPointF(landmarks[2 * i], landmarks[2 * i + 1]));
81 } 90 }
82 91
openbr/plugins/stream.cpp
@@ -364,6 +364,7 @@ protected: @@ -364,6 +364,7 @@ protected:
364 QMutex last_frame_update; 364 QMutex last_frame_update;
365 }; 365 };
366 366
  367 +static QMutex openLock;
367 // Read a video frame by frame using cv::VideoCapture 368 // Read a video frame by frame using cv::VideoCapture
368 class VideoDataSource : public DataSource 369 class VideoDataSource : public DataSource
369 { 370 {
@@ -396,6 +397,8 @@ public: @@ -396,6 +397,8 @@ public:
396 // Yes, we should specify absolute path: 397 // Yes, we should specify absolute path:
397 // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python 398 // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
398 QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name; 399 QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name;
  400 + // On windows, this appears to not be thread-safe
  401 + QMutexLocker lock(&openLock);
399 video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); 402 video.open(QFileInfo(fileName).absoluteFilePath().toStdString());
400 } 403 }
401 404
@@ -707,8 +710,7 @@ public: @@ -707,8 +710,7 @@ public:
707 if (input == NULL) { 710 if (input == NULL) {
708 qFatal("null input to multi-thread stage"); 711 qFatal("null input to multi-thread stage");
709 } 712 }
710 - // Project the input we got  
711 - transform->projectUpdate(input->data); 713 + input->data >> *transform;
712 714
713 should_continue = nextStage->tryAcquireNextStage(input); 715 should_continue = nextStage->tryAcquireNextStage(input);
714 716
@@ -1058,7 +1060,10 @@ public: @@ -1058,7 +1060,10 @@ public:
1058 dst = src; 1060 dst = src;
1059 1061
1060 bool res = readStage->dataSource.open(dst); 1062 bool res = readStage->dataSource.open(dst);
1061 - if (!res) return; 1063 + if (!res) {
  1064 + qDebug("stream failed to open %s", qPrintable(dst[0].file.name));
  1065 + return;
  1066 + }
1062 1067
1063 // Start the first thread in the stream. 1068 // Start the first thread in the stream.
1064 QWriteLocker lock(&readStage->statusLock); 1069 QWriteLocker lock(&readStage->statusLock);
@@ -1300,6 +1305,7 @@ public: @@ -1300,6 +1305,7 @@ public:
1300 { 1305 {
1301 if (!transform) 1306 if (!transform)
1302 return; 1307 return;
  1308 +
1303 trainable = transform->trainable; 1309 trainable = transform->trainable;
1304 1310
1305 basis.setParent(this->parent()); 1311 basis.setParent(this->parent());
openbr/plugins/topsurf.cmake deleted
1 -set(BR_WITH_TOPSURF OFF CACHE BOOL "Build with TOP-SURF")  
2 -  
3 -if(${BR_WITH_TOPSURF})  
4 - find_package(TopSurf REQUIRED)  
5 - set(THIRDPARTY_SRC ${THIRDPARTY_SRC} plugins/topsurf.cpp ${TOPSURF_SRC} ${TOPSURF_FLANN_SRC})  
6 - install(DIRECTORY ${TOPSURF_DIR}/dictionary_10000  
7 - ${TOPSURF_DIR}/dictionary_20000  
8 - ${TOPSURF_DIR}/dictionary_40000  
9 - DESTINATION models/topsurf)  
10 -endif()  
openbr/plugins/topsurf.cpp deleted
1 -#include <topsurf/descriptor.h>  
2 -#include <topsurf/topsurf.h>  
3 -#include <mm_plugin.h>  
4 -  
5 -#include "common/opencvutils.h"  
6 -#include "common/qtutils.h"  
7 -#include "common/resource.h"  
8 -  
9 -using namespace cv;  
10 -using namespace mm;  
11 -using namespace std;  
12 -  
13 -class TopSurfInitializer : public Initializer  
14 -{  
15 - void initialize() const  
16 - {  
17 - Globals.Abbreviations.insert("TopSurf", "Open!TopSurfExtract(40000):TopSurfCompare");  
18 - Globals.Abbreviations.insert("TopSurfM", "Open!TopSurfExtract(1000000):TopSurfCompare");  
19 - Globals.Abbreviations.insert("TopSurfKNN", "Open!TopSurfExtract+TopSurfKNN");  
20 - Globals.Abbreviations.insert("DocumentClassification", "TopSurfKNN");  
21 - }  
22 -  
23 - void finalize() const {}  
24 -};  
25 -  
26 -MM_REGISTER(Initializer, TopSurfInitializer, false)  
27 -  
28 -  
29 -class TopSurfResourceMaker : public ResourceMaker<TopSurf>  
30 -{  
31 - QString file;  
32 -  
33 -public:  
34 - TopSurfResourceMaker(const QString &dictionary)  
35 - {  
36 - file = Globals.SDKPath + "/models/topsurf/dictionary_" + dictionary;  
37 - }  
38 -  
39 -private:  
40 - TopSurf *make() const  
41 - {  
42 - TopSurf *topSurf = new TopSurf(256, 100);  
43 - if (!topSurf->LoadDictionary(qPrintable(file)))  
44 - qFatal("TopSurfResourceMaker::make failed to load dictionary.");  
45 - return topSurf;  
46 - }  
47 -};  
48 -  
49 -  
50 -/****  
51 -TopSurfExtract  
52 - Wrapper to TopSurf::ExtractDescriptor()  
53 - B. Thomee, E.M. Bakker, and M.S. Lew, "TOP-SURF: a visual words toolkit",  
54 - in Proceedings of the 18th ACM International Conference on Multimedia, pp. 1473-1476, Firenze, Italy, 2010.  
55 -****/  
56 -class TopSurfExtract : public UntrainableFeature  
57 -{  
58 - Q_OBJECT  
59 - Q_PROPERTY(QString dictionary READ get_dictionary WRITE set_dictionary)  
60 - MM_MEMBER(QString, dictionary)  
61 -  
62 - Resource<TopSurf> topSurfResource;  
63 -  
64 -public:  
65 - TopSurfExtract() : topSurfResource(new TopSurfResourceMaker("10000")) {}  
66 -  
67 -private:  
68 - void init()  
69 - {  
70 - topSurfResource.setResourceMaker(new TopSurfResourceMaker(dictionary));  
71 - }  
72 -  
73 - void project(const Template &src, Template &dst) const  
74 - {  
75 - // Compute descriptor (not thread safe)  
76 - TopSurf *topSurf = topSurfResource.acquire();  
77 - TOPSURF_DESCRIPTOR descriptor;  
78 - IplImage iplSrc = src.m();  
79 - if (!topSurf->ExtractDescriptor(iplSrc, descriptor))  
80 - qFatal("TopSurfExtract::project ExtractDescriptor failure.");  
81 - topSurfResource.release(topSurf);  
82 -  
83 - // Copy descriptor and clean up  
84 - unsigned char *data;  
85 - int length;  
86 - Descriptor2Array(descriptor, data, length);  
87 - Mat m(1, length, CV_8UC1);  
88 - memcpy(m.data, data, length);  
89 - delete data;  
90 - TopSurf::ReleaseDescriptor(descriptor);  
91 - dst = m;  
92 - }  
93 -  
94 -public:  
95 - static QString args()  
96 - {  
97 - return "10000|20000|40000 dictionary = 10000";  
98 - }  
99 -  
100 - static TopSurfExtract *make(const QStringList &args)  
101 - {  
102 - (void) args;  
103 - return new TopSurfExtract();  
104 - }  
105 -};  
106 -  
107 -MM_REGISTER(Feature, TopSurfExtract, true)  
108 -  
109 -  
110 -class TopSurfHist : public UntrainableFeature  
111 -{  
112 - Q_OBJECT  
113 - Q_PROPERTY(int size READ get_size WRITE set_size)  
114 - MM_MEMBER(int, size)  
115 -  
116 - void project(const Template &src, Template &dst) const  
117 - {  
118 - TOPSURF_DESCRIPTOR td;  
119 - Array2Descriptor(src.m().data, td);  
120 -  
121 - Mat m(1, size, CV_32FC1);  
122 - m.setTo(0);  
123 - for (int i=0; i<td.count; i++)  
124 - m.at<float>(0, td.visualword[i].identifier % size)++;  
125 -  
126 - TopSurf::ReleaseDescriptor(td);  
127 - dst = m;  
128 - }  
129 -  
130 -public:  
131 - static QString args()  
132 - {  
133 - return "int size = 10000";  
134 - }  
135 -  
136 - static TopSurfHist *make(const QStringList &args)  
137 - {  
138 - (void) args;  
139 - return new TopSurfHist();  
140 - }  
141 -};  
142 -  
143 -MM_REGISTER(Feature, TopSurfHist, true)  
144 -  
145 -  
146 -// Wrapper around TopSurf CompareDescriptors  
147 -float TopSurfSimilarity(const Mat &a, const Mat &b, bool cosine)  
148 -{  
149 - TOPSURF_DESCRIPTOR tda, tdb;  
150 - Array2Descriptor(a.data, tda);  
151 - Array2Descriptor(b.data, tdb);  
152 -  
153 - float result;  
154 - if (cosine) result = TopSurf::CompareDescriptorsCosine(tda, tdb);  
155 - else result = TopSurf::CompareDescriptorsAbsolute(tda, tdb);  
156 -  
157 - TopSurf::ReleaseDescriptor(tda);  
158 - TopSurf::ReleaseDescriptor(tdb);  
159 - return result;  
160 -}  
161 -  
162 -  
163 -/****  
164 -TopSurfCompare  
165 - Wrapper to TopSurf_CompareDescriptors()  
166 - B. Thomee, E.M. Bakker, and M.S. Lew, "TOP-SURF: a visual words toolkit",  
167 - in Proceedings of the 18th ACM International Conference on Multimedia, pp. 1473-1476, Firenze, Italy, 2010.  
168 -****/  
169 -class TopSurfCompare : public ComparerBase  
170 -{  
171 - Q_OBJECT  
172 - Q_PROPERTY(bool cosine READ get_cosine WRITE set_cosine)  
173 - MM_MEMBER(bool, cosine)  
174 -  
175 - float compare(const Mat &a, const Mat &b) const  
176 - {  
177 - return TopSurfSimilarity(a, b, cosine);  
178 - }  
179 -  
180 -public:  
181 - static QString args()  
182 - {  
183 - return "bool cosine = 1";  
184 - }  
185 -  
186 - static TopSurfCompare *make(const QStringList &args)  
187 - {  
188 - (void) args;  
189 - return new TopSurfCompare();  
190 - }  
191 -};  
192 -  
193 -MM_REGISTER(Comparer, TopSurfCompare, true)  
194 -  
195 -  
196 -/****  
197 -TopSurfKNN  
198 - KNN classifier for TopSurf features.  
199 -****/  
200 -class TopSurfKNN : public Feature  
201 -{  
202 - Q_OBJECT  
203 - Q_PROPERTY(int k READ get_k WRITE set_k)  
204 - Q_PROPERTY(bool cosine READ get_cosine WRITE set_cosine)  
205 - MM_MEMBER(int, k)  
206 - MM_MEMBER(bool, cosine)  
207 -  
208 - TemplateList data;  
209 -  
210 -private:  
211 - void train(const TemplateList &data)  
212 - {  
213 - this->data = data;  
214 - }  
215 -  
216 - void project(const Template &src, Template &dst) const  
217 - {  
218 - // Compute distance to each descriptor  
219 - QList< QPair<float, int> > distances; // <distance, label>  
220 - distances.reserve(data.size());  
221 - foreach (const Template &t, data)  
222 - distances.append(QPair<float, int>(TopSurfSimilarity(src, t, cosine), t.file.label()));  
223 -  
224 - // Find nearest neighbors  
225 - qSort(distances);  
226 - QHash<int, QPair<int, float> > counts; // <label, <count, cumulative distance>>  
227 - for (int i=0; i<k; i++) {  
228 - QPair<float,int> &distance = distances[i];  
229 - QPair<int,float> &count = counts[distance.second];  
230 - count.first++;  
231 - count.second += distance.first;  
232 - }  
233 -  
234 - // Find most occuring label  
235 - int best_label = -1;  
236 - int best_count = 0;  
237 - float best_distance = numeric_limits<float>::max();  
238 - foreach (int label, counts.keys()) {  
239 - const QPair<int, float> &count = counts[label];  
240 - if ((count.first > best_count) || ((count.first == best_count) && (count.second < best_distance))) {  
241 - best_label = label;  
242 - best_count = count.first;  
243 - best_distance = count.second;  
244 - }  
245 - }  
246 - assert(best_label != -1);  
247 -  
248 - // Measure confidence  
249 - int rest_count = 0;  
250 - float rest_distance = 0;  
251 - foreach (int label, counts.keys()) {  
252 - if (label != best_label) {  
253 - const QPair<int, float> &count = counts[label];  
254 - rest_count = count.first;  
255 - rest_distance = count.second;  
256 - }  
257 - }  
258 -  
259 - dst = src;  
260 - dst.file["Label"] = best_label;  
261 - dst.file["Confidence"] = (float)best_count/(float)k;  
262 - }  
263 -  
264 - void store(QDataStream &stream) const  
265 - {  
266 - stream << data;  
267 - }  
268 -  
269 - void load(QDataStream &stream)  
270 - {  
271 - stream >> data;  
272 - }  
273 -  
274 -public:  
275 - static QString args()  
276 - {  
277 - return "int k, int cosine = 1";  
278 - }  
279 -  
280 - static TopSurfKNN *make(const QStringList &args)  
281 - {  
282 - (void) args;  
283 - return new TopSurfKNN();  
284 - }  
285 -};  
286 -  
287 -MM_REGISTER(Feature, TopSurfKNN, true)  
288 -  
289 -#include "topsurf.moc"  
openbr/plugins/validate.cpp
@@ -19,9 +19,9 @@ class CrossValidateTransform : public MetaTransform @@ -19,9 +19,9 @@ class CrossValidateTransform : public MetaTransform
19 { 19 {
20 Q_OBJECT 20 Q_OBJECT
21 Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) 21 Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
22 - Q_PROPERTY(bool leaveOneOut READ get_leaveOneOut WRITE set_leaveOneOut RESET reset_leaveOneOut STORED false) 22 + Q_PROPERTY(bool leaveOneImageOut READ get_leaveOneImageOut WRITE set_leaveOneImageOut RESET reset_leaveOneImageOut STORED false)
23 BR_PROPERTY(QString, description, "Identity") 23 BR_PROPERTY(QString, description, "Identity")
24 - BR_PROPERTY(bool, leaveOneOut, false) 24 + BR_PROPERTY(bool, leaveOneImageOut, false)
25 25
26 QList<br::Transform*> transforms; 26 QList<br::Transform*> transforms;
27 27
@@ -49,10 +49,10 @@ class CrossValidateTransform : public MetaTransform @@ -49,10 +49,10 @@ class CrossValidateTransform : public MetaTransform
49 int j = partitionedData.size()-1; 49 int j = partitionedData.size()-1;
50 while (j>=0) { 50 while (j>=0) {
51 // Remove all templates belonging to partition i 51 // Remove all templates belonging to partition i
52 - // if leaveOneOut is true, 52 + // if leaveOneImageOut is true,
53 // and i is greater than the number of images for a particular subject 53 // and i is greater than the number of images for a particular subject
54 // even if the partitions are different 54 // even if the partitions are different
55 - if (leaveOneOut) { 55 + if (leaveOneImageOut) {
56 const QString label = partitionedData.at(j).file.get<QString>("Label"); 56 const QString label = partitionedData.at(j).file.get<QString>("Label");
57 QList<int> subjectIndices = partitionedData.find("Label",label); 57 QList<int> subjectIndices = partitionedData.find("Label",label);
58 QList<int> removed; 58 QList<int> removed;
@@ -80,6 +80,7 @@ class CrossValidateTransform : public MetaTransform @@ -80,6 +80,7 @@ class CrossValidateTransform : public MetaTransform
80 } 80 }
81 } else if (partitions[j] == i) { 81 } else if (partitions[j] == i) {
82 partitionedData.removeAt(j); 82 partitionedData.removeAt(j);
  83 + j--;
83 } else j--; 84 } else j--;
84 } 85 }
85 // Train on the remaining templates 86 // Train on the remaining templates
openbr/plugins/yubico.cmake deleted
1 -set(BR_WITH_YUBICO OFF CACHE BOOL "Build YubiKey authentication")  
2 -  
3 -if(${BR_WITH_YUBICO})  
4 - find_package(YubiKey REQUIRED) # For decrypting YubiKeys  
5 - find_package(YKPers REQUIRED) # For reading YubiKeys  
6 -  
7 - install(FILES ${YUBIKEY_LICENSE} RENAME YubiKey DESTINATION share/openbr/licenses)  
8 - install(FILES ${YKPERS_LICENSE} RENAME YKPers DESTINATION share/openbr/licenses)  
9 - install(FILES ${YKPERS_RULES} DESTINATION share/openbr)  
10 -  
11 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${YUBIKEY_SRC} ${YKPERS_SRC} plugins/yubico.cpp)  
12 - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${YKPERS_LIBS})  
13 -endif()  
openbr/plugins/yubico.cpp deleted
1 -#include <mm_plugin.h>  
2 -#include <yubikey.h>  
3 -#include <ykdef.h>  
4 -#include <ykpers.h>  
5 -#include <stdlib.h>  
6 -#include <time.h>  
7 -  
8 -/****  
9 -YubiKey Challenge-Response Authentication  
10 -  
11 -To configure YubiKeys for mm usage:  
12 -1) Download the cross platform personalization tool from http://yubico.com/personalization-tool.  
13 -2) Insert YubiKey and launch the personalization tool (may require sudo access).  
14 -3) Click "Challenge-Response Mode".  
15 -4) Click "Yubico OTP".  
16 -5) Select "Configuration Slot 2"  
17 -6) In the Private Identity text box enter "21 92 78 11 55 8a".  
18 -7) In the Secret Key text box enter "e7 32 df 49 f3 87 e6 89 04 d2 03 6a 59 ad b7 2f".  
19 -8) Click "Write Configuration".  
20 -9) Done!  
21 -  
22 -Unix implementation derived from "ykchalresp.c" in ykpers repository.  
23 -Windows implementation derived from "MFCTestDlg.cpp" in Yubikey Client API installer.  
24 -  
25 -!!! Attention Linux Users !!!  
26 -cp trunk/3rdparty/ykpers-1.6.3/70-yubikey.rules /etc/udev/rules.d  
27 -  
28 -!!! Attention Windows Users !!!  
29 -Install Yubikey Client API.  
30 -****/  
31 -  
32 -using namespace mm;  
33 -  
34 -static int challenge_response(YK_KEY *yk, int slot,  
35 - unsigned char *challenge, unsigned int len,  
36 - bool hmac, bool may_block, bool verbose, unsigned char output_buf[(SHA1_MAX_BLOCK_SIZE * 2) + 1])  
37 -{  
38 - unsigned char response[64];  
39 - int yk_cmd;  
40 - unsigned int flags = 0;  
41 - unsigned int response_len = 0;  
42 - unsigned int expect_bytes = 0;  
43 -  
44 - memset(response, 0, sizeof(response));  
45 -  
46 - if (may_block)  
47 - flags |= YK_FLAG_MAYBLOCK;  
48 -  
49 - if (verbose) {  
50 - fprintf(stderr, "Sending %i bytes %s challenge to slot %i\n", len, (hmac == true) ? "HMAC" : "Yubico", slot);  
51 - //_yk_hexdump(challenge, len);  
52 - }  
53 -  
54 - switch(slot) {  
55 - case 1:  
56 - yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC1 : SLOT_CHAL_OTP1;  
57 - break;  
58 - case 2:  
59 - yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC2 : SLOT_CHAL_OTP2;  
60 - break;  
61 - }  
62 -  
63 - if (!yk_write_to_key(yk, yk_cmd, challenge, len))  
64 - return 0;  
65 -  
66 - if (verbose) {  
67 - fprintf(stderr, "Reading response...\n");  
68 - }  
69 -  
70 - /* HMAC responses are 160 bits, Yubico 128 */  
71 - expect_bytes = (hmac == true) ? 20 : 16;  
72 -  
73 - if (! yk_read_response_from_key(yk, slot, flags,  
74 - &response, sizeof(response),  
75 - expect_bytes,  
76 - &response_len))  
77 - return 0;  
78 -  
79 - if (hmac && response_len > 20)  
80 - response_len = 20;  
81 - if (! hmac && response_len > 16)  
82 - response_len = 16;  
83 -  
84 - memset(output_buf, 0, SHA1_MAX_BLOCK_SIZE * 2 + 1);  
85 - if (hmac) {  
86 - yubikey_hex_encode((char *)output_buf, (char *)response, response_len);  
87 - } else {  
88 - yubikey_modhex_encode((char *)output_buf, (char *)response, response_len);  
89 - }  
90 - // printf("%s\n", output_buf);  
91 -  
92 - return 1;  
93 -}  
94 -  
95 -/*!  
96 - * \ingroup initializers  
97 - * \brief Initialize yubikey  
98 - * \author Josh Klontz \cite jklontz  
99 - */  
100 -class YubiKey : public Initializer  
101 -{  
102 - Q_OBJECT  
103 -  
104 - void initialize() const  
105 - {  
106 - // Read from device  
107 - YK_KEY *yk = 0;  
108 -  
109 - if (!yk_init())  
110 - qFatal("YubiKey::initialize yk_init failure.");  
111 -  
112 - if (!(yk = yk_open_first_key()))  
113 - qFatal("Could not connect to license.");  
114 -  
115 - // Challenge value is arbitrary  
116 - srand(time(NULL));  
117 - uint8_t challenge[6] = {rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255};  
118 - unsigned char output_buf[(SHA1_MAX_BLOCK_SIZE * 2) + 1];  
119 - if (!challenge_response(yk, 2, challenge, 6, false, true, false, output_buf))  
120 - qFatal("YubiKey::initialize challenge_response failure.");  
121 -  
122 - if (yk && !yk_close_key(yk))  
123 - qFatal("YubiKey::initialize yk_close_key failure.");  
124 -  
125 - if (!yk_release())  
126 - qFatal("YubiKey::initialize yk_release failure.");  
127 -  
128 - // Check response  
129 - // Our Secret Key! Shhh...  
130 - const uint8_t key[YUBIKEY_KEY_SIZE] = {0xe7, 0x32, 0xdf, 0x49, 0xf3, 0x87, 0xe6, 0x89, 0x04, 0xd2, 0x03, 0x6a, 0x59, 0xad, 0xb7, 0x2f};  
131 - yubikey_token_st out;  
132 - yubikey_parse(output_buf, key, &out);  
133 -  
134 - // Our Private Identity! Shhh...  
135 - uint8_t uid[YUBIKEY_UID_SIZE] = {0x21, 0x92, 0x78, 0x11, 0x55, 0x8a};  
136 - if ((uid[0] != (out.uid[0] ^ challenge[0])) ||  
137 - (uid[1] != (out.uid[1] ^ challenge[1])) ||  
138 - (uid[2] != (out.uid[2] ^ challenge[2])) ||  
139 - (uid[3] != (out.uid[3] ^ challenge[3])) ||  
140 - (uid[4] != (out.uid[4] ^ challenge[4])) ||  
141 - (uid[5] != (out.uid[5] ^ challenge[5])))  
142 - qFatal("Invalid license.");  
143 - }  
144 -  
145 - void finalize() const  
146 - {  
147 - // Nothing to do  
148 - }  
149 -};  
150 -  
151 -MM_REGISTER(Initializer,YubiKey,"")  
152 -  
153 -#include "yubico.moc"  
share/openbr/cmake/FindCT8.cmake deleted
1 -# ================================================================  
2 -# The CT8 CMake configuration file  
3 -#  
4 -# Usage from an external project:  
5 -# In your CMakeLists.txt, add these lines:  
6 -#  
7 -# find_package(CT8 REQUIRED)  
8 -# target_link_libraries(MY_TARGET ${CT8_LIBS})  
9 -# ================================================================  
10 -  
11 -set(CT8_DIR "CT8_DIR-NOTFOUND" CACHE PATH "Cognitec FaceVACS 8.x directory")  
12 -  
13 -  
14 -if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")  
15 - set(ARCH_STRING x86_64)  
16 -else("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")  
17 - set(ARCH_STRING x86_32)  
18 -endif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")  
19 -  
20 -if(DEFINED MSVC80)  
21 - set(COMP_DIR_EXT "msc_8.0-ipp_crtdll")  
22 -elseif(DEFINED MSVC90)  
23 - set(COMP_DIR_EXT "msc_9.0-ipp_crtdll")  
24 -elseif(DEFINED MSVC10)  
25 - set(COMP_DIR_EXT "msc_10.0-ipp_crtdll")  
26 -elseif(CMAKE_HOST_APPLE)  
27 - set(COMP_DIR_EXT "gcc-4.2-ipp")  
28 -else()  
29 - set(COMP_DIR_EXT "gcc-4.3-ipp")  
30 -endif()  
31 -  
32 -set(CT8_DIR_LIB ${CT8_DIR}/lib/${ARCH_STRING}/${COMP_DIR_EXT} )  
33 -set(CT8_LIBRARY_RELEASE libfrsdk-8.6.0)  
34 -set(CT8_LIBRARY_DEBUG libfrsdk-8.6.0d)  
35 -  
36 -include_directories(${CT8_DIR}/include)  
37 -link_directories(${CT8_DIR_LIB} ${CT8_DIR_LIB}_g)  
share/openbr/cmake/FindFST3.cmake deleted
1 -find_path(FST3_DIR _src_criteria/classifier.hpp ${CMAKE_SOURCE_DIR}/3rdparty/*)  
2 -mark_as_advanced(FST3_DIR)  
3 -include_directories(${FST3_DIR}/_src_criteria ${FST3_DIR}/_src_dataio ${FST3_DIR}/_src_global ${FST3_DIR}/_src_search)  
4 -set(FST3_SRC ${FST3_DIR}/_src_global/global.cpp)  
share/openbr/cmake/FindPP4.cmake deleted
1 -# ================================================================  
2 -# The PP4 CMake configuration file  
3 -#  
4 -# Usage from an external project:  
5 -# In your CMakeLists.txt, add these lines:  
6 -#  
7 -# find_package(PP4 REQUIRED)  
8 -# target_link_libraries(MY_TARGET ${PP4_LIBS})  
9 -# ================================================================  
10 -  
11 -find_path(PP4_DIR include/pittpatt_nc_sdk.h ${CMAKE_SOURCE_DIR}/3rdparty/*)  
12 -include_directories(${PP4_DIR}/include)  
13 -link_directories(${PP4_DIR}/lib)  
14 -set(PP4_LIBS pittpatt_nc_sdk  
15 - pittpatt_raw_image  
16 - pittpatt_raw_image_io  
17 - pittpatt_recognition_core  
18 - pittpatt_video_io)  
share/openbr/cmake/FindTopSurf.cmake deleted
1 -find_path(TOPSURF_DIR topsurf/topsurf.h ${CMAKE_SOURCE_DIR}/3rdparty/*)  
2 -mark_as_advanced(TOPSURF_DIR)  
3 -include_directories(${TOPSURF_DIR})  
4 -aux_source_directory(${TOPSURF_DIR}/topsurf TOPSURF_SRC)  
5 -aux_source_directory(${TOPSURF_DIR}/topsurf/flann TOPSURF_FLANN_SRC)  
share/openbr/cmake/FindYubiKey.cmake deleted
1 -find_path(YUBIKEY_DIR yubikey.h ${CMAKE_SOURCE_DIR}/3rdparty/*)  
2 -mark_as_advanced(YUBIKEY_DIR)  
3 -include_directories(${YUBIKEY_DIR})  
4 -if(MSVC)  
5 - include_directories(${YUBIKEY_DIR}/stdbool)  
6 -endif()  
7 -  
8 -if(NOT TARGET yubikey)  
9 - set(YUBIKEY_SRC ${YUBIKEY_DIR}/ykaes.c ${YUBIKEY_DIR}/ykcrc.c ${YUBIKEY_DIR}/ykhex.c ${YUBIKEY_DIR}/ykmodhex.c ${YUBIKEY_DIR}/yktoken.c)  
10 - if(WIN32)  
11 - set_source_files_properties(${YUBIKEY_SRC} PROPERTIES LANGUAGE CXX)  
12 - endif()  
13 -endif()  
14 -  
15 -set(YUBIKEY_LICENSE ${YUBIKEY_DIR}/COPYING)  
share/openbr/cmake/FindpHash.cmake deleted
1 -find_path(PHASH_DIR src/pHash.h ${CMAKE_SOURCE_DIR}/3rdparty/*)  
2 -mark_as_advanced(PHASH_DIR)  
3 -include_directories(${PHASH_DIR} ${PHASH_DIR}/src)  
4 -set(PHASH_SRC ${PHASH_DIR}/src/pHash.cpp ${PHASH_DIR}/src/ph_fft.c)  
1 -Subproject commit dccddf4dd3a5239911807beeec39308f8890b1e4 1 +Subproject commit a73d51013ea05f263e88a28539393159fff2183e