Commit ab502f60a54e382312888c9fd2947371f5ac51a5

Authored by Brendan Klare
2 parents a9fbb83e 5b3c7a8e

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

CHANGELOG.md
1 1 0.4.0 - ??/??/??
2 2 ================
  3 +* Added -evalLandmarking and -plotLandmarking for evaluating and plotting landmarking accuracy (#9)
3 4 * Added -evalDetection and -plotDetection for evaluating and plotting object detection accuracy (#9)
4 5 * Deprecated Transform::backProject
5 6  
... ...
app/br/br.cpp
... ... @@ -146,6 +146,9 @@ public:
146 146 } else if (!strcmp(fun, "plotDetection")) {
147 147 check(parc >= 2, "Incorrect parameter count for 'plotDetection'.");
148 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 152 } else if (!strcmp(fun, "plotMetadata")) {
150 153 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
151 154 br_plot_metadata(parc-1, parv, parv[parc-1], true);
... ... @@ -224,6 +227,7 @@ private:
224 227 "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>]]\n"
225 228 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n"
226 229 "-plotDetection <file> ... <file> {destination}\n"
  230 + "-plotLandmarking <file> ... <file> {destination}\n"
227 231 "-plotMetadata <file> ... <file> <columns>\n"
228 232 "-getHeader <matrix>\n"
229 233 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n"
... ...
openbr/core/plot.cpp
... ... @@ -228,7 +228,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
228 228 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
229 229 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
230 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 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 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 236 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") +
237 237 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
238 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 241 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") +
242 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 302 bool PlotDetection(const QStringList &files, const File &destination, bool show)
303 303 {
304 304 qDebug("Plotting %d detection file(s) to %s", files.size(), qPrintable(destination));
305   -
306 305 RPlot p(files, destination, false);
307 306  
308 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 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 368 bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
349 369 {
350 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 26 {
27 27 bool Plot(const QStringList &files, const File &destination, bool show = false);
28 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 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 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 46 template <typename T>
44 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 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 190 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show)
186 191 {
187 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 265 * - <i>destination</i><tt>.R</tt> which is the auto-generated R script used to render the figures.
266 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 274 * \param num_files Number of <tt>.csv</tt> files.
269 275 * \param files <tt>.csv</tt> files created using \ref br_eval.
270 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 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 318 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns.
299 319 *
300 320 * Several files will be created:
... ...
openbr/openbr_plugin.cpp
... ... @@ -387,7 +387,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
387 387  
388 388 const int crossValidate = gallery.get<int>("crossValidate");
389 389  
390   - if (gallery.getBool("leaveOneOut")) {
  390 + if (gallery.getBool("leaveOneImageOut")) {
391 391 QStringList labels;
392 392 for (int i=newTemplates.size()-1; i>=0; i--) {
393 393 newTemplates[i].file.set("Index", i+templates.size());
... ... @@ -406,11 +406,11 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
406 406 // Extend the gallery for each partition
407 407 for (int j=0; j<labelIndices.size(); j++) {
408 408 for (int k=0; k<crossValidate; k++) {
409   - Template leaveOneOutTemplate = newTemplates[labelIndices[j]];
410   - if (k!=leaveOneOutTemplate.file.get<int>("Partition")) {
411   - leaveOneOutTemplate.file.set("Partition", k);
412   - leaveOneOutTemplate.file.set("testOnly", true);
413   - newTemplates.insert(i+1,leaveOneOutTemplate);
  409 + Template leaveOneImageOutTemplate = newTemplates[labelIndices[j]];
  410 + if (k!=leaveOneImageOutTemplate.file.get<int>("Partition")) {
  411 + leaveOneImageOutTemplate.file.set("Partition", k);
  412 + leaveOneImageOutTemplate.file.set("testOnly", true);
  413 + newTemplates.insert(i+1,leaveOneImageOutTemplate);
414 414 }
415 415 }
416 416 }
... ...
openbr/plugins/algorithms.cpp
... ... @@ -50,9 +50,9 @@ class AlgorithmsInitializer : public Initializer
50 50 Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)");
51 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 57 // Generic Image Processing
58 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 69  
70 70 /*!
71 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 97 * \brief Resize the template
73 98 * \author Josh Klontz \cite jklontz
74 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 253 {
254 254 Q_OBJECT
255 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 256 BR_PROPERTY(float, keep, 0.95)
258   - BR_PROPERTY(br::Transform*, transform, NULL)
259 257  
260 258 PCATransform pca;
261 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 5 #include <QMutex>
6 6 #include <QMouseEvent>
7 7 #include <QPainter>
  8 +#include <QMainWindow>
  9 +#include <QPushButton>
  10 +#include <QHBoxLayout>
  11 +#include <QFormLayout>
  12 +#include <QLineEdit>
8 13  
9 14 #include <opencv2/imgproc/imgproc.hpp>
10 15 #include "openbr_internal.h"
... ... @@ -65,6 +70,7 @@ public:
65 70  
66 71 DisplayWindow(QWidget * parent = NULL) : QLabel(parent)
67 72 {
  73 + setFixedSize(200,200);
68 74 QApplication::instance()->installEventFilter(this);
69 75 }
70 76  
... ... @@ -75,7 +81,13 @@ public slots:
75 81  
76 82 show();
77 83 setPixmap(pixmap);
78   - setFixedSize(input.size());
  84 +
  85 + // We appear to get a warning on windows if we set window width < 104. This is of course not
  86 + // reflected in the Qt min size settings, and I don't know how to query it.
  87 + QSize temp = input.size();
  88 + if (temp.width() < 104)
  89 + temp.setWidth(104);
  90 + setFixedSize(temp);
79 91 }
80 92  
81 93  
... ... @@ -188,6 +200,85 @@ private:
188 200  
189 201 };
190 202  
  203 +class DisplayGUI : public QMainWindow
  204 +{
  205 + Q_OBJECT
  206 +
  207 +public:
  208 +
  209 + DisplayGUI(QWidget * parent = NULL) : QMainWindow(parent)
  210 + {
  211 + centralWidget = new QWidget();
  212 + layout = new QHBoxLayout();
  213 + inputLayout = new QVBoxLayout();
  214 +
  215 + button.setText("Set Template Metadata");
  216 +
  217 + layout->addWidget(&label);
  218 +
  219 + inputLayout->addWidget(&button);
  220 + layout->addLayout(inputLayout);
  221 +
  222 + centralWidget->setLayout(layout);
  223 +
  224 + setCentralWidget(centralWidget);
  225 +
  226 + connect(&button, SIGNAL(clicked()), this, SLOT(buttonPressed()));
  227 + }
  228 +
  229 +public slots:
  230 + void showImage(const QPixmap & input)
  231 + {
  232 + pixmap = input;
  233 + foreach(const QString& label, keys) {
  234 + QLineEdit *edit = new QLineEdit;
  235 + fields.append(edit);
  236 + QFormLayout *form = new QFormLayout;
  237 + form->addRow(label, edit);
  238 + inputLayout->addLayout(form);
  239 + }
  240 +
  241 + show();
  242 + label.setPixmap(pixmap);
  243 + label.setFixedSize(input.size());
  244 + }
  245 +
  246 + QStringList waitForButtonPress()
  247 + {
  248 + QMutexLocker locker(&lock);
  249 + wait.wait(&lock);
  250 +
  251 + QStringList values;
  252 + for(int i = 0; i<fields.size(); i++) values.append(fields.at(i)->text());
  253 + return values;
  254 + }
  255 +
  256 +public slots:
  257 +
  258 + void buttonPressed()
  259 + {
  260 + wait.wakeAll();
  261 + }
  262 +
  263 + void setKeys(const QStringList& k)
  264 + {
  265 + keys = k;
  266 + }
  267 +
  268 +private:
  269 +
  270 + QWidget *centralWidget;
  271 + QStringList keys;
  272 + QList<QLineEdit*> fields;
  273 + QPushButton button;
  274 + QMutex lock;
  275 + QWaitCondition wait;
  276 + QPixmap pixmap;
  277 + QLabel label;
  278 + QHBoxLayout *layout;
  279 + QVBoxLayout *inputLayout;
  280 +
  281 +};
191 282  
192 283 // I want a template class that doesn't look like a template class
193 284 class NominalCreation
... ... @@ -298,7 +389,7 @@ public:
298 389 {
299 390 dst = src;
300 391  
301   - if (src.empty() || !Globals->useGui)
  392 + if (src.empty())
302 393 return;
303 394  
304 395 foreach (const Template & t, src) {
... ... @@ -427,6 +518,104 @@ public:
427 518  
428 519 BR_REGISTER(Transform, ManualTransform)
429 520  
  521 +/*!
  522 + * \ingroup transforms
  523 + * \brief Elicits metadata for templates in a pretty GUI
  524 + * \author Scott Klum \cite sklum
  525 + */
  526 +class ElicitTransform : public TimeVaryingTransform
  527 +{
  528 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  529 + BR_PROPERTY(QStringList, keys, QStringList())
  530 +
  531 + Q_OBJECT
  532 +
  533 + MainThreadCreator creator;
  534 + DisplayGUI *gui;
  535 + QImage qImageBuffer;
  536 + QPixmap *displayBuffer;
  537 +
  538 +public:
  539 + ElicitTransform() : TimeVaryingTransform(false, false)
  540 + {
  541 + displayBuffer = NULL;
  542 + gui = NULL;
  543 + }
  544 +
  545 + ~ElicitTransform()
  546 + {
  547 + delete displayBuffer;
  548 + delete gui;
  549 + }
  550 +
  551 + void train(const TemplateList &data) { (void) data; }
  552 +
  553 + void project(const TemplateList &src, TemplateList &dst) const
  554 + {
  555 + Transform * non_const = (ElicitTransform *) this;
  556 + non_const->projectUpdate(src,dst);
  557 + }
  558 +
  559 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  560 + {
  561 + dst = src;
  562 +
  563 + if (src.empty()) return;
  564 +
  565 + for (int i = 0; i < dst.size(); i++) {
  566 + foreach(const cv::Mat &m, dst[i]) {
  567 + qImageBuffer = toQImage(m);
  568 + displayBuffer->convertFromImage(qImageBuffer);
  569 +
  570 + emit updateImage(displayBuffer->copy(displayBuffer->rect()));
  571 +
  572 + QStringList metadata = gui->waitForButtonPress();
  573 + for(int j = 0; j < keys.size(); j++) dst[i].file.set(keys[j],metadata[j]);
  574 + }
  575 + }
  576 + }
  577 +
  578 + void finalize(TemplateList & output)
  579 + {
  580 + (void) output;
  581 + emit hideWindow();
  582 + }
  583 +
  584 + void init()
  585 + {
  586 + initActual<DisplayGUI>();
  587 + }
  588 +
  589 + template<typename GUIType>
  590 + void initActual()
  591 + {
  592 + if (!Globals->useGui)
  593 + return;
  594 +
  595 + TimeVaryingTransform::init();
  596 +
  597 + if (displayBuffer)
  598 + delete displayBuffer;
  599 +
  600 + displayBuffer = new QPixmap();
  601 +
  602 + if (gui)
  603 + delete gui;
  604 +
  605 + gui = creator.getItem<GUIType>();
  606 + gui->setKeys(keys);
  607 + // Connect our signals to the window's slots
  608 + connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap)));
  609 + connect(this, SIGNAL(hideWindow()), gui, SLOT(hide()));
  610 + }
  611 +
  612 +signals:
  613 +
  614 + void updateImage(const QPixmap & input);
  615 + void hideWindow();
  616 +
  617 +};
  618 +BR_REGISTER(Transform, ElicitTransform)
430 619  
431 620 /*!
432 621 * \ingroup transforms
... ...
openbr/plugins/keypoint.cpp
... ... @@ -222,9 +222,9 @@ class GridTransform : public UntrainableTransform
222 222 QList<QPointF> landmarks;
223 223 const float row_step = 1.f * src.m().rows / rows;
224 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 228 dst = src;
229 229 dst.file.setPoints(landmarks);
230 230 }
... ...
openbr/plugins/meta.cpp
... ... @@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform
264 264  
265 265 virtual void project(const TemplateList &src, TemplateList &dst) const
266 266 {
267   - //dst = Expanded(src);
268 267 if (src.empty()) return;
269 268 Template out;
270 269  
... ... @@ -682,8 +681,10 @@ public:
682 681  
683 682 void init()
684 683 {
685   - if (transform && transform->timeVarying())
686   - transform = new br::TimeInvariantWrapperTransform(transform);
  684 + if (!transform)
  685 + return;
  686 +
  687 + trainable = transform->trainable;
687 688 }
688 689  
689 690 };
... ...
openbr/plugins/misc.cpp
... ... @@ -332,57 +332,6 @@ class AnonymizeTransform : public UntrainableMetaTransform
332 332  
333 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 336 * \ingroup transforms
388 337 * \brief Change the br::Template::file extension
... ... @@ -405,27 +354,31 @@ BR_REGISTER(Transform, AsTransform)
405 354  
406 355 /*!
407 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 362 Q_OBJECT
414 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 366 BR_PROPERTY(QString, regexp, "(.*)")
  367 + BR_PROPERTY(QString, inputProperty, "name")
  368 + BR_PROPERTY(QString, outputProperty, "Label")
416 369  
417 370 void project(const Template &src, Template &dst) const
418 371 {
419 372 dst = src;
420 373 QRegularExpression re(regexp);
421   - QRegularExpressionMatch match = re.match(dst.file.baseName());
  374 + QRegularExpressionMatch match = re.match(dst.file.get<QString>(inputProperty));
422 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 384 * \ingroup transforms
... ... @@ -521,6 +474,73 @@ class RestoreMatTransform : public UntrainableMetaTransform
521 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 544 class EventTransform : public UntrainableMetaTransform
525 545 {
526 546 Q_OBJECT
... ...
openbr/plugins/openbr_internal.h
... ... @@ -24,81 +24,27 @@ private:
24 24 };
25 25  
26 26 /*!
27   - * \brief A br::MetaTransform that does not require training data.
  27 + * \brief A br::Transform expecting multiple matrices per template.
28 28 */
29   -class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform
  29 +class BR_EXPORT MetaTransform : public Transform
30 30 {
31 31 Q_OBJECT
32 32  
33 33 protected:
34   - UntrainableMetaTransform() : UntrainableTransform(false) {}
35   -};
36   -
37   -/*!
38   - * \brief A br::Transform for which the results of project may change due to prior calls to project
39   - */
40   -class BR_EXPORT TimeVaryingTransform : public Transform
41   -{
42   - Q_OBJECT
43   -
44   -public:
45   - virtual bool timeVarying() const { return true; }
46   -
47   - virtual void project(const Template &src, Template &dst) const
48   - {
49   - qFatal("No const project defined for time-varying transform");
50   - (void) dst; (void) src;
51   - }
52   -
53   - virtual void project(const TemplateList &src, TemplateList &dst) const
54   - {
55   - qFatal("No const project defined for time-varying transform");
56   - (void) dst; (void) src;
57   - }
58   -
59   - // Get a compile failure if this isn't here to go along with the other
60   - // projectUpdate, no idea why
61   - virtual void projectUpdate(const Template & src, Template & dst)
62   - {
63   - (void) src; (void) dst;
64   - qFatal("do something useful");
65   - }
66   -
67   - virtual void projectUpdate(const TemplateList &src, TemplateList &dst)
68   - {
69   - foreach (const Template & src_part, src) {
70   - Template out;
71   - projectUpdate(src_part, out);
72   - dst.append(out);
73   - }
74   - }
75   -
76   - /*!
77   - *\brief For transforms that don't do any training, this default implementation
78   - * which creates a new copy of the Transform from its description string is sufficient.
79   - */
80   - virtual Transform * smartCopy()
81   - {
82   - return this->clone();
83   - }
84   -
85   -
86   -protected:
87   - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {}
  34 + MetaTransform() : Transform(false) {}
88 35 };
89 36  
90 37 /*!
91   - * \brief A br::Transform expecting multiple matrices per template.
  38 + * \brief A br::MetaTransform that does not require training data.
92 39 */
93   -class BR_EXPORT MetaTransform : public Transform
  40 +class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform
94 41 {
95 42 Q_OBJECT
96 43  
97 44 protected:
98   - MetaTransform() : Transform(false) {}
  45 + UntrainableMetaTransform() : UntrainableTransform(false) {}
99 46 };
100 47  
101   -
102 48 class TransformCopier : public ResourceMaker<Transform>
103 49 {
104 50 public:
... ... @@ -151,6 +97,63 @@ private:
151 97 Transform * baseTransform;
152 98 };
153 99  
  100 +/*!
  101 + * \brief A br::Transform for which the results of project may change due to prior calls to project
  102 + */
  103 +class BR_EXPORT TimeVaryingTransform : public Transform
  104 +{
  105 + Q_OBJECT
  106 +
  107 +public:
  108 +
  109 + virtual bool timeVarying() const { return true; }
  110 +
  111 + virtual void project(const Template &src, Template &dst) const
  112 + {
  113 + timeInvariantAlias.project(src,dst);
  114 + }
  115 +
  116 + virtual void project(const TemplateList &src, TemplateList &dst) const
  117 + {
  118 + timeInvariantAlias.project(src,dst);
  119 + }
  120 +
  121 + // Get a compile failure if this isn't here to go along with the other
  122 + // projectUpdate, no idea why
  123 + virtual void projectUpdate(const Template & src, Template & dst)
  124 + {
  125 + (void) src; (void) dst;
  126 + qFatal("do something useful");
  127 + }
  128 +
  129 + virtual void projectUpdate(const TemplateList &src, TemplateList &dst)
  130 + {
  131 + foreach (const Template & src_part, src) {
  132 + Template out;
  133 + projectUpdate(src_part, out);
  134 + dst.append(out);
  135 + }
  136 + }
  137 +
  138 + /*!
  139 + *\brief For transforms that don't do any training, this default implementation
  140 + * which creates a new copy of the Transform from its description string is sufficient.
  141 + */
  142 + virtual Transform * smartCopy()
  143 + {
  144 + return this->clone();
  145 + }
  146 +
  147 +protected:
  148 + // Since copies aren't actually made until project is called, we can set up
  149 + // timeInvariantAlias in the constructor.
  150 + TimeInvariantWrapperTransform timeInvariantAlias;
  151 + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable), timeInvariantAlias(this)
  152 + {
  153 + //
  154 + }
  155 +};
  156 +
154 157  
155 158 /*!
156 159 * \brief A MetaTransform that aggregates some sub-transforms
... ... @@ -165,15 +168,17 @@ public:
165 168  
166 169 virtual void project(const Template &src, Template &dst) const
167 170 {
168   - if (timeVarying()) qFatal("No const project defined for time-varying transform");
  171 + if (timeVarying()) {
  172 + timeInvariantAlias.project(src,dst);
  173 + return;
  174 + }
169 175 _project(src, dst);
170 176 }
171 177  
172 178 virtual void project(const TemplateList &src, TemplateList &dst) const
173 179 {
174 180 if (timeVarying()) {
175   - CompositeTransform * non_const = const_cast<CompositeTransform *>(this);
176   - non_const->projectUpdate(src,dst);
  181 + timeInvariantAlias.project(src,dst);
177 182 return;
178 183 }
179 184 _project(src, dst);
... ...
openbr/plugins/phash.cmake deleted
1   -set(BR_WITH_PHASH OFF CACHE BOOL "Build with pHash")
2   -
3   -if(${BR_WITH_PHASH})
4   - find_package(pHash REQUIRED)
5   - find_package(CImg REQUIRED)
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/phash.cpp ${PHASH_SRC})
7   -endif()
openbr/plugins/phash.cpp deleted
1   -#include <opencv2/core/core.hpp>
2   -#include <pHash.h>
3   -#include <mm_plugin.h>
4   -
5   -using namespace mm;
6   -
7   -/**** PHASH ****/
8   -class pHashEnroll : public UntrainableFeature
9   -{
10   - void project(const Matrix &src, Matrix &dst) const
11   - {
12   - CImg<uint8_t> cImg(src.data, src.cols, src.rows, 1, src.channels());
13   - cv::Mat m(1, sizeof(ulong64), CV_8UC1);
14   - ulong64 hash;
15   - if (ph_dct_imagehash(cImg, hash) == -1)
16   - qFatal("pHashEnroll::project ph_dct_imagehash failure for file %s.", qPrintable(src.metadata.fileName));
17   - memcpy(m.data, &hash, sizeof(ulong64));
18   - dst = Matrix(m, src.metadata);
19   - }
20   -
21   - /*** Taken from pHash, modified to take in a CImg instead of a file. ***/
22   - static CImg<float>* ph_dct_matrix(const int N){
23   - CImg<float> *ptr_matrix = new CImg<float>(N,N,1,1,1/sqrt((float)N));
24   - const float c1 = sqrt(2.0/N);
25   - for (int x=0;x<N;x++){
26   - for (int y=1;y<N;y++){
27   - *ptr_matrix->data(x,y) = c1*cos((cimg::PI/2/N)*y*(2*x+1));
28   - }
29   - }
30   - return ptr_matrix;
31   - }
32   -
33   - static int ph_dct_imagehash(CImg<uint8_t> src, ulong64 &hash)
34   - {
35   - CImg<float> meanfilter(7,7,1,1,1);
36   - CImg<float> img;
37   - if (src.spectrum() == 3){
38   - img = src.RGBtoYCbCr().channel(0).get_convolve(meanfilter);
39   - } else if (src.spectrum() == 4){
40   - int width = img.width();
41   - int height = img.height();
42   - int depth = img.depth();
43   - img = src.crop(0,0,0,0,width-1,height-1,depth-1,2).RGBtoYCbCr().channel(0).get_convolve(meanfilter);
44   - } else {
45   - img = src.channel(0).get_convolve(meanfilter);
46   - }
47   -
48   - img.resize(32,32);
49   - CImg<float> *C = ph_dct_matrix(32);
50   - CImg<float> Ctransp = C->get_transpose();
51   -
52   - CImg<float> dctImage = (*C)*img*Ctransp;
53   -
54   - CImg<float> subsec = dctImage.crop(1,1,8,8).unroll('x');;
55   -
56   - float median = subsec.median();
57   - ulong64 one = 0x0000000000000001;
58   - hash = 0x0000000000000000;
59   - for (int i=0;i< 64;i++){
60   - float current = subsec(i);
61   - if (current > median)
62   - hash |= one;
63   - one = one << 1;
64   - }
65   -
66   - delete C;
67   -
68   - return 0;
69   - }
70   -};
71   -
72   -MM_REGISTER(Feature, pHashEnroll, false)
73   -
74   -
75   -/**** PHASH_COMPARE ****/
76   -class pHashCompare : public ComparerBase
77   -{
78   - float compare(const cv::Mat &a, const cv::Mat &b) const
79   - {
80   - return 1.f - 1.f * ph_hamming_distance(*reinterpret_cast<ulong64*>(a.data), *reinterpret_cast<ulong64*>(b.data)) / 64;
81   - }
82   -};
83   -
84   -MM_REGISTER(Comparer, pHashCompare, false)
85   -
86   -
87   -/**** PHASH ****/
88   -class pHash : public Algorithm
89   -{
90   - QString algorithm() const
91   - {
92   - return "Open+pHashEnroll:Identity:pHashCompare";
93   - }
94   -};
95   -
96   -MM_REGISTER(Algorithm, pHash, false)
openbr/plugins/pp4.cmake deleted
1   -set(BR_WITH_PP4 OFF CACHE BOOL "Build with PittPatt 4")
2   -
3   -if(${BR_WITH_PP4})
4   - find_package(PP4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp)
6   - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS})
7   - install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib)
8   - install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4)
9   -endif()
openbr/plugins/pp4.cpp deleted
1   -#include <QThreadPool>
2   -#include <pittpatt_errors.h>
3   -#include <pittpatt_nc_sdk.h>
4   -#include <pittpatt_raw_image_io.h>
5   -#include <pittpatt_license.h>
6   -#include <mm_plugin.h>
7   -
8   -#define TRY(CC) \
9   -{ \
10   - if ((CC) != PPR_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_error_message(CC)); \
11   -}
12   -
13   -#define TRY_VIDEO(CC) \
14   -{ \
15   - if ((CC) != PPR_VIDEO_IO_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_video_io_error_message(CC)); \
16   -}
17   -
18   -#define TRY_RAW_IMAGE(CC) \
19   -{ \
20   - if ((CC) != PPR_RAW_IMAGE_SUCCESS) qFatal("%d error (%s, %d): %s.", CC, __FILE__, __LINE__, ppr_raw_image_error_message(CC)); \
21   -}
22   -
23   -using namespace mm;
24   -
25   -/*!
26   - * \brief PittPatt 4 context
27   - * \author Josh Klontz \cite jklontz
28   - * \warning Needs a maintainer.
29   - */
30   -struct PP4Context
31   -{
32   - static ppr_context_type context;
33   -
34   - static void createRawImage(const cv::Mat &src, ppr_raw_image_type &dst)
35   - {
36   - ppr_raw_image_create(&dst, src.cols, src.rows, PPR_RAW_IMAGE_BGR24);
37   - assert((src.type() == CV_8UC3) && src.isContinuous());
38   - memcpy(dst.data, src.data, 3*src.rows*src.cols);
39   - }
40   -
41   - static void createMat(const ppr_template_type &src, cv::Mat &dst)
42   - {
43   - ppr_flat_template_type flat_template;
44   - TRY(ppr_flatten_template(context,src,&flat_template))
45   - dst = cv::Mat(1, flat_template.num_bytes, CV_8UC1, flat_template.data).clone();
46   - ppr_free_flat_template(flat_template);
47   - }
48   -
49   - static void createTemplate(const cv::Mat &src, ppr_template_type *dst)
50   - {
51   - ppr_flat_template_type flat_template;
52   - flat_template.num_bytes = src.cols;
53   - flat_template.data = src.data;
54   - TRY(ppr_unflatten_template(context, flat_template, dst))
55   - }
56   -
57   - static QString toString(const ppr_landmark_category_type &category)
58   - {
59   - switch (category) {
60   - case PPR_LANDMARK_LEFT_EYE:
61   - return "Left_Eye";
62   - case PPR_LANDMARK_RIGHT_EYE:
63   - return "Right_Eye";
64   - case PPR_LANDMARK_NOSE_BASE:
65   - return "Nose_Base";
66   - case PPR_LANDMARK_NOSE_BRIDGE:
67   - return "Nose_Bridge";
68   - case PPR_LANDMARK_NOSE_TIP:
69   - return "Nose_Tip";
70   - case PPR_LANDMARK_NOSE_TOP:
71   - return "Nose_Top";
72   - case PPR_LANDMARK_EYE_NOSE:
73   - return "Eye_Nose";
74   - case PPR_LANDMARK_MOUTH:
75   - return "Mouth";
76   - }
77   -
78   - return "Unknown";
79   - }
80   -
81   - static File toMetadata(const ppr_object_type &object)
82   - {
83   - File metadata;
84   - metadata.insert("PP4_Object_X", object.position.x - object.dimensions.width/2);
85   - metadata.insert("PP4_Object_Y", object.position.y - object.dimensions.height/2);
86   - metadata.insert("PP4_Object_Width", object.dimensions.width);
87   - metadata.insert("PP4_Object_Height", object.dimensions.height);
88   - metadata.insert("PP4_Object_Confidence", object.confidence);
89   - metadata.insert("PP4_Object_Roll", object.rotation.roll);
90   - metadata.insert("PP4_Object_Pitch", object.rotation.pitch);
91   - metadata.insert("PP4_Object_Yaw", object.rotation.yaw);
92   - metadata.insert("PP4_Object_Precision", object.rotation.precision);
93   - metadata.insert("PP4_Object_ModelID", object.model_id);
94   - metadata.insert("PP4_Object_NumLandmarks", object.num_landmarks);
95   - metadata.insert("PP4_Object_Size", object.size);
96   -
97   - QList<ppr_landmark_category_type> categories;
98   - categories << PPR_LANDMARK_RIGHT_EYE
99   - << PPR_LANDMARK_LEFT_EYE
100   - << PPR_LANDMARK_NOSE_BASE
101   - << PPR_LANDMARK_NOSE_BRIDGE
102   - << PPR_LANDMARK_NOSE_TIP
103   - << PPR_LANDMARK_NOSE_TOP
104   - << PPR_LANDMARK_EYE_NOSE
105   - << PPR_LANDMARK_MOUTH;
106   -
107   - for (int i=0; i<categories.size(); i++) {
108   - ppr_landmark_category_type category = categories[i];
109   - QString metadataString = QString("PP4_Landmark%1_%2").arg(QString::number(i), toString(category));
110   -
111   - bool found = false;
112   - for (int j=0; j<object.num_landmarks; j++) {
113   - ppr_landmark_type &landmark = object.landmarks[j];
114   - if (landmark.category != category) continue;
115   -
116   - metadata.insert(metadataString+"_X", landmark.position.x);
117   - metadata.insert(metadataString+"_Y", landmark.position.y);
118   - metadata.insert(metadataString+"_Category", landmark.category);
119   - metadata.insert(metadataString+"_ModelID", landmark.model_id);
120   - metadata.insert(metadataString+"_Index", j);
121   - found = true;
122   - break;
123   - }
124   -
125   - if (!found) {
126   - metadata.insert(metadataString+"_X", -1);
127   - metadata.insert(metadataString+"_Y", -1);
128   - metadata.insert(metadataString+"_Category", -1);
129   - metadata.insert(metadataString+"_ModelID", -1);
130   - metadata.insert(metadataString+"_Index", -1);
131   - }
132   - }
133   -
134   - return metadata;
135   - }
136   -
137   - static ppr_object_type fromMetadata(const File &metadata)
138   - {
139   - ppr_object_type object;
140   -
141   - object.position.x = metadata.value("PP4_Object_X").toFloat() + metadata.value("PP4_Object_Width").toFloat()/2;
142   - object.position.y = metadata.value("PP4_Object_Y").toFloat() + metadata.value("PP4_Object_Height").toFloat()/2;
143   - object.dimensions.width = metadata.value("PP4_Object_Width").toFloat();
144   - object.dimensions.height = metadata.value("PP4_Object_Height").toFloat();
145   - object.confidence = metadata.value("PP4_Object_Confidence").toFloat();
146   - object.rotation.roll = metadata.value("PP4_Object_Roll").toFloat();
147   - object.rotation.pitch = metadata.value("PP4_Object_Pitch").toFloat();
148   - object.rotation.yaw = metadata.value("PP4_Object_Yaw").toFloat();
149   - object.rotation.precision = (ppr_precision_type) metadata.value("PP4_Object_Precision").toFloat();
150   - object.model_id = metadata.value("PP4_Object_ModelID").toInt();
151   - object.num_landmarks = metadata.value("PP4_Object_NumLandmarks").toInt();
152   - object.size = metadata.value("PP4_Object_Size").toFloat();
153   -
154   - QStringList landmarkNames = QStringList(metadata.keys()).filter(QRegExp("(.*)_Category")).replaceInStrings("_Category", "");
155   - object.landmarks = new ppr_landmark_type[object.num_landmarks];
156   - for (int j=0; j<landmarkNames.size(); j++) {
157   - int landmarkIndex = metadata.value(landmarkNames[j]+"_Index").toInt();
158   - if (landmarkIndex == -1) continue;
159   - object.landmarks[landmarkIndex].position.x = metadata.value(landmarkNames[j]+"_X").toFloat();
160   - object.landmarks[landmarkIndex].position.y = metadata.value(landmarkNames[j]+"_Y").toFloat();
161   - object.landmarks[landmarkIndex].category = (ppr_landmark_category_type)metadata.value(landmarkNames[j]+"_Category").toInt();
162   - object.landmarks[landmarkIndex].model_id = metadata.value(landmarkNames[j]+"_ModelID").toInt();
163   - landmarkIndex++;
164   - }
165   -
166   - return object;
167   - }
168   -
169   - static void freeObject(ppr_object_type &object)
170   - {
171   - delete[] object.landmarks;
172   - object.landmarks = NULL;
173   - object.num_landmarks = 0;
174   - }
175   -};
176   -
177   -ppr_context_type PP4Context::context;
178   -
179   -/*!
180   - * \ingroup initializers
181   - * \brief Initialize PittPatt 4
182   - * \author Josh Klontz \cite jklontz
183   - * \warning Needs a maintainer.
184   - */
185   -class PP4Initializer : public Initializer
186   - , public PP4Context
187   -{
188   - Q_OBJECT
189   -
190   - void initialize() const
191   - {
192   - context = ppr_get_context();
193   - TRY(ppr_enable_recognition(context))
194   - TRY(ppr_set_license(context, my_license_id, my_license_key))
195   - TRY(ppr_set_models_path(context, qPrintable(Globals->SDKPath + "/models/pp4")))
196   - TRY(ppr_set_num_recognition_threads(context, QThreadPool::globalInstance()->maxThreadCount()))
197   - TRY(ppr_set_num_detection_threads(context, 1))
198   - TRY(ppr_set_detection_precision(context, PPR_FINE_PRECISION))
199   - TRY(ppr_set_landmark_detector_type(context, PPR_DUAL_MULTI_POSE_LANDMARK_DETECTOR, PPR_AUTOMATIC_LANDMARKS))
200   - TRY(ppr_set_min_size(context, 4))
201   - TRY(ppr_set_frontal_yaw_constraint(context, PPR_FRONTAL_YAW_CONSTRAINT_PERMISSIVE))
202   - TRY(ppr_set_template_extraction_type(context, PPR_EXTRACT_DOUBLE))
203   - TRY(ppr_initialize_context(context))
204   - Globals->Abbreviations.insert("PP4", "Open+PP4Detect!PP4Enroll:PP4Compare");
205   - }
206   -
207   - void finalize() const
208   - {
209   - TRY(ppr_release_context(context))
210   - ppr_finalize_sdk();
211   - }
212   -};
213   -
214   -MM_REGISTER(Initializer, PP4Initializer, "")
215   -
216   -/*!
217   - * \ingroup transforms
218   - * \brief Detect a face in PittPatt 4
219   - * \author Josh Klontz \cite jklontz
220   - * \warning Needs a maintainer.
221   - */
222   -class PP4Detect : public UntrainableMetaFeature
223   - , public PP4Context
224   -{
225   - Q_OBJECT
226   -
227   - void project(const Template &src, Template &dst) const
228   - {
229   - dst.file = src.file;
230   -
231   - foreach (const cv::Mat &matrix, src) {
232   - ppr_raw_image_type raw_image;
233   - createRawImage(matrix, raw_image);
234   - ppr_image_type image;
235   - TRY(ppr_create_image(raw_image, &image))
236   - ppr_object_list_type object_list;
237   - TRY(ppr_detect_objects(context, image, &object_list))
238   -
239   - QList<ppr_object_type> objects;
240   - if (src.file.getBool("ForceEnrollment")) objects = getBestObject(object_list);
241   - else objects = getAllObjects(object_list);
242   -
243   - foreach (const ppr_object_type &object, objects) {
244   - dst.file.append(toMetadata(object));
245   - dst += matrix;
246   - }
247   -
248   - ppr_free_object_list(object_list);
249   - ppr_free_image(image);
250   - ppr_raw_image_free(raw_image);
251   - }
252   -
253   - if (src.file.getBool("ForceEnrollment") && dst.isEmpty()) dst += cv::Mat();
254   - }
255   -
256   -private:
257   - QList<ppr_object_type> getBestObject(ppr_object_list_type object_list) const
258   - {
259   - int best_index = -1;
260   - float best_confidence = 0;
261   - for (int i=0; i<object_list.num_objects; i++) {
262   - ppr_object_type object = object_list.objects[i];
263   - ppr_object_suitability_type suitability;
264   - TRY(ppr_is_object_suitable_for_recognition(context, object, &suitability))
265   - if (suitability != PPR_OBJECT_SUITABLE_FOR_RECOGNITION) continue;
266   - if ((object.confidence > best_confidence) ||
267   - (best_index == -1)) {
268   - best_confidence = object.confidence;
269   - best_index = i;
270   - }
271   - }
272   -
273   - QList<ppr_object_type> objects;
274   - if (best_index != -1) objects.append(object_list.objects[best_index]);
275   - return objects;
276   - }
277   -
278   - QList<ppr_object_type> getAllObjects(ppr_object_list_type object_list) const
279   - {
280   - QList<ppr_object_type> objects;
281   - for (int i=0; i<object_list.num_objects; i++)
282   - objects.append(object_list.objects[i]);
283   - return objects;
284   - }
285   -};
286   -
287   -MM_REGISTER(Feature, PP4Detect, "")
288   -
289   -/*!
290   - * \ingroup transforms
291   - * \brief Enroll face in PittPatt 4
292   - * \author Josh Klontz \cite jklontz
293   - * \warning Needs a maintainer.
294   - */
295   -class PP4Enroll : public UntrainableMetaFeature
296   - , public PP4Context
297   -{
298   - Q_OBJECT
299   -
300   - void project(const Template &src, Template &dst) const
301   - {
302   - if (!src.m().data) {
303   - dst += cv::Mat();
304   - return;
305   - }
306   -
307   - ppr_raw_image_type raw_image;
308   - createRawImage(src, raw_image);
309   - ppr_image_type image;
310   - TRY(ppr_create_image(raw_image, &image))
311   -
312   - ppr_object_type object = fromMetadata(src.file);
313   -
314   - ppr_template_type curr_template;
315   - TRY(ppr_extract_template_from_object(context, image, object, &curr_template))
316   -
317   - freeObject(object);
318   -
319   - cv::Mat m;
320   - createMat(curr_template, m);
321   - dst += m;
322   -
323   - ppr_free_template(curr_template);
324   - ppr_free_image(image);
325   - ppr_raw_image_free(raw_image);
326   - }
327   -};
328   -
329   -MM_REGISTER(Feature, PP4Enroll, "")
330   -
331   -
332   -class PP4Compare : public Comparer,
333   - public PP4Context
334   -{
335   - Q_OBJECT
336   -
337   - void compare(const TemplateList &target, const TemplateList &query, Output *output) const
338   - {
339   - ppr_gallery_type target_gallery, query_gallery;
340   - ppr_create_gallery(context, &target_gallery);
341   - ppr_create_gallery(context, &query_gallery);
342   - QList<int> target_template_ids, query_template_ids;
343   - enroll(target, &target_gallery, target_template_ids);
344   - enroll(query, &query_gallery, query_template_ids);
345   -
346   - ppr_similarity_matrix_type similarity_matrix;
347   - TRY(ppr_compare_galleries(context, query_gallery, target_gallery, &similarity_matrix))
348   -
349   - for (int i=0; i<query_template_ids.size(); i++) {
350   - int query_template_id = query_template_ids[i];
351   - for (int j=0; j<target_template_ids.size(); j++) {
352   - int target_template_id = target_template_ids[j];
353   - float score = -std::numeric_limits<float>::max();
354   - if ((query_template_id != -1) && (target_template_id != -1)) {
355   - TRY(ppr_get_similarity_matrix_element(context, similarity_matrix, query_template_id, target_template_id, &score))
356   - }
357   - output->setData(score, i, j);
358   - }
359   - }
360   -
361   - ppr_free_similarity_matrix(similarity_matrix);
362   - ppr_free_gallery(target_gallery);
363   - ppr_free_gallery(query_gallery);
364   - }
365   -
366   - void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &template_ids) const
367   - {
368   - foreach (const Template &t, templates) {
369   - if (t.m().data) {
370   - ppr_template_type u;
371   - createTemplate(t.m(), &u);
372   - int template_id;
373   - TRY(ppr_copy_template_to_gallery(context, gallery, u, &template_id))
374   - template_ids.append(template_id);
375   - ppr_free_template(u);
376   - } else {
377   - template_ids.append(-1);
378   - }
379   - }
380   - }
381   -};
382   -
383   -MM_REGISTER(Comparer, PP4Compare, "")
384   -
385   -#include "plugins/pp4.moc"
openbr/plugins/regions.cpp
... ... @@ -141,13 +141,15 @@ class CatColsTransform : public UntrainableMetaTransform
141 141  
142 142 void project(const Template &src, Template &dst) const
143 143 {
  144 + int half = src.size()/2;
  145 + for (int i=0; i<half; i++) {
  146 + Mat first = src[i];
  147 + Mat second = src[half+i];
  148 + Mat both;
  149 + hconcat(first, second, both);
  150 + dst.append(both);
  151 + }
144 152 dst.file = src.file;
145   - Mat m = OpenCVUtils::toMatByRow(src);
146   - // right now this just splits src in half and joins them horizontally
147   - // TODO: add partitions parameter for more than a single split
148   - Mat first = m.rowRange(Range(0, m.rows/2));
149   - Mat second = m.rowRange(Range(m.rows/2, m.rows));
150   - hconcat(first, second, dst);
151 153 }
152 154 };
153 155  
... ...
openbr/plugins/stasm4.cpp
... ... @@ -54,6 +54,9 @@ class StasmTransform : public UntrainableTransform
54 54 {
55 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 60 Resource<StasmCascadeClassifier> stasmCascadeResource;
58 61  
59 62 void init()
... ... @@ -69,14 +72,20 @@ class StasmTransform : public UntrainableTransform
69 72 StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire();
70 73  
71 74 int foundface;
  75 + int nLandmarks = stasm_NLANDMARKS;
72 76 float landmarks[2 * stasm_NLANDMARKS];
73 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 84 stasmCascadeResource.release(stasmCascade);
76 85  
77 86 if (!foundface) qWarning("No face found in %s", qPrintable(src.file.fileName()));
78 87 else {
79   - for (int i = 0; i < stasm_NLANDMARKS; i++)
  88 + for (int i = 0; i < nLandmarks; i++)
80 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 364 QMutex last_frame_update;
365 365 };
366 366  
  367 +static QMutex openLock;
367 368 // Read a video frame by frame using cv::VideoCapture
368 369 class VideoDataSource : public DataSource
369 370 {
... ... @@ -396,6 +397,8 @@ public:
396 397 // Yes, we should specify absolute path:
397 398 // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
398 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 402 video.open(QFileInfo(fileName).absoluteFilePath().toStdString());
400 403 }
401 404  
... ... @@ -707,8 +710,7 @@ public:
707 710 if (input == NULL) {
708 711 qFatal("null input to multi-thread stage");
709 712 }
710   - // Project the input we got
711   - transform->projectUpdate(input->data);
  713 + input->data >> *transform;
712 714  
713 715 should_continue = nextStage->tryAcquireNextStage(input);
714 716  
... ... @@ -1058,7 +1060,10 @@ public:
1058 1060 dst = src;
1059 1061  
1060 1062 bool res = readStage->dataSource.open(dst);
1061   - if (!res) return;
  1063 + if (!res) {
  1064 + qDebug("stream failed to open %s", qPrintable(dst[0].file.name));
  1065 + return;
  1066 + }
1062 1067  
1063 1068 // Start the first thread in the stream.
1064 1069 QWriteLocker lock(&readStage->statusLock);
... ... @@ -1300,6 +1305,7 @@ public:
1300 1305 {
1301 1306 if (!transform)
1302 1307 return;
  1308 +
1303 1309 trainable = transform->trainable;
1304 1310  
1305 1311 basis.setParent(this->parent());
... ...
openbr/plugins/topsurf.cmake deleted
1   -set(BR_WITH_TOPSURF OFF CACHE BOOL "Build with TOP-SURF")
2   -
3   -if(${BR_WITH_TOPSURF})
4   - find_package(TopSurf REQUIRED)
5   - set(THIRDPARTY_SRC ${THIRDPARTY_SRC} plugins/topsurf.cpp ${TOPSURF_SRC} ${TOPSURF_FLANN_SRC})
6   - install(DIRECTORY ${TOPSURF_DIR}/dictionary_10000
7   - ${TOPSURF_DIR}/dictionary_20000
8   - ${TOPSURF_DIR}/dictionary_40000
9   - DESTINATION models/topsurf)
10   -endif()
openbr/plugins/topsurf.cpp deleted
1   -#include <topsurf/descriptor.h>
2   -#include <topsurf/topsurf.h>
3   -#include <mm_plugin.h>
4   -
5   -#include "common/opencvutils.h"
6   -#include "common/qtutils.h"
7   -#include "common/resource.h"
8   -
9   -using namespace cv;
10   -using namespace mm;
11   -using namespace std;
12   -
13   -class TopSurfInitializer : public Initializer
14   -{
15   - void initialize() const
16   - {
17   - Globals.Abbreviations.insert("TopSurf", "Open!TopSurfExtract(40000):TopSurfCompare");
18   - Globals.Abbreviations.insert("TopSurfM", "Open!TopSurfExtract(1000000):TopSurfCompare");
19   - Globals.Abbreviations.insert("TopSurfKNN", "Open!TopSurfExtract+TopSurfKNN");
20   - Globals.Abbreviations.insert("DocumentClassification", "TopSurfKNN");
21   - }
22   -
23   - void finalize() const {}
24   -};
25   -
26   -MM_REGISTER(Initializer, TopSurfInitializer, false)
27   -
28   -
29   -class TopSurfResourceMaker : public ResourceMaker<TopSurf>
30   -{
31   - QString file;
32   -
33   -public:
34   - TopSurfResourceMaker(const QString &dictionary)
35   - {
36   - file = Globals.SDKPath + "/models/topsurf/dictionary_" + dictionary;
37   - }
38   -
39   -private:
40   - TopSurf *make() const
41   - {
42   - TopSurf *topSurf = new TopSurf(256, 100);
43   - if (!topSurf->LoadDictionary(qPrintable(file)))
44   - qFatal("TopSurfResourceMaker::make failed to load dictionary.");
45   - return topSurf;
46   - }
47   -};
48   -
49   -
50   -/****
51   -TopSurfExtract
52   - Wrapper to TopSurf::ExtractDescriptor()
53   - B. Thomee, E.M. Bakker, and M.S. Lew, "TOP-SURF: a visual words toolkit",
54   - in Proceedings of the 18th ACM International Conference on Multimedia, pp. 1473-1476, Firenze, Italy, 2010.
55   -****/
56   -class TopSurfExtract : public UntrainableFeature
57   -{
58   - Q_OBJECT
59   - Q_PROPERTY(QString dictionary READ get_dictionary WRITE set_dictionary)
60   - MM_MEMBER(QString, dictionary)
61   -
62   - Resource<TopSurf> topSurfResource;
63   -
64   -public:
65   - TopSurfExtract() : topSurfResource(new TopSurfResourceMaker("10000")) {}
66   -
67   -private:
68   - void init()
69   - {
70   - topSurfResource.setResourceMaker(new TopSurfResourceMaker(dictionary));
71   - }
72   -
73   - void project(const Template &src, Template &dst) const
74   - {
75   - // Compute descriptor (not thread safe)
76   - TopSurf *topSurf = topSurfResource.acquire();
77   - TOPSURF_DESCRIPTOR descriptor;
78   - IplImage iplSrc = src.m();
79   - if (!topSurf->ExtractDescriptor(iplSrc, descriptor))
80   - qFatal("TopSurfExtract::project ExtractDescriptor failure.");
81   - topSurfResource.release(topSurf);
82   -
83   - // Copy descriptor and clean up
84   - unsigned char *data;
85   - int length;
86   - Descriptor2Array(descriptor, data, length);
87   - Mat m(1, length, CV_8UC1);
88   - memcpy(m.data, data, length);
89   - delete data;
90   - TopSurf::ReleaseDescriptor(descriptor);
91   - dst = m;
92   - }
93   -
94   -public:
95   - static QString args()
96   - {
97   - return "10000|20000|40000 dictionary = 10000";
98   - }
99   -
100   - static TopSurfExtract *make(const QStringList &args)
101   - {
102   - (void) args;
103   - return new TopSurfExtract();
104   - }
105   -};
106   -
107   -MM_REGISTER(Feature, TopSurfExtract, true)
108   -
109   -
110   -class TopSurfHist : public UntrainableFeature
111   -{
112   - Q_OBJECT
113   - Q_PROPERTY(int size READ get_size WRITE set_size)
114   - MM_MEMBER(int, size)
115   -
116   - void project(const Template &src, Template &dst) const
117   - {
118   - TOPSURF_DESCRIPTOR td;
119   - Array2Descriptor(src.m().data, td);
120   -
121   - Mat m(1, size, CV_32FC1);
122   - m.setTo(0);
123   - for (int i=0; i<td.count; i++)
124   - m.at<float>(0, td.visualword[i].identifier % size)++;
125   -
126   - TopSurf::ReleaseDescriptor(td);
127   - dst = m;
128   - }
129   -
130   -public:
131   - static QString args()
132   - {
133   - return "int size = 10000";
134   - }
135   -
136   - static TopSurfHist *make(const QStringList &args)
137   - {
138   - (void) args;
139   - return new TopSurfHist();
140   - }
141   -};
142   -
143   -MM_REGISTER(Feature, TopSurfHist, true)
144   -
145   -
146   -// Wrapper around TopSurf CompareDescriptors
147   -float TopSurfSimilarity(const Mat &a, const Mat &b, bool cosine)
148   -{
149   - TOPSURF_DESCRIPTOR tda, tdb;
150   - Array2Descriptor(a.data, tda);
151   - Array2Descriptor(b.data, tdb);
152   -
153   - float result;
154   - if (cosine) result = TopSurf::CompareDescriptorsCosine(tda, tdb);
155   - else result = TopSurf::CompareDescriptorsAbsolute(tda, tdb);
156   -
157   - TopSurf::ReleaseDescriptor(tda);
158   - TopSurf::ReleaseDescriptor(tdb);
159   - return result;
160   -}
161   -
162   -
163   -/****
164   -TopSurfCompare
165   - Wrapper to TopSurf_CompareDescriptors()
166   - B. Thomee, E.M. Bakker, and M.S. Lew, "TOP-SURF: a visual words toolkit",
167   - in Proceedings of the 18th ACM International Conference on Multimedia, pp. 1473-1476, Firenze, Italy, 2010.
168   -****/
169   -class TopSurfCompare : public ComparerBase
170   -{
171   - Q_OBJECT
172   - Q_PROPERTY(bool cosine READ get_cosine WRITE set_cosine)
173   - MM_MEMBER(bool, cosine)
174   -
175   - float compare(const Mat &a, const Mat &b) const
176   - {
177   - return TopSurfSimilarity(a, b, cosine);
178   - }
179   -
180   -public:
181   - static QString args()
182   - {
183   - return "bool cosine = 1";
184   - }
185   -
186   - static TopSurfCompare *make(const QStringList &args)
187   - {
188   - (void) args;
189   - return new TopSurfCompare();
190   - }
191   -};
192   -
193   -MM_REGISTER(Comparer, TopSurfCompare, true)
194   -
195   -
196   -/****
197   -TopSurfKNN
198   - KNN classifier for TopSurf features.
199   -****/
200   -class TopSurfKNN : public Feature
201   -{
202   - Q_OBJECT
203   - Q_PROPERTY(int k READ get_k WRITE set_k)
204   - Q_PROPERTY(bool cosine READ get_cosine WRITE set_cosine)
205   - MM_MEMBER(int, k)
206   - MM_MEMBER(bool, cosine)
207   -
208   - TemplateList data;
209   -
210   -private:
211   - void train(const TemplateList &data)
212   - {
213   - this->data = data;
214   - }
215   -
216   - void project(const Template &src, Template &dst) const
217   - {
218   - // Compute distance to each descriptor
219   - QList< QPair<float, int> > distances; // <distance, label>
220   - distances.reserve(data.size());
221   - foreach (const Template &t, data)
222   - distances.append(QPair<float, int>(TopSurfSimilarity(src, t, cosine), t.file.label()));
223   -
224   - // Find nearest neighbors
225   - qSort(distances);
226   - QHash<int, QPair<int, float> > counts; // <label, <count, cumulative distance>>
227   - for (int i=0; i<k; i++) {
228   - QPair<float,int> &distance = distances[i];
229   - QPair<int,float> &count = counts[distance.second];
230   - count.first++;
231   - count.second += distance.first;
232   - }
233   -
234   - // Find most occuring label
235   - int best_label = -1;
236   - int best_count = 0;
237   - float best_distance = numeric_limits<float>::max();
238   - foreach (int label, counts.keys()) {
239   - const QPair<int, float> &count = counts[label];
240   - if ((count.first > best_count) || ((count.first == best_count) && (count.second < best_distance))) {
241   - best_label = label;
242   - best_count = count.first;
243   - best_distance = count.second;
244   - }
245   - }
246   - assert(best_label != -1);
247   -
248   - // Measure confidence
249   - int rest_count = 0;
250   - float rest_distance = 0;
251   - foreach (int label, counts.keys()) {
252   - if (label != best_label) {
253   - const QPair<int, float> &count = counts[label];
254   - rest_count = count.first;
255   - rest_distance = count.second;
256   - }
257   - }
258   -
259   - dst = src;
260   - dst.file["Label"] = best_label;
261   - dst.file["Confidence"] = (float)best_count/(float)k;
262   - }
263   -
264   - void store(QDataStream &stream) const
265   - {
266   - stream << data;
267   - }
268   -
269   - void load(QDataStream &stream)
270   - {
271   - stream >> data;
272   - }
273   -
274   -public:
275   - static QString args()
276   - {
277   - return "int k, int cosine = 1";
278   - }
279   -
280   - static TopSurfKNN *make(const QStringList &args)
281   - {
282   - (void) args;
283   - return new TopSurfKNN();
284   - }
285   -};
286   -
287   -MM_REGISTER(Feature, TopSurfKNN, true)
288   -
289   -#include "topsurf.moc"
openbr/plugins/validate.cpp
... ... @@ -19,9 +19,9 @@ class CrossValidateTransform : public MetaTransform
19 19 {
20 20 Q_OBJECT
21 21 Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
22   - Q_PROPERTY(bool leaveOneOut READ get_leaveOneOut WRITE set_leaveOneOut RESET reset_leaveOneOut STORED false)
  22 + Q_PROPERTY(bool leaveOneImageOut READ get_leaveOneImageOut WRITE set_leaveOneImageOut RESET reset_leaveOneImageOut STORED false)
23 23 BR_PROPERTY(QString, description, "Identity")
24   - BR_PROPERTY(bool, leaveOneOut, false)
  24 + BR_PROPERTY(bool, leaveOneImageOut, false)
25 25  
26 26 QList<br::Transform*> transforms;
27 27  
... ... @@ -49,10 +49,10 @@ class CrossValidateTransform : public MetaTransform
49 49 int j = partitionedData.size()-1;
50 50 while (j>=0) {
51 51 // Remove all templates belonging to partition i
52   - // if leaveOneOut is true,
  52 + // if leaveOneImageOut is true,
53 53 // and i is greater than the number of images for a particular subject
54 54 // even if the partitions are different
55   - if (leaveOneOut) {
  55 + if (leaveOneImageOut) {
56 56 const QString label = partitionedData.at(j).file.get<QString>("Label");
57 57 QList<int> subjectIndices = partitionedData.find("Label",label);
58 58 QList<int> removed;
... ... @@ -80,6 +80,7 @@ class CrossValidateTransform : public MetaTransform
80 80 }
81 81 } else if (partitions[j] == i) {
82 82 partitionedData.removeAt(j);
  83 + j--;
83 84 } else j--;
84 85 }
85 86 // Train on the remaining templates
... ...
openbr/plugins/yubico.cmake deleted
1   -set(BR_WITH_YUBICO OFF CACHE BOOL "Build YubiKey authentication")
2   -
3   -if(${BR_WITH_YUBICO})
4   - find_package(YubiKey REQUIRED) # For decrypting YubiKeys
5   - find_package(YKPers REQUIRED) # For reading YubiKeys
6   -
7   - install(FILES ${YUBIKEY_LICENSE} RENAME YubiKey DESTINATION share/openbr/licenses)
8   - install(FILES ${YKPERS_LICENSE} RENAME YKPers DESTINATION share/openbr/licenses)
9   - install(FILES ${YKPERS_RULES} DESTINATION share/openbr)
10   -
11   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${YUBIKEY_SRC} ${YKPERS_SRC} plugins/yubico.cpp)
12   - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${YKPERS_LIBS})
13   -endif()
openbr/plugins/yubico.cpp deleted
1   -#include <mm_plugin.h>
2   -#include <yubikey.h>
3   -#include <ykdef.h>
4   -#include <ykpers.h>
5   -#include <stdlib.h>
6   -#include <time.h>
7   -
8   -/****
9   -YubiKey Challenge-Response Authentication
10   -
11   -To configure YubiKeys for mm usage:
12   -1) Download the cross platform personalization tool from http://yubico.com/personalization-tool.
13   -2) Insert YubiKey and launch the personalization tool (may require sudo access).
14   -3) Click "Challenge-Response Mode".
15   -4) Click "Yubico OTP".
16   -5) Select "Configuration Slot 2"
17   -6) In the Private Identity text box enter "21 92 78 11 55 8a".
18   -7) In the Secret Key text box enter "e7 32 df 49 f3 87 e6 89 04 d2 03 6a 59 ad b7 2f".
19   -8) Click "Write Configuration".
20   -9) Done!
21   -
22   -Unix implementation derived from "ykchalresp.c" in ykpers repository.
23   -Windows implementation derived from "MFCTestDlg.cpp" in Yubikey Client API installer.
24   -
25   -!!! Attention Linux Users !!!
26   -cp trunk/3rdparty/ykpers-1.6.3/70-yubikey.rules /etc/udev/rules.d
27   -
28   -!!! Attention Windows Users !!!
29   -Install Yubikey Client API.
30   -****/
31   -
32   -using namespace mm;
33   -
34   -static int challenge_response(YK_KEY *yk, int slot,
35   - unsigned char *challenge, unsigned int len,
36   - bool hmac, bool may_block, bool verbose, unsigned char output_buf[(SHA1_MAX_BLOCK_SIZE * 2) + 1])
37   -{
38   - unsigned char response[64];
39   - int yk_cmd;
40   - unsigned int flags = 0;
41   - unsigned int response_len = 0;
42   - unsigned int expect_bytes = 0;
43   -
44   - memset(response, 0, sizeof(response));
45   -
46   - if (may_block)
47   - flags |= YK_FLAG_MAYBLOCK;
48   -
49   - if (verbose) {
50   - fprintf(stderr, "Sending %i bytes %s challenge to slot %i\n", len, (hmac == true) ? "HMAC" : "Yubico", slot);
51   - //_yk_hexdump(challenge, len);
52   - }
53   -
54   - switch(slot) {
55   - case 1:
56   - yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC1 : SLOT_CHAL_OTP1;
57   - break;
58   - case 2:
59   - yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC2 : SLOT_CHAL_OTP2;
60   - break;
61   - }
62   -
63   - if (!yk_write_to_key(yk, yk_cmd, challenge, len))
64   - return 0;
65   -
66   - if (verbose) {
67   - fprintf(stderr, "Reading response...\n");
68   - }
69   -
70   - /* HMAC responses are 160 bits, Yubico 128 */
71   - expect_bytes = (hmac == true) ? 20 : 16;
72   -
73   - if (! yk_read_response_from_key(yk, slot, flags,
74   - &response, sizeof(response),
75   - expect_bytes,
76   - &response_len))
77   - return 0;
78   -
79   - if (hmac && response_len > 20)
80   - response_len = 20;
81   - if (! hmac && response_len > 16)
82   - response_len = 16;
83   -
84   - memset(output_buf, 0, SHA1_MAX_BLOCK_SIZE * 2 + 1);
85   - if (hmac) {
86   - yubikey_hex_encode((char *)output_buf, (char *)response, response_len);
87   - } else {
88   - yubikey_modhex_encode((char *)output_buf, (char *)response, response_len);
89   - }
90   - // printf("%s\n", output_buf);
91   -
92   - return 1;
93   -}
94   -
95   -/*!
96   - * \ingroup initializers
97   - * \brief Initialize yubikey
98   - * \author Josh Klontz \cite jklontz
99   - */
100   -class YubiKey : public Initializer
101   -{
102   - Q_OBJECT
103   -
104   - void initialize() const
105   - {
106   - // Read from device
107   - YK_KEY *yk = 0;
108   -
109   - if (!yk_init())
110   - qFatal("YubiKey::initialize yk_init failure.");
111   -
112   - if (!(yk = yk_open_first_key()))
113   - qFatal("Could not connect to license.");
114   -
115   - // Challenge value is arbitrary
116   - srand(time(NULL));
117   - uint8_t challenge[6] = {rand()%255, rand()%255, rand()%255, rand()%255, rand()%255, rand()%255};
118   - unsigned char output_buf[(SHA1_MAX_BLOCK_SIZE * 2) + 1];
119   - if (!challenge_response(yk, 2, challenge, 6, false, true, false, output_buf))
120   - qFatal("YubiKey::initialize challenge_response failure.");
121   -
122   - if (yk && !yk_close_key(yk))
123   - qFatal("YubiKey::initialize yk_close_key failure.");
124   -
125   - if (!yk_release())
126   - qFatal("YubiKey::initialize yk_release failure.");
127   -
128   - // Check response
129   - // Our Secret Key! Shhh...
130   - const uint8_t key[YUBIKEY_KEY_SIZE] = {0xe7, 0x32, 0xdf, 0x49, 0xf3, 0x87, 0xe6, 0x89, 0x04, 0xd2, 0x03, 0x6a, 0x59, 0xad, 0xb7, 0x2f};
131   - yubikey_token_st out;
132   - yubikey_parse(output_buf, key, &out);
133   -
134   - // Our Private Identity! Shhh...
135   - uint8_t uid[YUBIKEY_UID_SIZE] = {0x21, 0x92, 0x78, 0x11, 0x55, 0x8a};
136   - if ((uid[0] != (out.uid[0] ^ challenge[0])) ||
137   - (uid[1] != (out.uid[1] ^ challenge[1])) ||
138   - (uid[2] != (out.uid[2] ^ challenge[2])) ||
139   - (uid[3] != (out.uid[3] ^ challenge[3])) ||
140   - (uid[4] != (out.uid[4] ^ challenge[4])) ||
141   - (uid[5] != (out.uid[5] ^ challenge[5])))
142   - qFatal("Invalid license.");
143   - }
144   -
145   - void finalize() const
146   - {
147   - // Nothing to do
148   - }
149   -};
150   -
151   -MM_REGISTER(Initializer,YubiKey,"")
152   -
153   -#include "yubico.moc"
share/openbr/cmake/FindCT8.cmake deleted
1   -# ================================================================
2   -# The CT8 CMake configuration file
3   -#
4   -# Usage from an external project:
5   -# In your CMakeLists.txt, add these lines:
6   -#
7   -# find_package(CT8 REQUIRED)
8   -# target_link_libraries(MY_TARGET ${CT8_LIBS})
9   -# ================================================================
10   -
11   -set(CT8_DIR "CT8_DIR-NOTFOUND" CACHE PATH "Cognitec FaceVACS 8.x directory")
12   -
13   -
14   -if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
15   - set(ARCH_STRING x86_64)
16   -else("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
17   - set(ARCH_STRING x86_32)
18   -endif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
19   -
20   -if(DEFINED MSVC80)
21   - set(COMP_DIR_EXT "msc_8.0-ipp_crtdll")
22   -elseif(DEFINED MSVC90)
23   - set(COMP_DIR_EXT "msc_9.0-ipp_crtdll")
24   -elseif(DEFINED MSVC10)
25   - set(COMP_DIR_EXT "msc_10.0-ipp_crtdll")
26   -elseif(CMAKE_HOST_APPLE)
27   - set(COMP_DIR_EXT "gcc-4.2-ipp")
28   -else()
29   - set(COMP_DIR_EXT "gcc-4.3-ipp")
30   -endif()
31   -
32   -set(CT8_DIR_LIB ${CT8_DIR}/lib/${ARCH_STRING}/${COMP_DIR_EXT} )
33   -set(CT8_LIBRARY_RELEASE libfrsdk-8.6.0)
34   -set(CT8_LIBRARY_DEBUG libfrsdk-8.6.0d)
35   -
36   -include_directories(${CT8_DIR}/include)
37   -link_directories(${CT8_DIR_LIB} ${CT8_DIR_LIB}_g)
share/openbr/cmake/FindFST3.cmake deleted
1   -find_path(FST3_DIR _src_criteria/classifier.hpp ${CMAKE_SOURCE_DIR}/3rdparty/*)
2   -mark_as_advanced(FST3_DIR)
3   -include_directories(${FST3_DIR}/_src_criteria ${FST3_DIR}/_src_dataio ${FST3_DIR}/_src_global ${FST3_DIR}/_src_search)
4   -set(FST3_SRC ${FST3_DIR}/_src_global/global.cpp)
share/openbr/cmake/FindPP4.cmake deleted
1   -# ================================================================
2   -# The PP4 CMake configuration file
3   -#
4   -# Usage from an external project:
5   -# In your CMakeLists.txt, add these lines:
6   -#
7   -# find_package(PP4 REQUIRED)
8   -# target_link_libraries(MY_TARGET ${PP4_LIBS})
9   -# ================================================================
10   -
11   -find_path(PP4_DIR include/pittpatt_nc_sdk.h ${CMAKE_SOURCE_DIR}/3rdparty/*)
12   -include_directories(${PP4_DIR}/include)
13   -link_directories(${PP4_DIR}/lib)
14   -set(PP4_LIBS pittpatt_nc_sdk
15   - pittpatt_raw_image
16   - pittpatt_raw_image_io
17   - pittpatt_recognition_core
18   - pittpatt_video_io)
share/openbr/cmake/FindTopSurf.cmake deleted
1   -find_path(TOPSURF_DIR topsurf/topsurf.h ${CMAKE_SOURCE_DIR}/3rdparty/*)
2   -mark_as_advanced(TOPSURF_DIR)
3   -include_directories(${TOPSURF_DIR})
4   -aux_source_directory(${TOPSURF_DIR}/topsurf TOPSURF_SRC)
5   -aux_source_directory(${TOPSURF_DIR}/topsurf/flann TOPSURF_FLANN_SRC)
share/openbr/cmake/FindYubiKey.cmake deleted
1   -find_path(YUBIKEY_DIR yubikey.h ${CMAKE_SOURCE_DIR}/3rdparty/*)
2   -mark_as_advanced(YUBIKEY_DIR)
3   -include_directories(${YUBIKEY_DIR})
4   -if(MSVC)
5   - include_directories(${YUBIKEY_DIR}/stdbool)
6   -endif()
7   -
8   -if(NOT TARGET yubikey)
9   - set(YUBIKEY_SRC ${YUBIKEY_DIR}/ykaes.c ${YUBIKEY_DIR}/ykcrc.c ${YUBIKEY_DIR}/ykhex.c ${YUBIKEY_DIR}/ykmodhex.c ${YUBIKEY_DIR}/yktoken.c)
10   - if(WIN32)
11   - set_source_files_properties(${YUBIKEY_SRC} PROPERTIES LANGUAGE CXX)
12   - endif()
13   -endif()
14   -
15   -set(YUBIKEY_LICENSE ${YUBIKEY_DIR}/COPYING)
share/openbr/cmake/FindpHash.cmake deleted
1   -find_path(PHASH_DIR src/pHash.h ${CMAKE_SOURCE_DIR}/3rdparty/*)
2   -mark_as_advanced(PHASH_DIR)
3   -include_directories(${PHASH_DIR} ${PHASH_DIR}/src)
4   -set(PHASH_SRC ${PHASH_DIR}/src/pHash.cpp ${PHASH_DIR}/src/ph_fft.c)
1   -Subproject commit dccddf4dd3a5239911807beeec39308f8890b1e4
  1 +Subproject commit a73d51013ea05f263e88a28539393159fff2183e
... ...