Commit 3320ddac1be46c8fa1ee0372efca9d5f46034aa2

Authored by Scott Klum
2 parents e443d224 0e37f1a9

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

1 -Subproject commit 50452eccc85ed3092fd6b915f4dc52498e825c02 1 +Subproject commit e8e79d30eb6bce6e295837179dbf4544c78739b5
openbr/core/classify.cpp
@@ -14,8 +14,6 @@ @@ -14,8 +14,6 @@
14 * limitations under the License. * 14 * limitations under the License. *
15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16
17 -#include <QDebug>  
18 -#include <QHash>  
19 #include <openbr/openbr_plugin.h> 17 #include <openbr/openbr_plugin.h>
20 18
21 #include "classify.h" 19 #include "classify.h"
@@ -24,7 +22,7 @@ @@ -24,7 +22,7 @@
24 // Helper struct for statistics accumulation 22 // Helper struct for statistics accumulation
25 struct Counter 23 struct Counter
26 { 24 {
27 - int truePositive, falsePositive, falseNegative; 25 + float truePositive, falsePositive, falseNegative;
28 Counter() 26 Counter()
29 { 27 {
30 truePositive = 0; 28 truePositive = 0;
@@ -41,35 +39,44 @@ void br::EvalClassification(const QString &amp;predictedInput, const QString &amp;truthI @@ -41,35 +39,44 @@ void br::EvalClassification(const QString &amp;predictedInput, const QString &amp;truthI
41 TemplateList truth(TemplateList::fromGallery(truthInput)); 39 TemplateList truth(TemplateList::fromGallery(truthInput));
42 if (predicted.size() != truth.size()) qFatal("Input size mismatch."); 40 if (predicted.size() != truth.size()) qFatal("Input size mismatch.");
43 41
44 - QHash<int, Counter> counters; 42 + QHash<QString, Counter> counters;
45 for (int i=0; i<predicted.size(); i++) { 43 for (int i=0; i<predicted.size(); i++) {
46 if (predicted[i].file.name != truth[i].file.name) 44 if (predicted[i].file.name != truth[i].file.name)
47 qFatal("Input order mismatch."); 45 qFatal("Input order mismatch.");
48 46
49 - const int trueLabel = truth[i].file.label();  
50 - const int predictedLabel = predicted[i].file.label();  
51 - if (trueLabel == predictedLabel) {  
52 - counters[trueLabel].truePositive++;  
53 - } else {  
54 - counters[trueLabel].falseNegative++;  
55 - counters[predictedLabel].falsePositive++; 47 + // Typically these lists will be of length one, but this generalization allows measuring multi-class labeling accuracy.
  48 + QStringList predictedSubjects = predicted[i].file.get<QStringList>("Subject");
  49 + QStringList trueSubjects = truth[i].file.get<QStringList>("Subject");
  50 + foreach (const QString &subject, trueSubjects.toVector() /* Hack to copy the list. */) {
  51 + if (predictedSubjects.contains(subject)) {
  52 + counters[subject].truePositive++;
  53 + trueSubjects.removeOne(subject);
  54 + predictedSubjects.removeOne(subject);
  55 + } else {
  56 + counters[subject].falseNegative++;
  57 + }
56 } 58 }
  59 +
  60 + for (int i=0; i<trueSubjects.size(); i++)
  61 + foreach (const QString &subject, predictedSubjects)
  62 + counters[subject].falsePositive += 1.f / predictedSubjects.size();
57 } 63 }
58 64
59 QSharedPointer<Output> output(Output::make("", FileList() << "Subject" << "Count" << "Precision" << "Recall" << "F-score", FileList(counters.size()))); 65 QSharedPointer<Output> output(Output::make("", FileList() << "Subject" << "Count" << "Precision" << "Recall" << "F-score", FileList(counters.size())));
60 66
61 int tpc = 0; 67 int tpc = 0;
62 int fnc = 0; 68 int fnc = 0;
  69 + const QStringList keys = counters.keys();
63 for (int i=0; i<counters.size(); i++) { 70 for (int i=0; i<counters.size(); i++) {
64 - int trueLabel = counters.keys()[i];  
65 - const Counter &counter = counters[trueLabel]; 71 + const QString &subject = keys[i];
  72 + const Counter &counter = counters[subject];
66 tpc += counter.truePositive; 73 tpc += counter.truePositive;
67 fnc += counter.falseNegative; 74 fnc += counter.falseNegative;
68 const int count = counter.truePositive + counter.falseNegative; 75 const int count = counter.truePositive + counter.falseNegative;
69 const float precision = counter.truePositive / (float)(counter.truePositive + counter.falsePositive); 76 const float precision = counter.truePositive / (float)(counter.truePositive + counter.falsePositive);
70 const float recall = counter.truePositive / (float)(counter.truePositive + counter.falseNegative); 77 const float recall = counter.truePositive / (float)(counter.truePositive + counter.falseNegative);
71 const float fscore = 2 * precision * recall / (precision + recall); 78 const float fscore = 2 * precision * recall / (precision + recall);
72 - output->setRelative(trueLabel, i, 0); 79 + output->setRelative(File("", subject).label(), i, 0);
73 output->setRelative(count, i, 1); 80 output->setRelative(count, i, 1);
74 output->setRelative(precision, i, 2); 81 output->setRelative(precision, i, 2);
75 output->setRelative(recall, i, 3); 82 output->setRelative(recall, i, 3);
openbr/core/common.h
@@ -102,7 +102,7 @@ void MinMax(const QList&lt;T&gt; &amp;vals, T *min, T *max) @@ -102,7 +102,7 @@ void MinMax(const QList&lt;T&gt; &amp;vals, T *min, T *max)
102 template <typename T> 102 template <typename T>
103 T Min(const QList<T> &vals) 103 T Min(const QList<T> &vals)
104 { 104 {
105 - int min, max; 105 + T min, max;
106 MinMax(vals, &min, &max); 106 MinMax(vals, &min, &max);
107 return min; 107 return min;
108 } 108 }
@@ -110,7 +110,7 @@ T Min(const QList&lt;T&gt; &amp;vals) @@ -110,7 +110,7 @@ T Min(const QList&lt;T&gt; &amp;vals)
110 template <typename T> 110 template <typename T>
111 T Max(const QList<T> &vals) 111 T Max(const QList<T> &vals)
112 { 112 {
113 - int min, max; 113 + T min, max;
114 MinMax(vals, &min, &max); 114 MinMax(vals, &min, &max);
115 return max; 115 return max;
116 } 116 }
openbr/core/opencvutils.cpp
@@ -157,6 +157,26 @@ Mat OpenCVUtils::toMatByRow(const QList&lt;Mat&gt; &amp;src) @@ -157,6 +157,26 @@ Mat OpenCVUtils::toMatByRow(const QList&lt;Mat&gt; &amp;src)
157 return dst; 157 return dst;
158 } 158 }
159 159
  160 +QString OpenCVUtils::depthToString(const Mat &m)
  161 +{
  162 + switch (m.depth()) {
  163 + case CV_8U: return "8U";
  164 + case CV_8S: return "8S";
  165 + case CV_16U: return "16U";
  166 + case CV_16S: return "16S";
  167 + case CV_32S: return "32S";
  168 + case CV_32F: return "32F";
  169 + case CV_64F: return "64F";
  170 + default: qFatal("Unknown matrix depth!");
  171 + }
  172 + return "?";
  173 +}
  174 +
  175 +QString OpenCVUtils::typeToString(const cv::Mat &m)
  176 +{
  177 + return depthToString(m) + "C" + QString::number(m.channels());
  178 +}
  179 +
160 QString OpenCVUtils::elemToString(const Mat &m, int r, int c) 180 QString OpenCVUtils::elemToString(const Mat &m, int r, int c)
161 { 181 {
162 assert(m.channels() == 1); 182 assert(m.channels() == 1);
openbr/core/opencvutils.h
@@ -39,6 +39,8 @@ namespace OpenCVUtils @@ -39,6 +39,8 @@ namespace OpenCVUtils
39 cv::Mat toMatByRow(const QList<cv::Mat> &src); // Data organized one row per row 39 cv::Mat toMatByRow(const QList<cv::Mat> &src); // Data organized one row per row
40 40
41 // From image 41 // From image
  42 + QString depthToString(const cv::Mat &m);
  43 + QString typeToString(const cv::Mat &m);
42 QString elemToString(const cv::Mat &m, int r, int c); 44 QString elemToString(const cv::Mat &m, int r, int c);
43 QString matrixToString(const cv::Mat &m); 45 QString matrixToString(const cv::Mat &m);
44 QStringList matrixToStringList(const cv::Mat &m); 46 QStringList matrixToStringList(const cv::Mat &m);
openbr/openbr_plugin.cpp
@@ -923,24 +923,20 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte @@ -923,24 +923,20 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
923 { 923 {
924 // Something about this method is not thread safe, and will lead to crashes if qDebug 924 // Something about this method is not thread safe, and will lead to crashes if qDebug
925 // statements are called from multiple threads. Unless we lock the whole thing... 925 // statements are called from multiple threads. Unless we lock the whole thing...
926 - static QMutex generalLock(QMutex::Recursive); 926 + static QMutex generalLock;
927 QMutexLocker locker(&generalLock); 927 QMutexLocker locker(&generalLock);
928 928
929 QString txt; 929 QString txt;
930 - switch (type) {  
931 - case QtDebugMsg: 930 + if (type == QtDebugMsg) {
932 if (Globals->quiet) return; 931 if (Globals->quiet) return;
933 txt = QString("%1\n").arg(msg); 932 txt = QString("%1\n").arg(msg);
934 - break;  
935 - case QtWarningMsg:  
936 - txt = QString("Warning: %1\n").arg(msg);  
937 - break;  
938 - case QtCriticalMsg:  
939 - txt = QString("Critical: %1\n").arg(msg);  
940 - break;  
941 - case QtFatalMsg:  
942 - txt = QString("Fatal: %1\n").arg(msg);  
943 - break; 933 + } else {
  934 + switch (type) {
  935 + case QtWarningMsg: txt = QString("Warning: %1\n" ).arg(msg); break;
  936 + case QtCriticalMsg: txt = QString("Critical: %1\n").arg(msg); break;
  937 + default: txt = QString("Fatal: %1\n" ).arg(msg);
  938 + }
  939 + txt += " File: " + QString(context.file) + "\n Function: " + QString(context.function) + "\n Line: " + QString::number(context.line) + "\n";
944 } 940 }
945 941
946 std::cerr << txt.toStdString(); 942 std::cerr << txt.toStdString();
@@ -951,11 +947,8 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte @@ -951,11 +947,8 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
951 Globals->logFile.flush(); 947 Globals->logFile.flush();
952 } 948 }
953 949
954 - if (type == QtFatalMsg) {  
955 - // Write debug output then close  
956 - qDebug(" File: %s\n Function: %s\n Line: %d", qPrintable(context.file), qPrintable(context.function), context.line);  
957 - Globals->finalize();  
958 - } 950 + if (type == QtFatalMsg)
  951 + abort(); // We abort so we can get a stack trace back to the code that triggered the message.
959 } 952 }
960 953
961 Context *br::Globals = NULL; 954 Context *br::Globals = NULL;
@@ -1027,7 +1020,7 @@ MatrixOutput *MatrixOutput::make(const FileList &amp;targetFiles, const FileList &amp;qu @@ -1027,7 +1020,7 @@ MatrixOutput *MatrixOutput::make(const FileList &amp;targetFiles, const FileList &amp;qu
1027 /* MatrixOutput - protected methods */ 1020 /* MatrixOutput - protected methods */
1028 QString MatrixOutput::toString(int row, int column) const 1021 QString MatrixOutput::toString(int row, int column) const
1029 { 1022 {
1030 - if (targetFiles[column] == "Label") { 1023 + if (targetFiles[column] == "Subject") {
1031 const int label = data.at<float>(row,column); 1024 const int label = data.at<float>(row,column);
1032 return Globals->subjects.key(label, QString::number(label)); 1025 return Globals->subjects.key(label, QString::number(label));
1033 } 1026 }
openbr/plugins/algorithms.cpp
@@ -50,6 +50,7 @@ class AlgorithmsInitializer : public Initializer @@ -50,6 +50,7 @@ class AlgorithmsInitializer : public Initializer
50 Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); 50 Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
51 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); 51 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)");
52 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)!EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); 52 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)!EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2");
  53 + Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+Bin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Singleton(KMeans(256)))+Cat+CvtFloat+Hist(256)+KNN(5,Dist(L1),false,5)+Rename(KNN,Subject)");
53 54
54 // Hash 55 // Hash
55 Globals->abbreviations.insert("FileName", "Name+Identity:Identical"); 56 Globals->abbreviations.insert("FileName", "Name+Identity:Identical");
openbr/plugins/cluster.cpp
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 #include <opencv2/flann/flann.hpp> 17 #include <opencv2/flann/flann.hpp>
18 18
19 #include "openbr_internal.h" 19 #include "openbr_internal.h"
  20 +#include "openbr/core/common.h"
20 #include "openbr/core/opencvutils.h" 21 #include "openbr/core/opencvutils.h"
21 22
22 using namespace cv; 23 using namespace cv;
@@ -76,6 +77,68 @@ class KMeansTransform : public Transform @@ -76,6 +77,68 @@ class KMeansTransform : public Transform
76 77
77 BR_REGISTER(Transform, KMeansTransform) 78 BR_REGISTER(Transform, KMeansTransform)
78 79
79 -} 80 +/*!
  81 + * \ingroup transforms
  82 + * \brief K nearest neighbors classifier.
  83 + * \author Josh Klontz \cite jklontz
  84 + */
  85 +class KNNTransform : public Transform
  86 +{
  87 + Q_OBJECT
  88 + Q_PROPERTY(int k READ get_k WRITE set_k RESET reset_k STORED false)
  89 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  90 + Q_PROPERTY(bool weighted READ get_weighted WRITE set_weighted RESET reset_weighted STORED false)
  91 + Q_PROPERTY(int numSubjects READ get_numSubjects WRITE set_numSubjects RESET reset_numSubjects STORED false)
  92 + BR_PROPERTY(int, k, 1)
  93 + BR_PROPERTY(br::Distance*, distance, NULL)
  94 + BR_PROPERTY(bool, weighted, false)
  95 + BR_PROPERTY(int, numSubjects, 1)
  96 +
  97 + TemplateList gallery;
  98 +
  99 + void train(const TemplateList &data)
  100 + {
  101 + distance->train(data);
  102 + gallery = data;
  103 + }
  104 +
  105 + void project(const Template &src, Template &dst) const
  106 + {
  107 + QList< QPair<float, int> > sortedScores = Common::Sort(distance->compare(gallery, src), true);
  108 +
  109 + QStringList subjects;
  110 + for (int i=0; i<numSubjects; i++) {
  111 + QHash<QString, float> votes;
  112 + const int max = (k < 1) ? sortedScores.size() : std::min(k, sortedScores.size());
  113 + for (int j=0; j<max; j++)
  114 + votes[gallery[sortedScores[j].second].file.subject()] += (weighted ? sortedScores[j].first : 1);
  115 + subjects.append(votes.keys()[votes.values().indexOf(Common::Max(votes.values()))]);
  116 +
  117 + // Remove subject from consideration
  118 + if (subjects.size() < numSubjects)
  119 + for (int j=sortedScores.size()-1; j>=0; j--)
  120 + if (gallery[sortedScores[j].second].file.subject() == subjects.last())
  121 + sortedScores.removeAt(j);
  122 + }
  123 +
  124 + dst.file.set("KNN", subjects.size() > 1 ? "[" + subjects.join(",") + "]" : subjects.first());
  125 + }
  126 +
  127 + void store(QDataStream &stream) const
  128 + {
  129 + stream << gallery;
  130 + }
  131 +
  132 + void load(QDataStream &stream)
  133 + {
  134 + stream >> gallery;
  135 + }
  136 +};
  137 +
  138 +BR_REGISTER(Transform, KNNTransform)
  139 +
  140 +
  141 +
  142 +} // namespace br
80 143
81 #include "cluster.moc" 144 #include "cluster.moc"
openbr/plugins/crop.cpp
@@ -151,6 +151,48 @@ class CropBlackTransform : public UntrainableTransform @@ -151,6 +151,48 @@ class CropBlackTransform : public UntrainableTransform
151 151
152 BR_REGISTER(Transform, CropBlackTransform) 152 BR_REGISTER(Transform, CropBlackTransform)
153 153
  154 +/*!
  155 + * \ingroup transforms
  156 + * \brief Divide the matrix into 4 smaller matricies of equal size.
  157 + * \author Josh Klontz \cite jklontz
  158 + */
  159 +class SubdivideTransform : public UntrainableTransform
  160 +{
  161 + Q_OBJECT
  162 +
  163 + void project(const Template &src, Template &dst) const
  164 + {
  165 + const Mat &m = src;
  166 + const int subrows = m.rows/2;
  167 + const int subcolumns = m.cols/2;
  168 + dst.append(Mat(m,Rect(0, 0, subcolumns, subrows)).clone());
  169 + dst.append(Mat(m,Rect(subcolumns, 0, subcolumns, subrows)).clone());
  170 + dst.append(Mat(m,Rect(0, subrows, subcolumns, subrows)).clone());
  171 + dst.append(Mat(m,Rect(subcolumns, subrows, subcolumns, subrows)).clone());
  172 + }
  173 +};
  174 +
  175 +BR_REGISTER(Transform, SubdivideTransform)
  176 +
  177 +/*!
  178 + * \ingroup transforms
  179 + * \brief Trim the image so the width and the height are the same size.
  180 + * \author Josh Klontz \cite jklontz
  181 + */
  182 +class CropSquareTransform : public UntrainableTransform
  183 +{
  184 + Q_OBJECT
  185 +
  186 + void project(const Template &src, Template &dst) const
  187 + {
  188 + const Mat &m = src;
  189 + const int newSize = min(m.rows, m.cols);
  190 + dst = Mat(m, Rect((m.cols-newSize)/2, (m.rows-newSize)/2, newSize, newSize));
  191 + }
  192 +};
  193 +
  194 +BR_REGISTER(Transform, CropSquareTransform)
  195 +
154 } // namespace br 196 } // namespace br
155 197
156 #include "crop.moc" 198 #include "crop.moc"
openbr/plugins/gallery.cpp
@@ -212,10 +212,52 @@ class DefaultGallery : public Gallery @@ -212,10 +212,52 @@ class DefaultGallery : public Gallery
212 format->write(t); 212 format->write(t);
213 } 213 }
214 }; 214 };
  215 +
