Commit d0f1b236473da269610f25b7a9ecc6ff754c6754

Authored by Charles Otto
2 parents 9670e296 ead4a56a

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

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"
data/FDDB/README.md 0 → 100644
  1 +## FDDB Face Detection Data Set and Benchmark
  2 +Unconstrained face detection dataset containing 2845 images with 5171 annotated face locations. Contained in this directory are .FDDB files for train and test splits for FDDB. These are based on the `FDDB-folds` directory that comes with the original dataset, but organized as 10 different train/test splits instead of 10 folds. All splits are based on the original folds.
  3 +
  4 +Image data currently available online.
  5 +* [Website](http://vis-www.cs.umass.edu/fddb/)
data/README.md
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 * [MNIST](MNIST/README.md) 10 * [MNIST](MNIST/README.md)
11 * [PCSO](PCSO/README.md) 11 * [PCSO](PCSO/README.md)
12 * [KTH](KTH/README.md) 12 * [KTH](KTH/README.md)
  13 +* [FDDB](FDDB/README.md)
13 14
14 For both practical and legal reasons we only include images for some of the datasets in this repository. 15 For both practical and legal reasons we only include images for some of the datasets in this repository.
15 Researchers should contact the respective owners of the other datasets in order to obtain a copy. 16 Researchers should contact the respective owners of the other datasets in order to obtain a copy.
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/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"
@@ -13,6 +18,109 @@ using namespace cv; @@ -13,6 +18,109 @@ using namespace cv;
13 18
14 namespace br 19 namespace br
15 { 20 {
  21 +// Generally speaking, Qt wants GUI objects to be on the main thread, and
  22 +// for the main thread to be in an event loop. We don't restrict transform
  23 +// creation to just the main thread, but in br we do compromise and put
  24 +// the main thread in an event loop (and so should any applications wanting to
  25 +// use GUI transforms). This does mean we need a way to make our QWidget subclasses
  26 +// on the main thread. We can't create them from an arbitrary thread, then move them
  27 +// (you know, since that would be crazy), so we need some tricks to get the main
  28 +// thread to make these objects.
  29 +
  30 +// Part 1. A generic interface for creating objects, the type of object
  31 +// created is not exposed in the interface.
  32 +class NominalCreation
  33 +{
  34 +public:
  35 + virtual ~NominalCreation() {}
  36 + virtual void creation()=0;
  37 +};
  38 +
  39 +// Part 2. A template class that creates an object of the specified type
  40 +// through the interface defined in part 1. The point of this is that the
  41 +// type of object created can be hidden by using a NominalCreation *.
  42 +template<typename T>
  43 +class ActualCreation : public NominalCreation
  44 +{
  45 +public:
  46 + T * basis;
  47 +
  48 + void creation()
  49 + {
  50 + basis = new T();
  51 + }
  52 +};
  53 +
  54 +// Part 3. A class that inherits from QObject, but not QWidget. This means
  55 +// we are free to move it to the main thread.
  56 +// If this object is on the main thread, and we signal one of its slots, then
  57 +// the slot will be executed by the main thread, which is what we need.
  58 +// Unfortunately, since it uses Q_OBJECT we cannot make it a template class, but
  59 +// we still want to be able to make objects of arbitrary type on the main thread,
  60 +// so that we don't need a different adaptor for every type of QWidget subclass we use.
  61 +class MainThreadCreator : public QObject
  62 +{
  63 + Q_OBJECT
  64 +public:
  65 +
  66 + MainThreadCreator()
  67 + {
  68 + this->moveToThread(QApplication::instance()->thread());
  69 + // We actually bind a signal on this object to one of its own slots.
  70 + // the signal will be emitted by a call to getItem from an abitrary
  71 + // thread.
  72 + connect(this, SIGNAL(needCreation()), this, SLOT(createThing()), Qt::BlockingQueuedConnection);
  73 + }
  74 +
  75 + // While this cannot be a template class, it can still have a template
  76 + // method. Which is useful, but the slot which will actually be executed
  77 + // by the main thread cannot be a template. So, we use the template method
  78 + // here (called from an arbitrary thread, to create an object of arbitrary type)
  79 + // to instantiate an ActualCreation object with matching type, then we hide
  80 + // the template with the NominalCreation interface, and call worker->creation
  81 + // in the slot.
  82 + template<typename T>
  83 + T * getItem()
  84 + {
  85 + // If this is called by the main thread, we can just create the object
  86 + // it's important to check, otherwise we will have problems trying to
  87 + // wait for a blocking connection that is supposed to be processed by
  88 + // the thread that is waiting.
  89 + if (QThread::currentThread() == QApplication::instance()->thread())
  90 + return new T();
  91 +
  92 + // Create the object creation interface
  93 + ActualCreation<T> * actualWorker;
  94 + actualWorker = new ActualCreation<T> ();
  95 + // hide it
  96 + worker = actualWorker;
  97 +
  98 + // emit the signal, we set up a blocking queued connection, so
  99 + // this is a blocking wait for the slot to finish being run.
  100 + emit needCreation();
  101 +
  102 + // collect the results, and return.
  103 + T * output = actualWorker->basis;
  104 + delete actualWorker;
  105 + return output;
  106 + }
  107 +
  108 + NominalCreation * worker;
  109 +
  110 +signals:
  111 + void needCreation();
  112 +
  113 +public slots:
  114 + // The actual slot, to be run by the main thread. The type
  115 + // of object being created is not, and indeed cannot, be exposed here
  116 + // since this cannot be a template method, and the class cannot be a
  117 + // template class.
  118 + void createThing()
  119 + {
  120 + worker->creation();
  121 + }
  122 +};
  123 +
16 QImage toQImage(const Mat &mat) 124 QImage toQImage(const Mat &mat)
17 { 125 {
18 // Convert to 8U depth 126 // Convert to 8U depth
@@ -65,6 +173,7 @@ public: @@ -65,6 +173,7 @@ public:
65 173
66 DisplayWindow(QWidget * parent = NULL) : QLabel(parent) 174 DisplayWindow(QWidget * parent = NULL) : QLabel(parent)
67 { 175 {
  176 + setFixedSize(200,200);
68 QApplication::instance()->installEventFilter(this); 177 QApplication::instance()->installEventFilter(this);
69 } 178 }
70 179
@@ -75,7 +184,13 @@ public slots: @@ -75,7 +184,13 @@ public slots:
75 184
76 show(); 185 show();
77 setPixmap(pixmap); 186 setPixmap(pixmap);
78 - setFixedSize(input.size()); 187 +
  188 + // We appear to get a warning on windows if we set window width < 104. This is of course not
  189 + // reflected in the Qt min size settings, and I don't know how to query it.
  190 + QSize temp = input.size();
  191 + if (temp.width() < 104)
  192 + temp.setWidth(104);
  193 + setFixedSize(temp);
79 } 194 }
80 195
81 196
@@ -188,74 +303,84 @@ private: @@ -188,74 +303,84 @@ private:
188 303
189 }; 304 };
190 305
191 -  
192 -// I want a template class that doesn't look like a template class  
193 -class NominalCreation 306 +class DisplayGUI : public QMainWindow
194 { 307 {
195 -public:  
196 - virtual ~NominalCreation() {}  
197 - virtual void creation()=0;  
198 -}; 308 + Q_OBJECT
199 309
200 -// Putting the template on a subclass means we can maintain a pointer that  
201 -// doesn't include T in its type.  
202 -template<typename T>  
203 -class ActualCreation : public NominalCreation  
204 -{  
205 public: 310 public:
206 - T * basis;  
207 311
208 - void creation() 312 + DisplayGUI(QWidget * parent = NULL) : QMainWindow(parent)
209 { 313 {
210 - basis = new T();  
211 - }  
212 -}; 314 + centralWidget = new QWidget();
  315 + layout = new QHBoxLayout();
  316 + inputLayout = new QVBoxLayout();
213 317
214 -// We want to create a QLabel subclass on the main thread, but are running in another thread.  
215 -// We cannot move QWidget subclasses to a different thread (obviously that would be crazy), but  
216 -// we can create one of these, and move it to the main thread, and then use it to create the object  
217 -// we want.  
218 -// Additional fact: QObject subclasses cannot be template classes.  
219 -class MainThreadCreator : public QObject  
220 -{  
221 - Q_OBJECT  
222 -public: 318 + button.setText("Set Template Metadata");
223 319
224 - MainThreadCreator()  
225 - {  
226 - this->moveToThread(QApplication::instance()->thread()); 320 + layout->addWidget(&label);
227 321
228 - connect(this, SIGNAL(needCreation()), this, SLOT(createThing()), Qt::BlockingQueuedConnection); 322 + inputLayout->addWidget(&button);
  323 + layout->addLayout(inputLayout);
  324 +
  325 + centralWidget->setLayout(layout);
  326 +
  327 + setCentralWidget(centralWidget);
  328 +
  329 + connect(&button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
229 } 330 }
230 331
231 - // While this cannot be a template class, it can still have a template method.  
232 - template<typename T>  
233 - T * getItem() 332 +public slots:
  333 + void showImage(const QPixmap & input)
234 { 334 {
235 - if (QThread::currentThread() == QApplication::instance()->thread())  
236 - return new T(); 335 + pixmap = input;
  336 + foreach(const QString& label, keys) {
  337 + QLineEdit *edit = new QLineEdit;
  338 + fields.append(edit);
  339 + QFormLayout *form = new QFormLayout;
  340 + form->addRow(label, edit);
  341 + inputLayout->addLayout(form);
  342 + }
237 343
238 - ActualCreation<T> * actualWorker;  
239 - actualWorker = new ActualCreation<T> ();  
240 - worker = actualWorker; 344 + show();
  345 + label.setPixmap(pixmap);
  346 + label.setFixedSize(input.size());
  347 + }
241 348
242 - emit needCreation(); 349 + QStringList waitForButtonPress()
  350 + {
  351 + QMutexLocker locker(&lock);
  352 + wait.wait(&lock);
243 353
244 - T * output = actualWorker->basis;  
245 - delete actualWorker;  
246 - return output; 354 + QStringList values;
  355 + for(int i = 0; i<fields.size(); i++) values.append(fields.at(i)->text());
  356 + return values;
247 } 357 }
248 358
249 - NominalCreation * worker; 359 +public slots:
250 360
251 -signals:  
252 - void needCreation(); 361 + void buttonPressed()
  362 + {
  363 + wait.wakeAll();
  364 + }
253 365
254 -public slots:  
255 - void createThing() 366 + void setKeys(const QStringList& k)
256 { 367 {
257 - worker->creation(); 368 + keys = k;
258 } 369 }
  370 +
  371 +private:
  372 +
  373 + QWidget *centralWidget;
  374 + QStringList keys;
  375 + QList<QLineEdit*> fields;
  376 + QPushButton button;
  377 + QMutex lock;
  378 + QWaitCondition wait;
  379 + QPixmap pixmap;
  380 + QLabel label;
  381 + QHBoxLayout *layout;
  382 + QVBoxLayout *inputLayout;
  383 +
259 }; 384 };
260 385
261 /*! 386 /*!
@@ -288,17 +413,11 @@ public: @@ -288,17 +413,11 @@ public:
288 413
289 void train(const TemplateList &data) { (void) data; } 414 void train(const TemplateList &data) { (void) data; }
290 415
291 - void project(const TemplateList &src, TemplateList &dst) const  
292 - {  
293 - Transform * non_const = (ShowTransform *) this;  
294 - non_const->projectUpdate(src,dst);  
295 - }  
296 -  
297 void projectUpdate(const TemplateList &src, TemplateList &dst) 416 void projectUpdate(const TemplateList &src, TemplateList &dst)
298 { 417 {
299 dst = src; 418 dst = src;
300 419
301 - if (src.empty() || !Globals->useGui) 420 + if (src.empty())
302 return; 421 return;
303 422
304 foreach (const Template & t, src) { 423 foreach (const Template & t, src) {
@@ -427,6 +546,98 @@ public: @@ -427,6 +546,98 @@ public:
427 546
428 BR_REGISTER(Transform, ManualTransform) 547 BR_REGISTER(Transform, ManualTransform)
429 548
  549 +/*!
  550 + * \ingroup transforms
  551 + * \brief Elicits metadata for templates in a pretty GUI
  552 + * \author Scott Klum \cite sklum
  553 + */
  554 +class ElicitTransform : public TimeVaryingTransform
  555 +{
  556 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  557 + BR_PROPERTY(QStringList, keys, QStringList())
  558 +
  559 + Q_OBJECT
  560 +
  561 + MainThreadCreator creator;
  562 + DisplayGUI *gui;
  563 + QImage qImageBuffer;
  564 + QPixmap *displayBuffer;
  565 +
  566 +public:
  567 + ElicitTransform() : TimeVaryingTransform(false, false)
  568 + {
  569 + displayBuffer = NULL;
  570 + gui = NULL;
  571 + }
  572 +
  573 + ~ElicitTransform()
  574 + {
  575 + delete displayBuffer;
  576 + delete gui;
  577 + }
  578 +
  579 + void train(const TemplateList &data) { (void) data; }
  580 +
  581 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  582 + {
  583 + dst = src;
  584 +
  585 + if (src.empty()) return;
  586 +
  587 + for (int i = 0; i < dst.size(); i++) {
  588 + foreach(const cv::Mat &m, dst[i]) {
  589 + qImageBuffer = toQImage(m);
  590 + displayBuffer->convertFromImage(qImageBuffer);
  591 +
  592 + emit updateImage(displayBuffer->copy(displayBuffer->rect()));
  593 +
  594 + QStringList metadata = gui->waitForButtonPress();
  595 + for(int j = 0; j < keys.size(); j++) dst[i].file.set(keys[j],metadata[j]);
  596 + }
  597 + }
  598 + }
  599 +
  600 + void finalize(TemplateList & output)
  601 + {
  602 + (void) output;
  603 + emit hideWindow();
  604 + }
  605 +
  606 + void init()
  607 + {
  608 + initActual<DisplayGUI>();
  609 + }
  610 +
  611 + template<typename GUIType>
  612 + void initActual()
  613 + {
  614 + if (!Globals->useGui)
  615 + return;
  616 +
  617 + TimeVaryingTransform::init();
  618 +
  619 + if (displayBuffer)
  620 + delete displayBuffer;
  621 +
  622 + displayBuffer = new QPixmap();
  623 +
  624 + if (gui)
  625 + delete gui;
  626 +
  627 + gui = creator.getItem<GUIType>();
  628 + gui->setKeys(keys);
  629 + // Connect our signals to the window's slots
  630 + connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap)));
  631 + connect(this, SIGNAL(hideWindow()), gui, SLOT(hide()));
  632 + }
  633 +
  634 +signals:
  635 +
  636 + void updateImage(const QPixmap & input);
  637 + void hideWindow();
  638 +
  639 +};
  640 +BR_REGISTER(Transform, ElicitTransform)
