Commit 3320ddac1be46c8fa1ee0372efca9d5f46034aa2
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
17 changed files
with
973 additions
and
159 deletions
openbr/core/classify.cpp
| ... | ... | @@ -14,8 +14,6 @@ |
| 14 | 14 | * limitations under the License. * |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | -#include <QDebug> | |
| 18 | -#include <QHash> | |
| 19 | 17 | #include <openbr/openbr_plugin.h> |
| 20 | 18 | |
| 21 | 19 | #include "classify.h" |
| ... | ... | @@ -24,7 +22,7 @@ |
| 24 | 22 | // Helper struct for statistics accumulation |
| 25 | 23 | struct Counter |
| 26 | 24 | { |
| 27 | - int truePositive, falsePositive, falseNegative; | |
| 25 | + float truePositive, falsePositive, falseNegative; | |
| 28 | 26 | Counter() |
| 29 | 27 | { |
| 30 | 28 | truePositive = 0; |
| ... | ... | @@ -41,35 +39,44 @@ void br::EvalClassification(const QString &predictedInput, const QString &truthI |
| 41 | 39 | TemplateList truth(TemplateList::fromGallery(truthInput)); |
| 42 | 40 | if (predicted.size() != truth.size()) qFatal("Input size mismatch."); |
| 43 | 41 | |
| 44 | - QHash<int, Counter> counters; | |
| 42 | + QHash<QString, Counter> counters; | |
| 45 | 43 | for (int i=0; i<predicted.size(); i++) { |
| 46 | 44 | if (predicted[i].file.name != truth[i].file.name) |
| 47 | 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 | 65 | QSharedPointer<Output> output(Output::make("", FileList() << "Subject" << "Count" << "Precision" << "Recall" << "F-score", FileList(counters.size()))); |
| 60 | 66 | |
| 61 | 67 | int tpc = 0; |
| 62 | 68 | int fnc = 0; |
| 69 | + const QStringList keys = counters.keys(); | |
| 63 | 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 | 73 | tpc += counter.truePositive; |
| 67 | 74 | fnc += counter.falseNegative; |
| 68 | 75 | const int count = counter.truePositive + counter.falseNegative; |
| 69 | 76 | const float precision = counter.truePositive / (float)(counter.truePositive + counter.falsePositive); |
| 70 | 77 | const float recall = counter.truePositive / (float)(counter.truePositive + counter.falseNegative); |
| 71 | 78 | const float fscore = 2 * precision * recall / (precision + recall); |
| 72 | - output->setRelative(trueLabel, i, 0); | |
| 79 | + output->setRelative(File("", subject).label(), i, 0); | |
| 73 | 80 | output->setRelative(count, i, 1); |
| 74 | 81 | output->setRelative(precision, i, 2); |
| 75 | 82 | output->setRelative(recall, i, 3); | ... | ... |
openbr/core/common.h
| ... | ... | @@ -102,7 +102,7 @@ void MinMax(const QList<T> &vals, T *min, T *max) |
| 102 | 102 | template <typename T> |
| 103 | 103 | T Min(const QList<T> &vals) |
| 104 | 104 | { |
| 105 | - int min, max; | |
| 105 | + T min, max; | |
| 106 | 106 | MinMax(vals, &min, &max); |
| 107 | 107 | return min; |
| 108 | 108 | } |
| ... | ... | @@ -110,7 +110,7 @@ T Min(const QList<T> &vals) |
| 110 | 110 | template <typename T> |
| 111 | 111 | T Max(const QList<T> &vals) |
| 112 | 112 | { |
| 113 | - int min, max; | |
| 113 | + T min, max; | |
| 114 | 114 | MinMax(vals, &min, &max); |
| 115 | 115 | return max; |
| 116 | 116 | } | ... | ... |
openbr/core/opencvutils.cpp
| ... | ... | @@ -157,6 +157,26 @@ Mat OpenCVUtils::toMatByRow(const QList<Mat> &src) |
| 157 | 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 | 180 | QString OpenCVUtils::elemToString(const Mat &m, int r, int c) |
| 161 | 181 | { |
| 162 | 182 | assert(m.channels() == 1); | ... | ... |
openbr/core/opencvutils.h
| ... | ... | @@ -39,6 +39,8 @@ namespace OpenCVUtils |
| 39 | 39 | cv::Mat toMatByRow(const QList<cv::Mat> &src); // Data organized one row per row |
| 40 | 40 | |
| 41 | 41 | // From image |
| 42 | + QString depthToString(const cv::Mat &m); | |
| 43 | + QString typeToString(const cv::Mat &m); | |
| 42 | 44 | QString elemToString(const cv::Mat &m, int r, int c); |
| 43 | 45 | QString matrixToString(const cv::Mat &m); |
| 44 | 46 | QStringList matrixToStringList(const cv::Mat &m); | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -923,24 +923,20 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte |
| 923 | 923 | { |
| 924 | 924 | // Something about this method is not thread safe, and will lead to crashes if qDebug |
| 925 | 925 | // statements are called from multiple threads. Unless we lock the whole thing... |
| 926 | - static QMutex generalLock(QMutex::Recursive); | |
| 926 | + static QMutex generalLock; | |
| 927 | 927 | QMutexLocker locker(&generalLock); |
| 928 | 928 | |
| 929 | 929 | QString txt; |
| 930 | - switch (type) { | |
| 931 | - case QtDebugMsg: | |
| 930 | + if (type == QtDebugMsg) { | |
| 932 | 931 | if (Globals->quiet) return; |
| 933 | 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 | 942 | std::cerr << txt.toStdString(); |
| ... | ... | @@ -951,11 +947,8 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte |
| 951 | 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 | 954 | Context *br::Globals = NULL; |
| ... | ... | @@ -1027,7 +1020,7 @@ MatrixOutput *MatrixOutput::make(const FileList &targetFiles, const FileList &qu |
| 1027 | 1020 | /* MatrixOutput - protected methods */ |
| 1028 | 1021 | QString MatrixOutput::toString(int row, int column) const |
| 1029 | 1022 | { |
| 1030 | - if (targetFiles[column] == "Label") { | |
| 1023 | + if (targetFiles[column] == "Subject") { | |
| 1031 | 1024 | const int label = data.at<float>(row,column); |
| 1032 | 1025 | return Globals->subjects.key(label, QString::number(label)); |
| 1033 | 1026 | } | ... | ... |
openbr/plugins/algorithms.cpp
| ... | ... | @@ -50,6 +50,7 @@ class AlgorithmsInitializer : public Initializer |
| 50 | 50 | Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); |
| 51 | 51 | Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); |
| 52 | 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 | 55 | // Hash |
| 55 | 56 | Globals->abbreviations.insert("FileName", "Name+Identity:Identical"); | ... | ... |
openbr/plugins/cluster.cpp
| ... | ... | @@ -17,6 +17,7 @@ |
| 17 | 17 | #include <opencv2/flann/flann.hpp> |
| 18 | 18 | |
| 19 | 19 | #include "openbr_internal.h" |
| 20 | +#include "openbr/core/common.h" | |
| 20 | 21 | #include "openbr/core/opencvutils.h" |
| 21 | 22 | |
| 22 | 23 | using namespace cv; |
| ... | ... | @@ -76,6 +77,68 @@ class KMeansTransform : public Transform |
| 76 | 77 | |
| 77 | 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 | 144 | #include "cluster.moc" | ... | ... |
openbr/plugins/crop.cpp
| ... | ... | @@ -151,6 +151,48 @@ class CropBlackTransform : public UntrainableTransform |
| 151 | 151 | |
| 152 | 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 | 196 | } // namespace br |
| 155 | 197 | |
| 156 | 198 | #include "crop.moc" | ... | ... |
openbr/plugins/gallery.cpp
| ... | ... | @@ -212,10 +212,52 @@ class DefaultGallery : public Gallery |
| 212 | 212 | format->write(t); |
| 213 | 213 | } |
| 214 | 214 | }; |
| 215 | + | |
| 215 | 216 | BR_REGISTER(Gallery, DefaultGallery) |
| 216 | 217 | |
| 217 | 218 | /*! |
| 218 | 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 | 261 | * \brief Treat a video as a gallery, making a single template from each frame |
| 220 | 262 | * \author Charles Otto \cite caotto |
| 221 | 263 | */ |
| ... | ... | @@ -499,6 +541,8 @@ BR_REGISTER(Gallery, csvGallery) |
| 499 | 541 | class txtGallery : public Gallery |
| 500 | 542 | { |
| 501 | 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 | 547 | QStringList lines; |
| 504 | 548 | |
| ... | ... | @@ -521,7 +565,7 @@ class txtGallery : public Gallery |
| 521 | 565 | |
| 522 | 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 | 806 | |
| 763 | 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 | 844 | } // namespace br |
| 766 | 845 | |
| 767 | 846 | #include "gallery.moc" | ... | ... |
openbr/plugins/independent.cpp
| ... | ... | @@ -162,6 +162,71 @@ class IndependentTransform : public MetaTransform |
| 162 | 162 | |
| 163 | 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 | 230 | } // namespace br |
| 166 | 231 | |
| 167 | 232 | #include "independent.moc" | ... | ... |
openbr/plugins/integral.cpp
| ... | ... | @@ -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 | 159 | const int channels = src.channels(); |
| 160 | 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 | 167 | void computeDescriptor(const Mat &src, Mat &dst) const |
| ... | ... | @@ -171,11 +171,11 @@ class RecursiveIntegralSamplerTransform : public Transform |
| 171 | 171 | const int columns = src.cols-1; |
| 172 | 172 | |
| 173 | 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 | 179 | const SecondOrderInputDescriptor a(tmp.ptr<float>(0), channels, 1); |
| 180 | 180 | const SecondOrderInputDescriptor b(tmp.ptr<float>(1), channels, 1); |
| 181 | 181 | const SecondOrderInputDescriptor c(tmp.ptr<float>(2), channels, 1); |
| ... | ... | @@ -188,6 +188,7 @@ class RecursiveIntegralSamplerTransform : public Transform |
| 188 | 188 | OutputDescriptor(dst.ptr<float>(2), channels, 1) = ((a+b)-(c+d))/2.f; |
| 189 | 189 | OutputDescriptor(dst.ptr<float>(3), channels, 1) = ((a+c)-(b+d))/2.f; |
| 190 | 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 | 194 | Template subdivide(const Template &src) const | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -60,20 +60,18 @@ class PrintTransform : public UntrainableMetaTransform |
| 60 | 60 | Q_OBJECT |
| 61 | 61 | Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) |
| 62 | 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 | 63 | BR_PROPERTY(bool, error, true) |
| 65 | 64 | BR_PROPERTY(bool, data, false) |
| 66 | - BR_PROPERTY(bool, size, false) | |
| 67 | 65 | |
| 68 | 66 | void project(const Template &src, Template &dst) const |
| 69 | 67 | { |
| 70 | 68 | dst = src; |
| 71 | 69 | const QString nameString = src.file.flat(); |
| 72 | 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 | 400 | |
| 403 | 401 | /*! |
| 404 | 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 | 408 | Q_OBJECT |
| 410 | 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 | 412 | void project(const Template &src, Template &dst) const |
| 414 | 413 | { |
| ... | ... | @@ -417,11 +416,11 @@ class RelabelTransform : public UntrainableMetaTransform |
| 417 | 416 | QRegularExpressionMatch match = re.match(dst.file.baseName()); |
| 418 | 417 | if (!match.hasMatch()) |
| 419 | 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 | 426 | * \ingroup transforms | ... | ... |
openbr/plugins/regions.cpp
| ... | ... | @@ -92,15 +92,15 @@ class CatTransform : public UntrainableMetaTransform |
| 92 | 92 | qFatal("%d partitions does not evenly divide %d matrices.", partitions, src.size()); |
| 93 | 93 | QVector<int> sizes(partitions, 0); |
| 94 | 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 | 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 | 100 | QVector<int> offsets(partitions, 0); |
| 101 | 101 | for (int i=0; i<src.size(); i++) { |
| 102 | 102 | size_t size = src[i].total() * src[i].elemSize(); |
| 103 | - int j = i%partitions; | |
| 103 | + int j = i % partitions; | |
| 104 | 104 | memcpy(&dst[j].data[offsets[j]], src[i].ptr(), size); |
| 105 | 105 | offsets[j] += size; |
| 106 | 106 | } |
| ... | ... | @@ -111,6 +111,25 @@ BR_REGISTER(Transform, CatTransform) |
| 111 | 111 | |
| 112 | 112 | /*! |
| 113 | 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 | 133 | * \brief Wraps OpenCV merge |
| 115 | 134 | * \author Josh Klontz \cite jklontz |
| 116 | 135 | */ | ... | ... |
openbr/plugins/svm.cpp
| ... | ... | @@ -17,18 +17,98 @@ |
| 17 | 17 | #include <QTemporaryFile> |
| 18 | 18 | #include <opencv2/core/core.hpp> |
| 19 | 19 | #include <opencv2/ml/ml.hpp> |
| 20 | -#include "openbr_internal.h" | |
| 21 | 20 | |
| 21 | +#include "openbr_internal.h" | |
| 22 | 22 | #include "openbr/core/opencvutils.h" |
| 23 | 23 | |
| 24 | +using namespace cv; | |
| 25 | + | |
| 24 | 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 | 108 | * \ingroup transforms |
| 29 | 109 | * \brief C. Burges. "A tutorial on support vector machines for pattern recognition," |
| 30 | - * Knowledge Discovery and Data Mining 2(2), 1998. | |
| 31 | 110 | * \author Josh Klontz \cite jklontz |
| 111 | + * Knowledge Discovery and Data Mining 2(2), 1998. | |
| 32 | 112 | */ |
| 33 | 113 | class SVMTransform : public Transform |
| 34 | 114 | { |
| ... | ... | @@ -41,16 +121,11 @@ class SVMTransform : public Transform |
| 41 | 121 | Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false) |
| 42 | 122 | |
| 43 | 123 | public: |
| 44 | - /*! | |
| 45 | - * \brief The Kernel enum | |
| 46 | - */ | |
| 47 | 124 | enum Kernel { Linear = CvSVM::LINEAR, |
| 48 | 125 | Poly = CvSVM::POLY, |
| 49 | 126 | RBF = CvSVM::RBF, |
| 50 | 127 | Sigmoid = CvSVM::SIGMOID }; |
| 51 | - /*! | |
| 52 | - * \brief The Type enum | |
| 53 | - */ | |
| 128 | + | |
| 54 | 129 | enum Type { C_SVC = CvSVM::C_SVC, |
| 55 | 130 | NU_SVC = CvSVM::NU_SVC, |
| 56 | 131 | ONE_CLASS = CvSVM::ONE_CLASS, |
| ... | ... | @@ -63,99 +138,110 @@ private: |
| 63 | 138 | BR_PROPERTY(float, C, -1) |
| 64 | 139 | BR_PROPERTY(float, gamma, -1) |
| 65 | 140 | |
| 66 | - cv::SVM svm; | |
| 141 | + SVM svm; | |
| 67 | 142 | float a, b; |
| 68 | 143 | |
| 69 | -public: | |
| 70 | - SVMTransform() : a(1), b(0) {} | |
| 71 | - | |
| 72 | -private: | |
| 73 | 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 | 151 | void project(const Template &src, Template &dst) const |
| 115 | 152 | { |
| 116 | 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 | 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 | 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 &</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 | 70 | Title = {PittPatt {SDK} 5.2.2}, |
| 71 | 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 | 73 | % Papers |
| 89 | 74 | @inproceedings{arandjelovic12, |
| 90 | 75 | Author={Arandjelovic, R. and Zisserman, A.}, |
| ... | ... | @@ -117,16 +102,22 @@ |
| 117 | 102 | Title = {Average of Synthetic Exact Filters}, |
| 118 | 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 | 111 | @misc{grother12, |
| 121 | 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 | 114 | Month = {mar}, |
| 124 | 115 | Year = {2013}, |
| 125 | 116 | Url = {http://www.nist.gov/itl/iad/ig/frvt-2012.cfm}} |
| 126 | 117 | |
| 127 | 118 | @misc{grother13, |
| 128 | 119 | Author = {Grother, P.}, |
| 129 | - Title = {{MITRE} {FRVT} {Submission} {Question}}, | |
| 120 | + Title = {{MITRE FRVT Submission Question}}, | |
| 130 | 121 | HowPublished = {Personal communication}, |
| 131 | 122 | Month = {jan}, |
| 132 | 123 | Year = {2013}} |
| ... | ... | @@ -158,7 +149,7 @@ |
| 158 | 149 | @article{martinez98, |
| 159 | 150 | Author={Martinez, A.M.}, |
| 160 | 151 | Journal={CVC Technical Report}, |
| 161 | - Title={The AR face database}, | |
| 152 | + Title={The {AR} face database}, | |
| 162 | 153 | Volume={24}, |
| 163 | 154 | Year={1998}} |
| 164 | 155 | |
| ... | ... | @@ -183,7 +174,7 @@ |
| 183 | 174 | Booktitle = {Second international conference on audio and video-based biometric person authentication}, |
| 184 | 175 | Organization = {Citeseer}, |
| 185 | 176 | Pages = {965-966}, |
| 186 | - Title = {XM2VTSDB: The extended M2VTS database}, | |
| 177 | + Title = {{XM2VTSDB}: The extended {M2VTS} database}, | |
| 187 | 178 | Volume = {964}, |
| 188 | 179 | Year = {1999}} |
| 189 | 180 | |
| ... | ... | @@ -224,7 +215,7 @@ |
| 224 | 215 | Author = {Li, S.Z. and Lei, Z. and Ao, M.}, |
| 225 | 216 | Booktitle = {6th IEEE Workshop on Object Tracking and Classification Beyond and in the Visible Spectrum (OTCBVS, in conjunction with CVPR 2009)}, |
| 226 | 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 | 219 | Year = {2009}} |
| 229 | 220 | |
| 230 | 221 | @article{wang09, | ... | ... |