215 BR_REGISTER(Gallery, DefaultGallery) 216 BR_REGISTER(Gallery, DefaultGallery)
216 217
217 /*! 218 /*!
218 * \ingroup galleries 219 * \ingroup galleries
  220 + * \brief Combine all templates into one large matrix and process it as a br::Format
  221 + * \author Josh Klontz \cite jklontz
  222 + */
  223 +class matrixGallery : public Gallery
  224 +{
  225 + Q_OBJECT
  226 + Q_PROPERTY(const QString extension READ get_extension WRITE set_extension RESET reset_extension STORED false)
  227 + BR_PROPERTY(QString, extension, "mtx")
  228 +
  229 + TemplateList templates;
  230 +
  231 + ~matrixGallery()
  232 + {
  233 + if (templates.isEmpty())
  234 + return;
  235 +
  236 + QScopedPointer<Format> format(Factory<Format>::make(getFormat()));
  237 + format->write(Template(file, OpenCVUtils::toMat(templates.data())));
  238 + }
  239 +
  240 + File getFormat() const
  241 + {
  242 + return file.name.left(file.name.size() - file.suffix().size()) + extension;
  243 + }
  244 +
  245 + TemplateList readBlock(bool *done)
  246 + {
  247 + *done = true;
  248 + return TemplateList() << getFormat();
  249 + }
  250 +
  251 + void write(const Template &t)
  252 + {
  253 + templates.append(t);
  254 + }
  255 +};
  256 +
  257 +BR_REGISTER(Gallery, matrixGallery)
  258 +
  259 +/*!
  260 + * \ingroup galleries
219 * \brief Treat a video as a gallery, making a single template from each frame 261 * \brief Treat a video as a gallery, making a single template from each frame
220 * \author Charles Otto \cite caotto 262 * \author Charles Otto \cite caotto
221 */ 263 */
@@ -499,6 +541,8 @@ BR_REGISTER(Gallery, csvGallery) @@ -499,6 +541,8 @@ BR_REGISTER(Gallery, csvGallery)
499 class txtGallery : public Gallery 541 class txtGallery : public Gallery
500 { 542 {
501 Q_OBJECT 543 Q_OBJECT
  544 + Q_PROPERTY(QString metadataKey READ get_metadataKey WRITE set_metadataKey RESET reset_metadataKey STORED false)
  545 + BR_PROPERTY(QString, metadataKey, "")
502 546
503 QStringList lines; 547 QStringList lines;
504 548
@@ -521,7 +565,7 @@ class txtGallery : public Gallery @@ -521,7 +565,7 @@ class txtGallery : public Gallery
521 565
522 void write(const Template &t) 566 void write(const Template &t)
523 { 567 {
524 - lines.append(t.file.flat()); 568 + lines.append(metadataKey.isEmpty() ? t.file.flat() : t.file.get<QString>(metadataKey));
525 } 569 }
526 }; 570 };
527 571
@@ -762,6 +806,41 @@ class googleGallery : public Gallery @@ -762,6 +806,41 @@ class googleGallery : public Gallery
762 806
763 BR_REGISTER(Gallery, googleGallery) 807 BR_REGISTER(Gallery, googleGallery)
764 808
  809 +/*!
  810 + * \ingroup galleries
  811 + * \brief Count the number of templates.
  812 + * \author Josh Klontz \cite jklontz
  813 + */
  814 +class TemplateCountGallery : public Gallery
  815 +{
  816 + Q_OBJECT
  817 + int count;
  818 +
  819 + ~TemplateCountGallery()
  820 + {
  821 + printf("%d\n", count);
  822 + }
  823 +
  824 + void init()
  825 + {
  826 + count = 0;
  827 + }
  828 +
  829 + TemplateList readBlock(bool *done)
  830 + {
  831 + *done = true;
  832 + return TemplateList() << file;
  833 + }
  834 +
  835 + void write(const Template &t)
  836 + {
  837 + (void) t;
  838 + count++;
  839 + }
  840 +};
  841 +
  842 +BR_REGISTER(Gallery, TemplateCountGallery)
  843 +