430 641
431 /*! 642 /*!
432 * \ingroup transforms 643 * \ingroup transforms
@@ -489,6 +700,11 @@ public: @@ -489,6 +700,11 @@ public:
489 BR_REGISTER(Transform, SurveyTransform) 700 BR_REGISTER(Transform, SurveyTransform)
490 701
491 702
  703 +/*!
  704 + * \ingroup transforms
  705 + * \brief Limits the frequency of projects going through this transform to the input targetFPS
  706 + * \author Charles Otto \cite caotto
  707 + */
492 class FPSLimit : public TimeVaryingTransform 708 class FPSLimit : public TimeVaryingTransform
493 { 709 {
494 Q_OBJECT 710 Q_OBJECT
@@ -539,6 +755,12 @@ protected: @@ -539,6 +755,12 @@ protected:
539 }; 755 };
540 BR_REGISTER(Transform, FPSLimit) 756 BR_REGISTER(Transform, FPSLimit)
541 757
  758 +/*!
  759 + * \ingroup transforms
  760 + * \brief Calculates the average FPS of projects going through this transform, stores the result in AvgFPS
  761 + * Reports an average FPS from the initialization of this transform onwards.
  762 + * \author Charles Otto \cite caotto
  763 + */
542 class FPSCalc : public TimeVaryingTransform 764 class FPSCalc : public TimeVaryingTransform
543 { 765 {
544 Q_OBJECT 766 Q_OBJECT
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/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
@@ -116,12 +116,12 @@ public: @@ -116,12 +116,12 @@ public:
116 116
117 virtual void project(const Template &src, Template &dst) const 117 virtual void project(const Template &src, Template &dst) const
118 { 118 {
119 - timeInvariantAlias->project(src,dst); 119 + timeInvariantAlias.project(src,dst);
120 } 120 }
121 121
122 virtual void project(const TemplateList &src, TemplateList &dst) const 122 virtual void project(const TemplateList &src, TemplateList &dst) const
123 { 123 {
124 - timeInvariantAlias->project(src,dst); 124 + timeInvariantAlias.project(src,dst);
125 } 125 }
126 126
127 // Get a compile failure if this isn't here to go along with the other 127 // Get a compile failure if this isn't here to go along with the other
@@ -150,21 +150,13 @@ public: @@ -150,21 +150,13 @@ public:
150 return this->clone(); 150 return this->clone();
151 } 151 }
152 152
153 - void init()  
154 - {  
155 - delete timeInvariantAlias;  
156 - timeInvariantAlias = new TimeInvariantWrapperTransform(this);  
157 - }  
158 -  
159 protected: 153 protected:
160 - Transform * timeInvariantAlias;  
161 - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) 154 + // Since copies aren't actually made until project is called, we can set up
  155 + // timeInvariantAlias in the constructor.
  156 + TimeInvariantWrapperTransform timeInvariantAlias;
  157 + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable), timeInvariantAlias(this)