765 } // namespace br 844 } // namespace br
766 845
767 #include "gallery.moc" 846 #include "gallery.moc"
openbr/plugins/independent.cpp
@@ -162,6 +162,71 @@ class IndependentTransform : public MetaTransform @@ -162,6 +162,71 @@ class IndependentTransform : public MetaTransform
162 162
163 BR_REGISTER(Transform, IndependentTransform) 163 BR_REGISTER(Transform, IndependentTransform)
164 164
  165 +/*!
  166 + * \ingroup transforms
  167 + * \brief A globally shared transform.
  168 + * \author Josh Klontz \cite jklontz
  169 + */
  170 +class SingletonTransform : public MetaTransform
  171 +{
  172 + Q_OBJECT
  173 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
  174 + BR_PROPERTY(QString, description, "Identity")
  175 +
  176 + static QMutex mutex;
  177 + static QHash<QString,Transform*> transforms;
  178 + static QHash<QString,int> trainingReferenceCounts;
  179 + static QHash<QString,TemplateList> trainingData;
  180 +
  181 + Transform *transform;
  182 +
  183 + void init()
  184 + {
  185 + QMutexLocker locker(&mutex);
  186 + if (!transforms.contains(description)) {
  187 + transforms.insert(description, make(description));
  188 + trainingReferenceCounts.insert(description, 0);
  189 + }
  190 +
  191 + transform = transforms[description];
  192 + trainingReferenceCounts[description]++;
  193 + }
  194 +
  195 + void train(const TemplateList &data)
  196 + {
  197 + QMutexLocker locker(&mutex);
  198 + trainingData[description].append(data);
  199 + trainingReferenceCounts[description]--;
  200 + if (trainingReferenceCounts[description] > 0) return;
  201 + transform->train(trainingData[description]);
  202 + trainingData[description].clear();
  203 + }
  204 +
  205 + void project(const Template &src, Template &dst) const
  206 + {
  207 + transform->project(src, dst);
  208 + }
  209 +
  210 + void store(QDataStream &stream) const
  211 + {
  212 + if (transform->parent() == this)
  213 + transform->store(stream);
  214 + }
  215 +
  216 + void load(QDataStream &stream)
  217 + {
  218 + if (transform->parent() == this)
  219 + transform->load(stream);
  220 + }
  221 +};
  222 +
  223 +QMutex SingletonTransform::mutex;
  224 +QHash<QString,Transform*> SingletonTransform::transforms;
  225 +QHash<QString,int> SingletonTransform::trainingReferenceCounts;
  226 +QHash<QString,TemplateList> SingletonTransform::trainingData;
  227 +
  228 +BR_REGISTER(Transform, SingletonTransform)
  229 +
165 } // namespace br 230 } // namespace br
166 231
167 #include "independent.moc" 232 #include "independent.moc"
openbr/plugins/integral.cpp
@@ -154,14 +154,14 @@ class RecursiveIntegralSamplerTransform : public Transform @@ -154,14 +154,14 @@ class RecursiveIntegralSamplerTransform : public Transform
154 } 154 }
155 } 155 }
156 156
157 - static void integralHistogram(const Mat &src, const int x, const int y, const int rows, const int columns, Mat &dst, int index) 157 + static void integralHistogram(const Mat &src, const int x, const int y, const int width, const int height, Mat &dst, int index)
158 { 158 {
159 const int channels = src.channels(); 159 const int channels = src.channels();
160 OutputDescriptor(dst.ptr<float>(index), channels, 1) = 160 OutputDescriptor(dst.ptr<float>(index), channels, 1) =
161 - ( InputDescriptor(src.ptr<qint32>(y+rows, x+columns), channels, 1)  
162 - - InputDescriptor(src.ptr<qint32>(y, x+columns), channels, 1)  
163 - - InputDescriptor(src.ptr<qint32>(y+rows, x), channels, 1)  
164 - + InputDescriptor(src.ptr<qint32>(y, x), channels, 1)).cast<float>()/(rows*columns); 161 + ( InputDescriptor(src.ptr<qint32>(y+height, x+width), channels, 1)
  162 + - InputDescriptor(src.ptr<qint32>(y, x+width), channels, 1)
  163 + - InputDescriptor(src.ptr<qint32>(y+height, x), channels, 1)
  164 + + InputDescriptor(src.ptr<qint32>(y, x), channels, 1)).cast<float>()/(height*width);
165 } 165 }
166 166
167 void computeDescriptor(const Mat &src, Mat &dst) const 167 void computeDescriptor(const Mat &src, Mat &dst) const
@@ -171,11 +171,11 @@ class RecursiveIntegralSamplerTransform : public Transform @@ -171,11 +171,11 @@ class RecursiveIntegralSamplerTransform : public Transform
171 const int columns = src.cols-1; 171 const int columns = src.cols-1;
172 172
173 Mat tmp(5, channels, CV_32FC1); 173 Mat tmp(5, channels, CV_32FC1);
174 - integralHistogram(src, 0, 0, rows/2, columns/2, tmp, 0);  
175 - integralHistogram(src, 0, columns/2, rows/2, columns/2, tmp, 1);  
176 - integralHistogram(src, rows/2, 0, rows/2, columns/2, tmp, 2);  
177 - integralHistogram(src, rows/2, columns/2, rows/2, columns/2, tmp, 3);  
178 - integralHistogram(src, rows/4, columns/4, rows/2, columns/2, tmp, 4); 174 + integralHistogram(src, 0, 0, columns/2, rows/2, tmp, 0);
  175 + integralHistogram(src, columns/2, 0, columns/2, rows/2, tmp, 1);
  176 + integralHistogram(src, 0, rows/2, columns/2, rows/2, tmp, 2);
  177 + integralHistogram(src, columns/2, rows/2, columns/2, rows/2, tmp, 3);
  178 + integralHistogram(src, columns/4, rows/4, columns/2, rows/2, tmp, 4);
179 const SecondOrderInputDescriptor a(tmp.ptr<float>(0), channels, 1); 179 const SecondOrderInputDescriptor a(tmp.ptr<float>(0), channels, 1);
180 const SecondOrderInputDescriptor b(tmp.ptr<float>(1), channels, 1); 180 const SecondOrderInputDescriptor b(tmp.ptr<float>(1), channels, 1);
181 const SecondOrderInputDescriptor c(tmp.ptr<float>(2), channels, 1); 181 const SecondOrderInputDescriptor c(tmp.ptr<float>(2), channels, 1);
@@ -188,6 +188,7 @@ class RecursiveIntegralSamplerTransform : public Transform @@ -188,6 +188,7 @@ class RecursiveIntegralSamplerTransform : public Transform
188 OutputDescriptor(dst.ptr<float>(2), channels, 1) = ((a+b)-(c+d))/2.f; 188 OutputDescriptor(dst.ptr<float>(2), channels, 1) = ((a+b)-(c+d))/2.f;
189 OutputDescriptor(dst.ptr<float>(3), channels, 1) = ((a+c)-(b+d))/2.f; 189 OutputDescriptor(dst.ptr<float>(3), channels, 1) = ((a+c)-(b+d))/2.f;
190 OutputDescriptor(dst.ptr<float>(4), channels, 1) = ((a+d)-(b+c))/2.f; 190 OutputDescriptor(dst.ptr<float>(4), channels, 1) = ((a+d)-(b+c))/2.f;
  191 + dst = dst.reshape(1, 1);
191 } 192 }
192 193
193 Template subdivide(const Template &src) const 194 Template subdivide(const Template &src) const
openbr/plugins/misc.cpp
@@ -60,20 +60,18 @@ class PrintTransform : public UntrainableMetaTransform @@ -60,20 +60,18 @@ class PrintTransform : public UntrainableMetaTransform
60 Q_OBJECT 60 Q_OBJECT
61 Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) 61 Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error)
62 Q_PROPERTY(bool data READ get_data WRITE set_data RESET reset_data) 62 Q_PROPERTY(bool data READ get_data WRITE set_data RESET reset_data)
63 - Q_PROPERTY(bool nTemplates READ get_data WRITE set_data RESET reset_data)  
64 BR_PROPERTY(bool, error, true) 63 BR_PROPERTY(bool, error, true)
65 BR_PROPERTY(bool, data, false) 64 BR_PROPERTY(bool, data, false)
66 - BR_PROPERTY(bool, size, false)  
67 65
68 void project(const Template &src, Template &dst) const 66 void project(const Template &src, Template &dst) const
69 { 67 {
70 dst = src; 68 dst = src;
71 const QString nameString = src.file.flat(); 69 const QString nameString = src.file.flat();
72 const QString dataString = data ? OpenCVUtils::matrixToString(src)+"\n" : QString(); 70 const QString dataString = data ? OpenCVUtils::matrixToString(src)+"\n" : QString();
73 - const QString nTemplates = size ? QString::number(src.size()) : QString();  
74 - qDebug() << "Dimensionality: " << src.first().cols;  
75 - if (error) qDebug("%s\n%s\n%s", qPrintable(nameString), qPrintable(dataString), qPrintable(nTemplates));  
76 - else printf("%s\n%s\n%s", qPrintable(nameString), qPrintable(dataString), qPrintable(nTemplates)); 71 + QStringList matricies;
  72 + foreach (const Mat &m, src)
  73 + matricies.append(QString::number(m.rows) + "x" + QString::number(m.cols) + "_" + OpenCVUtils::typeToString(m));
  74 + fprintf(error ? stderr : stdout, "%s\n %s\n%s", qPrintable(nameString), qPrintable(matricies.join(",")), qPrintable(dataString));
77 } 75 }
78 }; 76 };
79 77
@@ -402,13 +400,14 @@ BR_REGISTER(Transform, AsTransform) @@ -402,13 +400,14 @@ BR_REGISTER(Transform, AsTransform)
402 400
403 /*! 401 /*!
404 * \ingroup transforms 402 * \ingroup transforms
405 - * \brief Change the template label using a regular expresion matched to the file's base name. 403 + * \brief Change the template subject using a regular expresion matched to the file's base name.
  404 + * \author Josh Klontz \cite jklontz
406 */ 405 */
407 -class RelabelTransform : public UntrainableMetaTransform 406 +class SubjectTransform : public UntrainableMetaTransform
408 { 407 {
409 Q_OBJECT 408 Q_OBJECT
410 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) 409 Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false)
411 - BR_PROPERTY(QString, regexp, "") 410 + BR_PROPERTY(QString, regexp, "(.*)")
412 411
413 void project(const Template &src, Template &dst) const 412 void project(const Template &src, Template &dst) const
414 { 413 {
@@ -417,11 +416,11 @@ class RelabelTransform : public UntrainableMetaTransform @@ -417,11 +416,11 @@ class RelabelTransform : public UntrainableMetaTransform
417 QRegularExpressionMatch match = re.match(dst.file.baseName()); 416 QRegularExpressionMatch match = re.match(dst.file.baseName());
418 if (!match.hasMatch()) 417 if (!match.hasMatch())
419 qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.baseName())); 418 qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.baseName()));
420 - dst.file.set("Label", match.captured(match.lastCapturedIndex())); 419 + dst.file.set("Subject", match.captured(match.lastCapturedIndex()));
421 } 420 }
422 }; 421 };
423 422
424 -BR_REGISTER(Transform, RelabelTransform) 423 +BR_REGISTER(Transform, SubjectTransform)
425 424
426 /*! 425 /*!
427 * \ingroup transforms 426 * \ingroup transforms
openbr/plugins/regions.cpp
@@ -92,15 +92,15 @@ class CatTransform : public UntrainableMetaTransform @@ -92,15 +92,15 @@ class CatTransform : public UntrainableMetaTransform
92 qFatal("%d partitions does not evenly divide %d matrices.", partitions, src.size()); 92 qFatal("%d partitions does not evenly divide %d matrices.", partitions, src.size());
93 QVector<int> sizes(partitions, 0); 93 QVector<int> sizes(partitions, 0);
94 for (int i=0; i<src.size(); i++) 94 for (int i=0; i<src.size(); i++)
95 - sizes[i%partitions] += src[i].total() * src[i].channels(); 95 + sizes[i%partitions] += src[i].total();
96 96
97 foreach (int size, sizes) 97 foreach (int size, sizes)
98 - dst.append(Mat(1, size, CV_32FC1)); 98 + dst.append(Mat(1, size, src.m().type()));
99 99
100 QVector<int> offsets(partitions, 0); 100 QVector<int> offsets(partitions, 0);
101 for (int i=0; i<src.size(); i++) { 101 for (int i=0; i<src.size(); i++) {
102 size_t size = src[i].total() * src[i].elemSize(); 102 size_t size = src[i].total() * src[i].elemSize();
103 - int j = i%partitions; 103 + int j = i % partitions;
104 memcpy(&dst[j].data[offsets[j]], src[i].ptr(), size); 104 memcpy(&dst[j].data[offsets[j]], src[i].ptr(), size);
105 offsets[j] += size; 105 offsets[j] += size;
106 } 106 }
@@ -111,6 +111,25 @@ BR_REGISTER(Transform, CatTransform) @@ -111,6 +111,25 @@ BR_REGISTER(Transform, CatTransform)
111 111
112 /*! 112 /*!
113 * \ingroup transforms 113 * \ingroup transforms
  114 + * \brief Reshape the each matrix to the specified number of rows.
  115 + * \author Josh Klontz \cite jklontz
  116 + */
  117 +class ReshapeTransform : public UntrainableTransform
  118 +{
  119 + Q_OBJECT
  120 + Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false)
  121 + BR_PROPERTY(int, rows, 1)
  122 +
  123 + void project(const Template &src, Template &dst) const
  124 + {
  125 + dst = src.m().reshape(src.m().channels(), rows);
  126 + }
  127 +};
  128 +
  129 +BR_REGISTER(Transform, ReshapeTransform)
  130 +
  131 +/*!
  132 + * \ingroup transforms
114 * \brief Wraps OpenCV merge 133 * \brief Wraps OpenCV merge
115 * \author Josh Klontz \cite jklontz 134 * \author Josh Klontz \cite jklontz
116 */ 135 */
openbr/plugins/svm.cpp
@@ -17,18 +17,98 @@ @@ -17,18 +17,98 @@
17 #include <QTemporaryFile> 17 #include <QTemporaryFile>
18 #include <opencv2/core/core.hpp> 18 #include <opencv2/core/core.hpp>
19 #include <opencv2/ml/ml.hpp> 19 #include <opencv2/ml/ml.hpp>
20 -#include "openbr_internal.h"  
21 20
  21 +#include "openbr_internal.h"