162 { 158 {
163 - timeInvariantAlias = NULL;  
164 - }  
165 - ~TimeVaryingTransform()  
166 - {  
167 - delete timeInvariantAlias; 159 + //
168 } 160 }
169 }; 161 };
170 162
@@ -183,7 +175,7 @@ public: @@ -183,7 +175,7 @@ public:
183 virtual void project(const Template &src, Template &dst) const 175 virtual void project(const Template &src, Template &dst) const
184 { 176 {
185 if (timeVarying()) { 177 if (timeVarying()) {
186 - timeInvariantAlias->project(src,dst); 178 + timeInvariantAlias.project(src,dst);
187 return; 179 return;
188 } 180 }
189 _project(src, dst); 181 _project(src, dst);
@@ -192,7 +184,7 @@ public: @@ -192,7 +184,7 @@ public:
192 virtual void project(const TemplateList &src, TemplateList &dst) const 184 virtual void project(const TemplateList &src, TemplateList &dst) const
193 { 185 {
194 if (timeVarying()) { 186 if (timeVarying()) {
195 - timeInvariantAlias->project(src,dst); 187 + timeInvariantAlias.project(src,dst);
196 return; 188 return;
197 } 189 }
198 _project(src, dst); 190 _project(src, dst);
@@ -209,10 +201,6 @@ public: @@ -209,10 +201,6 @@ public:
209 isTimeVarying = isTimeVarying || transform->timeVarying(); 201 isTimeVarying = isTimeVarying || transform->timeVarying();
210 trainable = trainable || transform->trainable; 202 trainable = trainable || transform->trainable;
211 } 203 }
212 -  
213 - // If we are time varying, set up timeInvariantAlias  
214 - if (this->timeVarying())  
215 - TimeVaryingTransform::init();  
216 } 204 }
217 205
218 /*! 206 /*!
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/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
@@ -1119,7 +1122,10 @@ public: @@ -1119,7 +1122,10 @@ public:
1119 dst = src; 1122 dst = src;
1120 1123
1121 bool res = readStage->dataSource.open(dst); 1124 bool res = readStage->dataSource.open(dst);
1122 - if (!res) return; 1125 + if (!res) {
  1126 + qDebug("stream failed to open %s", qPrintable(dst[0].file.name));
  1127 + return;
  1128 + }
1123 1129
1124 // Start the first thread in the stream. 1130 // Start the first thread in the stream.
1125 QWriteLocker lock(&readStage->statusLock); 1131 QWriteLocker lock(&readStage->statusLock);
@@ -1368,11 +1374,6 @@ public: @@ -1368,11 +1374,6 @@ public:
1368 if (!transform) 1374 if (!transform)
1369 return; 1375 return;
1370 1376
1371 - // Set up timeInvariantAlias  
1372 - // this is only safe because copies are actually made in project  
1373 - // calls, not during init.  
1374 - TimeVaryingTransform::init();  
1375 -  
1376 trainable = transform->trainable; 1377 trainable = transform->trainable;
1377 1378
1378 basis.setParent(this->parent()); 1379 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
@@ -89,6 +89,7 @@ class CrossValidateTransform : public MetaTransform @@ -89,6 +89,7 @@ class CrossValidateTransform : public MetaTransform
89 } 89 }
90 } else if (partitions[j] == i) { 90 } else if (partitions[j] == i) {
91 partitionedData.removeAt(j); 91 partitionedData.removeAt(j);
  92 + j--;
92 } else j--; 93 } else j--;
93 } 94 }
94 // Train on the remaining templates 95 // 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