22 #include "openbr/core/opencvutils.h" 22 #include "openbr/core/opencvutils.h"
23 23
  24 +using namespace cv;
  25 +
24 namespace br 26 namespace br
25 { 27 {
26 28
  29 +static void storeSVM(float a, float b, const SVM &svm, QDataStream &stream)
  30 +{
  31 + stream << a << b;
  32 +
  33 + // Create local file
  34 + QTemporaryFile tempFile;
  35 + tempFile.open();
  36 + tempFile.close();
  37 +
  38 + // Save SVM to local file
  39 + svm.save(qPrintable(tempFile.fileName()));
  40 +
  41 + // Copy local file contents to stream
  42 + tempFile.open();
  43 + QByteArray data = tempFile.readAll();
  44 + tempFile.close();
  45 + stream << data;
  46 +}
  47 +
  48 +static void loadSVM(float &a, float &b, SVM &svm, QDataStream &stream)
  49 +{
  50 + stream >> a >> b;
  51 +
  52 + // Copy local file contents from stream
  53 + QByteArray data;
  54 + stream >> data;
  55 +
  56 + // Create local file
  57 + QTemporaryFile tempFile(QDir::tempPath()+"/SVM");
  58 + tempFile.open();
  59 + tempFile.write(data);
  60 + tempFile.close();
  61 +
  62 + // Load SVM from local file
  63 + svm.load(qPrintable(tempFile.fileName()));
  64 +}
  65 +
  66 +static void trainSVM(float &a, float &b, SVM &svm, Mat data, Mat lab, int kernel, int type, float C, float gamma)
  67 +{
  68 + if ((type == CvSVM::EPS_SVR) || (type == CvSVM::NU_SVR)) {
  69 + // Scale labels to [-1,1]
  70 + double min, max;
  71 + minMaxLoc(lab, &min, &max);
  72 + if (max > min) {
  73 + a = 2.0/(max-min);
  74 + b = -(min*a+1);
  75 + lab = (lab * a) + b;
  76 + }
  77 + } else {
  78 + a = 1;
  79 + b = 0;
  80 + }
  81 +
  82 + if (data.type() != CV_32FC1)
  83 + qFatal("Expected single channel floating point training data.");
  84 +
  85 + CvSVMParams params;
  86 + params.kernel_type = kernel;
  87 + params.svm_type = type;
  88 + params.p = 0.1;
  89 + params.nu = 0.5;
  90 + if ((C == -1) || ((gamma == -1) && (kernel == CvSVM::RBF))) {
  91 + try {
  92 + svm.train_auto(data, lab, Mat(), Mat(), params, 5);
  93 + } catch (...) {
  94 + qWarning("Some classes do not contain sufficient examples or are not discriminative enough for accurate SVM classification.");
  95 + svm.train(data, lab);
  96 + }
  97 + } else {
  98 + params.C = C;
  99 + params.gamma = gamma;
  100 + svm.train(data, lab, Mat(), Mat(), params);
  101 + }
  102 +
  103 + CvSVMParams p = svm.get_params();
  104 + qDebug("SVM C = %f Gamma = %f Support Vectors = %d", p.C, p.gamma, svm.get_support_vector_count());
  105 +}
  106 +
27 /*! 107 /*!
28 * \ingroup transforms 108 * \ingroup transforms
29 * \brief C. Burges. "A tutorial on support vector machines for pattern recognition," 109 * \brief C. Burges. "A tutorial on support vector machines for pattern recognition,"
30 - * Knowledge Discovery and Data Mining 2(2), 1998.  
31 * \author Josh Klontz \cite jklontz 110 * \author Josh Klontz \cite jklontz
  111 + * Knowledge Discovery and Data Mining 2(2), 1998.
32 */ 112 */
33 class SVMTransform : public Transform 113 class SVMTransform : public Transform
34 { 114 {
@@ -41,16 +121,11 @@ class SVMTransform : public Transform @@ -41,16 +121,11 @@ class SVMTransform : public Transform
41 Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false) 121 Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false)
42 122
43 public: 123 public:
44 - /*!  
45 - * \brief The Kernel enum  
46 - */  
47 enum Kernel { Linear = CvSVM::LINEAR, 124 enum Kernel { Linear = CvSVM::LINEAR,
48 Poly = CvSVM::POLY, 125 Poly = CvSVM::POLY,
49 RBF = CvSVM::RBF, 126 RBF = CvSVM::RBF,
50 Sigmoid = CvSVM::SIGMOID }; 127 Sigmoid = CvSVM::SIGMOID };
51 - /*!  
52 - * \brief The Type enum  
53 - */ 128 +
54 enum Type { C_SVC = CvSVM::C_SVC, 129 enum Type { C_SVC = CvSVM::C_SVC,
55 NU_SVC = CvSVM::NU_SVC, 130 NU_SVC = CvSVM::NU_SVC,
56 ONE_CLASS = CvSVM::ONE_CLASS, 131 ONE_CLASS = CvSVM::ONE_CLASS,
@@ -63,99 +138,110 @@ private: @@ -63,99 +138,110 @@ private:
63 BR_PROPERTY(float, C, -1) 138 BR_PROPERTY(float, C, -1)
64 BR_PROPERTY(float, gamma, -1) 139 BR_PROPERTY(float, gamma, -1)
65 140
66 - cv::SVM svm; 141 + SVM svm;
67 float a, b; 142 float a, b;
68 143
69 -public:  
70 - SVMTransform() : a(1), b(0) {}  
71 -  
72 -private:  
73 void train(const TemplateList &_data) 144 void train(const TemplateList &_data)
74 { 145 {
75 - cv::Mat data = OpenCVUtils::toMat(_data.data());  
76 - cv::Mat lab = OpenCVUtils::toMat(_data.labels<float>());  
77 -  
78 - if ((type == EPS_SVR) || (type == NU_SVR)) {  
79 - // Scale labels to [-1,1]  
80 - double min, max;  
81 - cv::minMaxLoc(lab, &min, &max);  
82 - if (max > min) {  
83 - a = 2.0/(max-min);  
84 - b = -(min*a+1);  
85 - lab = (lab * a) + b;  
86 - }  
87 - }  
88 -  
89 - if (data.type() != CV_32FC1)  
90 - qFatal("Expected single channel floating point training data.");  
91 -  
92 - CvSVMParams params;  
93 - params.kernel_type = kernel;  
94 - params.svm_type = type;  
95 - params.p = 0.1;  
96 - params.nu = 0.5;  
97 - if ((C == -1) || ((gamma == -1) && (int(kernel) != int(CvSVM::LINEAR)))) {  
98 - try {  
99 - svm.train_auto(data, lab, cv::Mat(), cv::Mat(), params, 5);  
100 - } catch (...) {  
101 - qWarning("Some classes do not contain sufficient examples or are not discriminative enough for accurate SVM classification.");  
102 - svm.train(data, lab);  
103 - }  
104 - } else {  
105 - params.C = C;  
106 - params.gamma = gamma;  
107 - svm.train(data, lab, cv::Mat(), cv::Mat(), params);  
108 - }  
109 -  
110 - CvSVMParams p = svm.get_params();  
111 - qDebug("SVM C = %f Gamma = %f Support Vectors = %d", p.C, p.gamma, svm.get_support_vector_count()); 146 + Mat data = OpenCVUtils::toMat(_data.data());
  147 + Mat lab = OpenCVUtils::toMat(_data.labels<float>());
  148 + trainSVM(a, b, svm, data, lab, kernel, type, C, gamma);
112 } 149 }
113 150
114 void project(const Template &src, Template &dst) const 151 void project(const Template &src, Template &dst) const
115 { 152 {
116 dst = src; 153 dst = src;
117 - dst.file.set("Label", ((svm.predict(src.m().reshape(0, 1)) - b)/a)); 154 + dst.file.set("Label", ((svm.predict(src.m().reshape(1, 1)) - b)/a));
118 } 155 }
119 156
120 void store(QDataStream &stream) const 157 void store(QDataStream &stream) const
121 { 158 {
122 - stream << a << b; 159 + storeSVM(a, b, svm, stream);
  160 + }
123 161
124 - // Create local file  
125 - QTemporaryFile tempFile;  
126 - tempFile.open();  
127 - tempFile.close(); 162 + void load(QDataStream &stream)
  163 + {
  164 + loadSVM(a, b, svm, stream);
  165 + }
  166 +};
128 167
129 - // Save SVM to local file  
130 - svm.save(qPrintable(tempFile.fileName())); 168 +BR_REGISTER(Transform, SVMTransform)
131 169
132 - // Copy local file contents to stream  
133 - tempFile.open();  
134 - QByteArray data = tempFile.readAll();  
135 - tempFile.close();  
136 - stream << data;  
137 - } 170 +/*!
  171 + * \ingroup Distances
  172 + * \brief SVM Regression on template absolute differences.
  173 + * \author Josh Klontz
  174 + */
  175 +class SVMDistance : public Distance
  176 +{
  177 + Q_OBJECT
  178 + Q_ENUMS(Kernel)
  179 + Q_ENUMS(Type)
  180 + Q_PROPERTY(Kernel kernel READ get_kernel WRITE set_kernel RESET reset_kernel STORED false)
  181 + Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false)
138 182
139 - void load(QDataStream &stream) 183 +public:
  184 + enum Kernel { Linear = CvSVM::LINEAR,
  185 + Poly = CvSVM::POLY,
  186 + RBF = CvSVM::RBF,
  187 + Sigmoid = CvSVM::SIGMOID };
  188 +
  189 + enum Type { C_SVC = CvSVM::C_SVC,
  190 + NU_SVC = CvSVM::NU_SVC,
  191 + ONE_CLASS = CvSVM::ONE_CLASS,
  192 + EPS_SVR = CvSVM::EPS_SVR,
  193 + NU_SVR = CvSVM::NU_SVR};
  194 +
  195 +private:
  196 + BR_PROPERTY(Kernel, kernel, Linear)
  197 + BR_PROPERTY(Type, type, EPS_SVR)
  198 +
  199 + SVM svm;
  200 + float a, b;
  201 +
  202 + void train(const TemplateList &src)
140 { 203 {
141 - stream >> a >> b; 204 + const Mat data = OpenCVUtils::toMat(src.data());
  205 + const QList<int> lab = src.labels<int>();
  206 +
  207 + const int instances = data.rows * (data.rows+1) / 2;
  208 + Mat deltaData(instances, data.cols, data.type());
  209 + Mat deltaLab(instances, 1, CV_32FC1);
  210 + int index = 0;
  211 + for (int i=0; i<data.rows; i++)
  212 + for (int j=i; j<data.rows; j++) {
  213 + const bool match = lab[i] == lab[j];
  214 + if (!match && (type == ONE_CLASS))
  215 + continue;
  216 + absdiff(data.row(i), data.row(j), deltaData.row(index));
  217 + deltaLab.at<float>(index, 0) = (match ? 1 : 0);
  218 + index++;
  219 + }
  220 + deltaData = deltaData.rowRange(0, index);
  221 + deltaLab = deltaLab.rowRange(0, index);
142 222
143 - // Copy local file contents from stream  
144 - QByteArray data;  
145 - stream >> data; 223 + trainSVM(a, b, svm, deltaData, deltaLab, kernel, type, -1, -1);
  224 + }
146 225
147 - // Create local file  
148 - QTemporaryFile tempFile(QDir::tempPath()+"/SVM");  
149 - tempFile.open();  
150 - tempFile.write(data);  
151 - tempFile.close(); 226 + float compare(const Template &ta, const Template &tb) const
  227 + {
  228 + Mat delta;
  229 + absdiff(ta, tb, delta);
  230 + return (svm.predict(delta.reshape(1, 1)) - b)/a;
  231 + }
152 232
153 - // Load SVM from local file  
154 - svm.load(qPrintable(tempFile.fileName())); 233 + void store(QDataStream &stream) const
  234 + {
  235 + storeSVM(a, b, svm, stream);
  236 + }
  237 +
  238 + void load(QDataStream &stream)
  239 + {
  240 + loadSVM(a, b, svm, stream);
155 } 241 }
156 }; 242 };
157 243
158 -BR_REGISTER(Transform, SVMTransform) 244 +BR_REGISTER(Distance, SVMDistance)
159 245
160 } // namespace br 246 } // namespace br
161 247
share/openbr/abstraction.svg 0 โ†’ 100644
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
  3 +
  4 +<svg
  5 + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
  6 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  7 + xmlns:cc="http://creativecommons.org/ns#"
  8 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  9 + xmlns:svg="http://www.w3.org/2000/svg"
  10 + xmlns="http://www.w3.org/2000/svg"
  11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  13 + width="512"
  14 + height="416"
  15 + id="svg2"
  16 + version="1.1"
  17 + inkscape:version="0.48.2 r9819"
  18 + sodipodi:docname="abstraction.svg">
  19 + <defs
  20 + id="defs4">
  21 + <linearGradient
  22 + id="linearGradient5438"
  23 + osb:paint="gradient">
  24 + <stop
  25 + style="stop-color:#bebada;stop-opacity:1;"
  26 + offset="0"
  27 + id="stop5440" />
  28 + <stop
  29 + style="stop-color:#bebada;stop-opacity:0;"
  30 + offset="1"
  31 + id="stop5442" />
  32 + </linearGradient>
  33 + </defs>
  34 + <sodipodi:namedview
  35 + id="base"
  36 + pagecolor="#ffffff"
  37 + bordercolor="#666666"
  38 + borderopacity="1.0"
  39 + inkscape:pageopacity="0.0"
  40 + inkscape:pageshadow="2"
  41 + inkscape:zoom="1.414741"
  42 + inkscape:cx="245.94939"
  43 + inkscape:cy="199.44253"
  44 + inkscape:document-units="px"
  45 + inkscape:current-layer="layer1"
  46 + showgrid="false"
  47 + inkscape:window-width="1383"
  48 + inkscape:window-height="856"
  49 + inkscape:window-x="57"
  50 + inkscape:window-y="0"
  51 + inkscape:window-maximized="1" />
  52 + <metadata
  53 + id="metadata7">
  54 + <rdf:RDF>
  55 + <cc:Work
  56 + rdf:about="">
  57 + <dc:format>image/svg+xml</dc:format>
  58 + <dc:type
  59 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  60 + <dc:title />
  61 + </cc:Work>
  62 + </rdf:RDF>
  63 + </metadata>
  64 + <g
  65 + inkscape:label="Layer 1"
  66 + inkscape:groupmode="layer"
  67 + id="layer1"
  68 + transform="translate(0,-636.36218)">
  69 + <rect
  70 + style="fill:#8dd3c7;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
  71 + id="rect5563"
  72 + width="153"
  73 + height="62"
  74 + x="342"
  75 + y="653.36218" />
  76 + <rect
  77 + style="fill:#8dd3c7;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
  78 + id="rect2985"
  79 + width="153"
  80 + height="62"
  81 + x="17"
  82 + y="653.36218" />
  83 + <rect
  84 + style="fill:#ffffb3;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
  85 + id="rect2989"
  86 + width="478"
  87 + height="62"
  88 + x="17"
  89 + y="725.36218" />
  90 + <text
  91 + xml:space="preserve"
  92 + style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
  93 + x="68.367188"
  94 + y="699.79578"
  95 + id="text2995"
  96 + sodipodi:linespacing="125%"><tspan
  97 + sodipodi:role="line"
  98 + id="tspan2997"
  99 + x="68.367188"
  100 + y="699.79578">br</tspan></text>
  101 + <text
  102 + xml:space="preserve"
  103 + style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
  104 + x="171.7876"
  105 + y="768.62451"
  106 + id="text3003"
  107 + sodipodi:linespacing="125%"><tspan
  108 + sodipodi:role="line"
  109 + id="tspan3005"
  110 + x="171.7876"
  111 + y="768.62451">OpenBR</tspan></text>
  112 + <text
  113 + xml:space="preserve"
  114 + style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
  115 + x="300"
  116 + y="297.18518"
  117 + id="text3011"
  118 + sodipodi:linespacing="125%"
  119 + transform="translate(0,540.36218)"><tspan
  120 + sodipodi:role="line"
  121 + id="tspan3013"
  122 + x="300"
  123 + y="297.18518" /></text>
  124 + <text
  125 + xml:space="preserve"
  126 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  127 + x="489.27899"
  128 + y="750.23242"
  129 + id="text3019"
  130 + sodipodi:linespacing="125%"><tspan
  131 + sodipodi:role="line"
  132 + id="tspan3021"
  133 + x="489.27899"
  134 + y="750.23242">OpenCV</tspan><tspan
  135 + sodipodi:role="line"
  136 + x="489.27899"
  137 + y="772.73242"
  138 + id="tspan3945">Qt</tspan></text>
  139 + <text
  140 + xml:space="preserve"
  141 + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  142 + x="367.25104"
  143 + y="257.92224"
  144 + id="text3836"
  145 + sodipodi:linespacing="125%"
  146 + transform="translate(0,540.36218)"><tspan
  147 + sodipodi:role="line"
  148 + id="tspan3838"
  149 + x="367.25104"
  150 + y="257.92224" /></text>
  151 + <rect
  152 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 7.99999999;stroke-dashoffset:0"
  153 + id="rect3848"
  154 + width="118"
  155 + height="62.000004"
  156 + x="377"
  157 + y="797.36218" />
  158 + <rect
  159 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.99999988, 7.99999978;stroke-dashoffset:0"
  160 + id="rect3854"
  161 + width="62"
  162 + height="62"
  163 + x="233"
  164 + y="797.36212" />
  165 + <rect
  166 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 8;stroke-dashoffset:0"
  167 + id="rect3856"
  168 + width="62"
  169 + height="62"
  170 + x="233"
  171 + y="869.36218" />
  172 + <rect
  173 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 8;stroke-dashoffset:0"
  174 + id="rect3858"
  175 + width="61.999996"
  176 + height="62"
  177 + x="305"
  178 + y="797.36218" />
  179 + <text
  180 + xml:space="preserve"
  181 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  182 + x="262.64453"
  183 + y="836.02234"
  184 + id="text3816"
  185 + sodipodi:linespacing="125%"><tspan
  186 + sodipodi:role="line"
  187 + id="tspan3818"
  188 + x="262.64453"
  189 + y="836.02234">PCA</tspan></text>
  190 + <text
  191 + xml:space="preserve"
  192 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  193 + x="263.64453"
  194 + y="908.36218"
  195 + id="text3820"
  196 + sodipodi:linespacing="125%"><tspan
  197 + sodipodi:role="line"
  198 + id="tspan3822"
  199 + x="263.64453"
  200 + y="908.36218">LDA</tspan></text>
  201 + <text
  202 + xml:space="preserve"
  203 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  204 + x="335.84473"
  205 + y="836.36218"
  206 + id="text3824"
  207 + sodipodi:linespacing="125%"><tspan
  208 + sodipodi:role="line"
  209 + id="tspan3826"
  210 + x="335.84473"
  211 + y="836.36218">LBP</tspan></text>
  212 + <rect
  213 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4.00000014, 8.00000028;stroke-dashoffset:0"
  214 + id="rect3860"
  215 + width="62.000004"
  216 + height="62.000004"
  217 + x="305"
  218 + y="869.36218" />
  219 + <text
  220 + xml:space="preserve"
  221 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  222 + x="336.6709"
  223 + y="914.36218"
  224 + id="text3828"
  225 + sodipodi:linespacing="125%"><tspan
  226 + sodipodi:role="line"
  227 + id="tspan3830"
  228 + x="336.6709"
  229 + y="914.36218">...</tspan></text>
  230 + <text
  231 + xml:space="preserve"
  232 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  233 + x="435.84863"
  234 + y="823.69287"
  235 + id="text3840"
  236 + sodipodi:linespacing="125%"><tspan
  237 + sodipodi:role="line"
  238 + id="tspan3842"
  239 + x="435.84863"
  240 + y="823.69287"
  241 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans">Commercial</tspan><tspan
  242 + sodipodi:role="line"
  243 + x="435.84863"
  244 + y="846.19287"
  245 + id="tspan5663"
  246 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans">Wrapper</tspan></text>
  247 + <text
  248 + xml:space="preserve"
  249 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  250 + x="419.84863"
  251 + y="678.81708"
  252 + id="text3832"
  253 + sodipodi:linespacing="125%"><tspan
  254 + sodipodi:role="line"
  255 + id="tspan3834"
  256 + x="419.84863"
  257 + y="678.81708"
  258 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans">Commercial</tspan><tspan
  259 + sodipodi:role="line"
  260 + x="419.84863"
  261 + y="701.31708"
  262 + id="tspan5661"
  263 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans">Application</tspan></text>
  264 + <rect
  265 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
  266 + id="rect3901"
  267 + width="31.999998"
  268 + height="32"
  269 + x="288"
  270 + y="946.36218" />
  271 + <rect
  272 + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 8;stroke-dashoffset:0"
  273 + id="rect5411"
  274 + width="30"
  275 + height="30"
  276 + x="289"
  277 + y="995.36218" />
  278 + <text
  279 + xml:space="preserve"
  280 + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  281 + x="326.41797"
  282 + y="972.02234"
  283 + id="text5512"
  284 + sodipodi:linespacing="125%"><tspan
  285 + sodipodi:role="line"
  286 + id="tspan5514"
  287 + x="326.41797"
  288 + y="972.02234">Source Code</tspan></text>
  289 + <text
  290 + xml:space="preserve"
  291 + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  292 + x="70.417969"
  293 + y="1018.37"
  294 + id="text5516"
  295 + sodipodi:linespacing="125%"><tspan
  296 + sodipodi:role="line"
  297 + id="tspan5518"
  298 + x="70.417969"
  299 + y="1018.37">Shared Library</tspan></text>
  300 + <text
  301 + xml:space="preserve"
  302 + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  303 + x="71.8125"
  304 + y="971.37"
  305 + id="text5520"
  306 + sodipodi:linespacing="125%"><tspan
  307 + sodipodi:role="line"
  308 + id="tspan5522"
  309 + x="71.8125"
  310 + y="971.37">Application</tspan></text>
  311 + <text
  312 + xml:space="preserve"
  313 + style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  314 + x="325.64453"
  315 + y="1018.37"
  316 + id="text5524"
  317 + sodipodi:linespacing="125%"><tspan
  318 + sodipodi:role="line"
  319 + id="tspan5526"
  320 + x="325.64453"
  321 + y="1018.37">Plugin</tspan><tspan
  322 + sodipodi:role="line"
  323 + x="325.64453"
  324 + y="1048.37"
  325 + id="tspan5528" /></text>
  326 + <rect
  327 + style="fill:#ffffb3;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
  328 + id="rect5635"
  329 + width="32"
  330 + height="32"
  331 + x="32"
  332 + y="994.36218" />
  333 + <rect
  334 + style="fill:#8dd3c7;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
  335 + id="rect5641"
  336 + width="32"
  337 + height="32"
  338 + x="32"
  339 + y="946.36218" />
  340 + <rect
  341 + y="869.36218"
  342 + x="377"
  343 + height="62.000004"
  344 + width="118"
  345 + id="rect3923"
  346 + style="fill:#ffffb3;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 7.99999999;stroke-dashoffset:0" />
  347 + <text
  348 + sodipodi:linespacing="125%"
  349 + id="text3925"
  350 + y="895.08405"
  351 + x="435.84863"
  352 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  353 + xml:space="preserve"><tspan
  354 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
  355 + y="895.08405"
  356 + x="435.84863"
  357 + id="tspan3927"
  358 + sodipodi:role="line">Commercial</tspan><tspan
  359 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
  360 + id="tspan3929"
  361 + y="917.58405"
  362 + x="435.84863"
  363 + sodipodi:role="line">Library</tspan></text>
  364 + <rect
  365 + y="653.36218"
  366 + x="180"
  367 + height="62"
  368 + width="152"
  369 + id="rect3937"
  370 + style="fill:#8dd3c7;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
  371 + <text
  372 + sodipodi:linespacing="125%"
  373 + id="text3939"
  374 + y="678.81708"
  375 + x="256.83887"
  376 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  377 + xml:space="preserve"><tspan
  378 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
  379 + y="678.81708"
  380 + x="256.83887"
  381 + id="tspan3941"
  382 + sodipodi:role="line">Open Source</tspan><tspan
  383 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans"
  384 + id="tspan3943"
  385 + y="701.31708"
  386 + x="256.83887"
  387 + sodipodi:role="line">Application</tspan></text>
  388 + <rect
  389 + y="797.36218"
  390 + x="17"
  391 + height="134"
  392 + width="206"
  393 + id="rect3947"
  394 + style="fill:#bebada;fill-opacity:1;stroke:#000000;stroke-width:1.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
  395 + <text
  396 + xml:space="preserve"
  397 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  398 + x="123.47915"
  399 + y="895.03503"
  400 + id="text3961"
  401 + sodipodi:linespacing="125%"><tspan
  402 + id="tspan3965"
  403 + sodipodi:role="line"
  404 + x="123.47915"
  405 + y="895.03503"
  406 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Sans;-inkscape-font-specification:Sans" /></text>
  407 + <text
  408 + xml:space="preserve"
  409 + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
  410 + x="21"
  411 + y="823.81079"
  412 + id="text3993"
  413 + sodipodi:linespacing="125%"><tspan
  414 + sodipodi:role="line"
  415 + x="21"
  416 + y="823.81079"
  417 + id="tspan4025">โ€ขAlgorithm evaluation</tspan><tspan
  418 + sodipodi:role="line"
  419 + x="21"
  420 + y="846.31079"
  421 + id="tspan4011">โ€ขParallel training &amp;</tspan><tspan
  422 + sodipodi:role="line"
  423 + x="21"
  424 + y="868.81079"
  425 + id="tspan4023"> execution</tspan><tspan
  426 + sodipodi:role="line"
  427 + x="21"
  428 + y="891.31079"
  429 + id="tspan4013">โ€ขImage processing </tspan><tspan
  430 + sodipodi:role="line"
  431 + x="21"
  432 + y="913.81079"
  433 + id="tspan4015"> grammar</tspan></text>
  434 + <text
  435 + xml:space="preserve"
  436 + style="font-size:13px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#808080;fill-opacity:1;stroke:none;font-family:Sans"
  437 + x="176.38187"
  438 + y="1047.9127"
  439 + id="text4017"
  440 + sodipodi:linespacing="125%"><tspan
  441 + sodipodi:role="line"
  442 + id="tspan4019"
  443 + x="176.38187"
  444 + y="1047.9127">www.openbiometrics.org</tspan></text>
  445 + </g>
  446 +</svg>
share/openbr/openbr.bib
@@ -70,21 +70,6 @@ @@ -70,21 +70,6 @@
70 Title = {PittPatt {SDK} 5.2.2}, 70 Title = {PittPatt {SDK} 5.2.2},
71 Year = {2011}} 71 Year = {2011}}
72 72
73 -  
74 -% Datasets  
75 -@misc{GBU,  
76 - Author = {NIST},  
77 - Howpublished = {www.nist.gov/itl/iad/ig/focs.cfm},  
78 - Title = {Face and Ocular Challenge Series ({FOCS})},  
79 - Year = {2010}}  
80 -  
81 -@misc{MEDS,  
82 - Author = {NIST},  
83 - Howpublished = {www.nist.gov/itl/iad/ig/sd32.cfm},  
84 - Title = {{NIST} Special Database 32 - Multiple Encounter Dataset ({MEDS})},  
85 - Year = {2011}}  
86 -  
87 -  
88 % Papers 73 % Papers
89 @inproceedings{arandjelovic12, 74 @inproceedings{arandjelovic12,
90 Author={Arandjelovic, R. and Zisserman, A.}, 75 Author={Arandjelovic, R. and Zisserman, A.},
@@ -117,16 +102,22 @@ @@ -117,16 +102,22 @@
117 Title = {Average of Synthetic Exact Filters}, 102 Title = {Average of Synthetic Exact Filters},
118 Year = {2009}} 103 Year = {2009}}
119 104
  105 +@misc{founds11,
  106 + Author = {Founds, A.P. and Orlans, N. and Whiddon, G. and Watson, C.},
  107 + Howpublished = {www.nist.gov/itl/iad/ig/sd32.cfm},
  108 + Title = {{NIST Special Database 32 - Multiple Encounter Dataset II (MEDS-II)}},
  109 + Year = {2011}}
  110 +
120 @misc{grother12, 111 @misc{grother12,
121 Author = {Grother, P. and Quinn, G.W. and Ngan, M.}, 112 Author = {Grother, P. and Quinn, G.W. and Ngan, M.},
122 - Title = {Face Recognition Vendor Test (FRVT) 2012}, 113 + Title = {{Face Recognition Vendor Test (FRVT)} 2012},
123 Month = {mar}, 114 Month = {mar},
124 Year = {2013}, 115 Year = {2013},
125 Url = {http://www.nist.gov/itl/iad/ig/frvt-2012.cfm}} 116 Url = {http://www.nist.gov/itl/iad/ig/frvt-2012.cfm}}
126 117
127 @misc{grother13, 118 @misc{grother13,
128 Author = {Grother, P.}, 119 Author = {Grother, P.},
129 - Title = {{MITRE} {FRVT} {Submission} {Question}}, 120 + Title = {{MITRE FRVT Submission Question}},
130 HowPublished = {Personal communication}, 121 HowPublished = {Personal communication},
131 Month = {jan}, 122 Month = {jan},
132 Year = {2013}} 123 Year = {2013}}
@@ -158,7 +149,7 @@ @@ -158,7 +149,7 @@
158 @article{martinez98, 149 @article{martinez98,
159 Author={Martinez, A.M.}, 150 Author={Martinez, A.M.},
160 Journal={CVC Technical Report}, 151 Journal={CVC Technical Report},
161 - Title={The AR face database}, 152 + Title={The {AR} face database},
162 Volume={24}, 153 Volume={24},
163 Year={1998}} 154 Year={1998}}
164 155
@@ -183,7 +174,7 @@ @@ -183,7 +174,7 @@
183 Booktitle = {Second international conference on audio and video-based biometric person authentication}, 174 Booktitle = {Second international conference on audio and video-based biometric person authentication},
184 Organization = {Citeseer}, 175 Organization = {Citeseer},
185 Pages = {965-966}, 176 Pages = {965-966},
186 - Title = {XM2VTSDB: The extended M2VTS database}, 177 + Title = {{XM2VTSDB}: The extended {M2VTS} database},
187 Volume = {964}, 178 Volume = {964},
188 Year = {1999}} 179 Year = {1999}}
189 180
@@ -224,7 +215,7 @@ @@ -224,7 +215,7 @@
224 Author = {Li, S.Z. and Lei, Z. and Ao, M.}, 215 Author = {Li, S.Z. and Lei, Z. and Ao, M.},
225 Booktitle = {6th IEEE Workshop on Object Tracking and Classification Beyond and in the Visible Spectrum (OTCBVS, in conjunction with CVPR 2009)}, 216 Booktitle = {6th IEEE Workshop on Object Tracking and Classification Beyond and in the Visible Spectrum (OTCBVS, in conjunction with CVPR 2009)},
226 Month = {jun}, 217 Month = {jun},
227 - Title = {The HFB Face Database for Heterogeneous Face Biometrics Research}, 218 + Title = {{The HFB Face Database} for {Heterogeneous Face Biometrics} Research},
228 Year = {2009}} 219 Year = {2009}}
229 220
230 @article{wang09, 221 @article{wang09,