Commit 9e56c8699bff03b7101df5837ef56b8584b2f8ea

Authored by Scott Klum
2 parents 085f6d41 a3465289

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

Showing 348 changed files with 22214 additions and 13804 deletions

Too many changes.

To preserve performance only 100 of 348 files are displayed.

3rdparty/stasm4.0.0/CMakeLists.txt
... ... @@ -13,7 +13,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO
13 13 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/")
14 14  
15 15 # Find Qt 5.0.2
16   -set(QT_DEPENDENCIES Concurrent Core Gui Network Sql Svg Widgets Xml)
  16 +set(QT_DEPENDENCIES Concurrent Core Gui Network Sql Widgets Xml)
17 17 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES})
18 18 find_package(Qt5${QT_DEPENDENCY})
19 19 endforeach()
... ...
CMakeLists.txt
... ... @@ -80,7 +80,7 @@ endif()
80 80 set(QT_DEPENDENCIES Concurrent Core)
81 81 option(BR_EMBEDDED "Limit software dependencies")
82 82 if(NOT ${BR_EMBEDDED})
83   - set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Gui Network Sql Svg Widgets Xml)
  83 + set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Gui Network Sql Widgets Xml)
84 84 endif()
85 85 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES})
86 86 find_package(Qt5${QT_DEPENDENCY})
... ... @@ -89,7 +89,7 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Qt5Core_QTMAIN_LIBRARIES})
89 89  
90 90 # Find OpenCV
91 91 find_package(OpenCV 2.4.5 REQUIRED)
92   -set(OPENCV_DEPENDENCIES opencv_calib3d opencv_core opencv_features2d opencv_flann opencv_gpu opencv_highgui opencv_imgproc opencv_ml opencv_nonfree opencv_objdetect opencv_photo opencv_video)
  92 +set(OPENCV_DEPENDENCIES opencv_calib3d opencv_core opencv_features2d opencv_flann opencv_gpu opencv_highgui opencv_imgproc opencv_ml opencv_nonfree opencv_objdetect opencv_photo opencv_video opencv_videostab opencv_superres opencv_stitching opencv_ocl opencv_legacy opencv_contrib)
93 93 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS})
94 94  
95 95 # Find Alphanum
... ...
openbr/core/cluster.cpp
... ... @@ -82,7 +82,7 @@ float normalizedROD(const Neighborhood &neighborhood, int a, int b)
82 82 return 1.f * (distanceA + distanceB) / std::min(indexA+1, indexB+1);
83 83 }
84 84  
85   -Neighborhood getNeighborhood(const QStringList &simmats)
  85 +Neighborhood br::knnFromSimmat(const QList<cv::Mat> &simmats, int k)
86 86 {
87 87 Neighborhood neighborhood;
88 88  
... ... @@ -99,9 +99,7 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
99 99 int currentRows = -1;
100 100 int columnOffset = 0;
101 101 for (int j=0; j<numGalleries; j++) {
102   - QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmats[i*numGalleries+j]));
103   - br::Template t = format->read();
104   - cv::Mat m = t.m();
  102 + cv::Mat m = simmats[i * numGalleries + j];
105 103 if (j==0) {
106 104 currentRows = m.rows;
107 105 allNeighbors.resize(currentRows);
... ... @@ -132,37 +130,164 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
132 130 // Keep the top matches
133 131 for (int j=0; j<allNeighbors.size(); j++) {
134 132 Neighbors &val = allNeighbors[j];
135   - const int cutoff = 20; // Somewhat arbitrary number of neighbors to keep
  133 + const int cutoff = k; // Number of neighbors to keep
136 134 int keep = std::min(cutoff, val.size());
137 135 std::partial_sort(val.begin(), val.begin()+keep, val.end(), compareNeighbors);
138 136 neighborhood.append((Neighbors)val.mid(0, keep));
139 137 }
140 138 }
141 139  
142   - // Normalize scores
143   - for (int i=0; i<neighborhood.size(); i++) {
144   - Neighbors &neighbors = neighborhood[i];
145   - for (int j=0; j<neighbors.size(); j++) {
146   - Neighbor &neighbor = neighbors[j];
147   - if (neighbor.second == -std::numeric_limits<float>::infinity())
148   - neighbor.second = 0;
149   - else if (neighbor.second == std::numeric_limits<float>::infinity())
150   - neighbor.second = 1;
151   - else
152   - neighbor.second = (neighbor.second - globalMin) / (globalMax - globalMin);
153   - }
  140 + return neighborhood;
  141 +}
  142 +
  143 +// generate k-NN graph from pre-computed similarity matrices
  144 +Neighborhood br::knnFromSimmat(const QStringList &simmats, int k)
  145 +{
  146 + QList<cv::Mat> mats;
  147 + foreach (const QString &simmat, simmats) {
  148 + QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmat));
  149 + br::Template t = format->read();
  150 + mats.append(t);
  151 + }
  152 + return knnFromSimmat(mats, k);
  153 +}
  154 +
  155 +TemplateList knnFromGallery(const QString & galleryName, bool inMemory, const QString & outFile, int k)
  156 +{
  157 + QSharedPointer<Transform> comparison = Transform::fromComparison(Globals->algorithm);
  158 +
  159 + Gallery *tempG = Gallery::make(galleryName);
  160 + qint64 total = tempG->totalSize();
  161 + delete tempG;
  162 + comparison->setPropertyRecursive("galleryName", galleryName+"[dropMetadata=true]");
  163 +
  164 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  165 + if (multiProcess)
  166 + comparison = QSharedPointer<Transform> (br::wrapTransform(comparison.data(), "ProcessWrapper"));
  167 +
  168 + QScopedPointer<Transform> collect(Transform::make("CollectNN+ProgressCounter+Discard", NULL));
  169 + collect->setPropertyRecursive("totalProgress", total);
  170 + collect->setPropertyRecursive("keep", k);
  171 +
  172 + QList<Transform *> tforms;
  173 + tforms.append(comparison.data());
  174 + tforms.append(collect.data());
  175 +
  176 + QScopedPointer<Transform> compareCollect(br::pipeTransforms(tforms));
  177 +
  178 + QSharedPointer <Transform> projector;
  179 + if (inMemory)
  180 + projector = QSharedPointer<Transform> (br::wrapTransform(compareCollect.data(), "Stream(readMode=StreamGallery, endPoint=Discard"));
  181 + else
  182 + projector = QSharedPointer<Transform> (br::wrapTransform(compareCollect.data(), "Stream(readMode=StreamGallery, endPoint=LogNN("+outFile+")+DiscardTemplates)"));
  183 +
  184 + TemplateList input;
  185 + input.append(Template(galleryName));
  186 + TemplateList output;
  187 +
  188 + projector->init();
  189 + projector->projectUpdate(input, output);
  190 +
  191 + return output;
  192 +}
  193 +
  194 +// Generate k-NN graph from a gallery, using the current algorithm for comparison.
  195 +// Direct serialization to file system, k-NN graph is not retained in memory
  196 +void br::knnFromGallery(const QString &galleryName, const QString &outFile, int k)
  197 +{
  198 + knnFromGallery(galleryName, false, outFile, k);
  199 +}
  200 +
  201 +// In-memory graph construction
  202 +Neighborhood br::knnFromGallery(const QString &gallery, int k)
  203 +{
  204 + // Nearest neighbor data current stored as template metadata, so retrieve it
  205 + TemplateList res = knnFromGallery(gallery, true, "", k);
  206 +
  207 + Neighborhood neighborhood;
  208 + foreach (const Template &t, res) {
  209 + Neighbors neighbors = t.file.get<Neighbors>("neighbors");
  210 + neighbors.append(neighbors);
154 211 }
155 212  
156 213 return neighborhood;
157 214 }
158 215  
159   -// Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011
160   -br::Clusters br::ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv)
  216 +Neighborhood br::loadkNN(const QString &infile)
  217 +{
  218 + Neighborhood neighborhood;
  219 + QFile file(infile);
  220 + bool success = file.open(QFile::ReadOnly);
  221 + if (!success) qFatal("Failed to open %s for reading.", qPrintable(infile));
  222 + QStringList lines = QString(file.readAll()).split("\n");
  223 + file.close();
  224 + int min_idx = INT_MAX;
  225 + int max_idx = -1;
  226 + int count = 0;
  227 +
  228 + foreach (const QString &line, lines) {
  229 + Neighbors neighbors;
  230 + count++;
  231 + if (line.trimmed().isEmpty()) {
  232 + neighborhood.append(neighbors);
  233 + continue;
  234 + }
  235 + bool off = false;
  236 + QStringList list = line.trimmed().split(",", QString::SkipEmptyParts);
  237 + foreach (const QString &item, list) {
  238 + QStringList parts = item.trimmed().split(":", QString::SkipEmptyParts);
  239 + bool intOK = true;
  240 + bool floatOK = true;
  241 + int idx = parts[0].toInt(&intOK);
  242 + float score = parts[1].toFloat(&floatOK);
  243 +
  244 + if (idx > max_idx)
  245 + max_idx = idx;
  246 + if (idx <min_idx)
  247 + min_idx = idx;
  248 +
  249 + if (idx >= lines.size()) {
  250 + off = true;
  251 + continue;
  252 + }
  253 + neighbors.append(qMakePair(idx, score));
  254 +
  255 +
  256 + if (!intOK && floatOK)
  257 + qFatal("Failed to parse word: %s", qPrintable(item));
  258 + }
  259 + neighborhood.append(neighbors);
  260 + }
  261 + return neighborhood;
  262 +}
  263 +
  264 +bool br::savekNN(const Neighborhood &neighborhood, const QString &outfile)
  265 +{
  266 + QFile file(outfile);
  267 + bool success = file.open(QFile::WriteOnly);
  268 + if (!success) qFatal("Failed to open %s for writing.", qPrintable(outfile));
  269 +
  270 + foreach (Neighbors neighbors, neighborhood) {
  271 + QString aLine;
  272 + if (!neighbors.empty())
  273 + {
  274 + aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second));
  275 + for (int i=1; i < neighbors.size();i++) {
  276 + aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second));
  277 + }
  278 + }
  279 + aLine += "\n";
  280 + file.write(qPrintable(aLine));
  281 + }
  282 + file.close();
  283 + return true;
  284 +}
  285 +
  286 +
  287 +// Rank-order clustering on a pre-computed k-NN graph
  288 +Clusters br::ClusterGraph(Neighborhood neighborhood, float aggressiveness, const QString &csv)
161 289 {
162   - qDebug("Clustering %d simmat(s), aggressiveness %f", simmats.size(), aggressiveness);
163 290  
164   - // Read in gallery parts, keeping top neighbors of each template
165   - Neighborhood neighborhood = getNeighborhood(simmats);
166 291 const int cutoff = neighborhood.first().size();
167 292 const float threshold = 3*cutoff/4 * aggressiveness/5;
168 293  
... ... @@ -239,9 +364,39 @@ br::Clusters br::ClusterGallery(const QStringList &amp;simmats, float aggressiveness
239 364 neighborhood = newNeighborhood;
240 365 }
241 366  
242   - // Save clusters
243 367 if (!csv.isEmpty())
244 368 WriteClusters(clusters, csv);
  369 +
  370 + return clusters;
  371 +}
  372 +
  373 +Clusters br::ClusterGraph(const QString & knnName, float aggressiveness, const QString &csv)
  374 +{
  375 + Neighborhood neighbors = loadkNN(knnName);
  376 + return ClusterGraph(neighbors, aggressiveness, csv);
  377 +}
  378 +
  379 +// Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011
  380 +br::Clusters br::ClusterSimmat(const QList<cv::Mat> &simmats, float aggressiveness, const QString &csv)
  381 +{
  382 + qDebug("Clustering %d simmat(s), aggressiveness %f", simmats.size(), aggressiveness);
  383 +
  384 + // Read in gallery parts, keeping top neighbors of each template
  385 + Neighborhood neighborhood = knnFromSimmat(simmats);
  386 +
  387 + return ClusterGraph(neighborhood, aggressiveness, csv);
  388 +}
  389 +
  390 +br::Clusters br::ClusterSimmat(const QStringList &simmats, float aggressiveness, const QString &csv)
  391 +{
  392 + QList<cv::Mat> mats;
  393 + foreach (const QString &simmat, simmats) {
  394 + QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmat));
  395 + br::Template t = format->read();
  396 + mats.append(t);
  397 + }
  398 +
  399 + Clusters clusters = ClusterSimmat(mats, aggressiveness, csv);
245 400 return clusters;
246 401 }
247 402  
... ...
openbr/core/cluster.h
... ... @@ -21,15 +21,46 @@
21 21 #include <QString>
22 22 #include <QStringList>
23 23 #include <QVector>
  24 +#include <openbr/openbr_plugin.h>
  25 +#include <openbr/plugins/openbr_internal.h>
24 26  
25 27 namespace br
26 28 {
27 29 typedef QList<int> Cluster; // List of indices into galleries
28 30 typedef QVector<Cluster> Clusters;
29 31  
30   - Clusters ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv);
  32 + // generate k-NN graph from pre-computed similarity matrices
  33 + Neighborhood knnFromSimmat(const QStringList &simmats, int k = 20);
  34 + Neighborhood knnFromSimmat(const QList<cv::Mat> &simmats, int k = 20);
  35 +
  36 + // Generate k-NN graph from a gallery, using the current algorithm for comparison.
  37 + // direct serialization to file system.
  38 + void knnFromGallery(const QString &galleryName, const QString & outFile, int k = 20);
  39 + // in memory graph computation
  40 + Neighborhood knnFromGallery(const QString &gallery, int k = 20);
  41 +
  42 + // Load k-NN graph from a file with the following ascii format:
  43 + // One line per sample, each line lists the top k neighbors for the sample as follows:
  44 + // index1:score1,index2:score2,...,indexk:scorek
  45 + Neighborhood loadkNN(const QString &fname);
  46 +
  47 + // Save k-NN graph to file
  48 + bool savekNN(const Neighborhood &neighborhood, const QString &outfile);
  49 +
  50 + // Rank-order clustering on a pre-computed k-NN graph
  51 + Clusters ClusterGraph(Neighborhood neighbors, float aggresssiveness, const QString &csv = "");
  52 + Clusters ClusterGraph(const QString & knnName, float aggressiveness, const QString &csv = "");
  53 +
  54 + // Given a similarity matrix, compute the k-NN graph, then perform rank-order clustering.
  55 + Clusters ClusterSimmat(const QList<cv::Mat> &simmats, float aggressiveness, const QString &csv = "");
  56 + Clusters ClusterSimmat(const QStringList &simmats, float aggressiveness, const QString &csv = "");
  57 +
  58 + // evaluate clustering results in csv, reading ground truth data from gallery input, using truth_property
  59 + // as the key for ground truth labels.
31 60 void EvalClustering(const QString &csv, const QString &input, QString truth_property);
32 61  
  62 + // Read/write clusters from a text format, 1 line = 1 cluster, each line contains comma separated list
  63 + // of assigned indices.
33 64 Clusters ReadClusters(const QString &csv);
34 65 void WriteClusters(const Clusters &clusters, const QString &csv);
35 66 }
... ...
openbr/core/core.cpp
... ... @@ -138,6 +138,13 @@ struct AlgorithmCore
138 138  
139 139 void load(const QString &model)
140 140 {
  141 + // since we are loading an existing model, add its path to the search list for submodels
  142 + // assuming it is not already present.
  143 + QFileInfo finfo(model);
  144 + QString path = finfo.absolutePath();
  145 + if (!Globals->modelSearch.contains(path))
  146 + Globals->modelSearch.append(path);
  147 +
141 148 QtUtils::BlockCompression compressedRead;
142 149 QFile inFile(model);
143 150 compressedRead.setBasis(&inFile);
... ... @@ -762,5 +769,15 @@ QSharedPointer&lt;br::Distance&gt; br::Distance::fromAlgorithm(const QString &amp;algorith
762 769 return AlgorithmManager::getAlgorithm(algorithm)->distance;
763 770 }
764 771  
  772 +class pathInitializer : public Initializer
  773 +{
  774 + Q_OBJECT
  775 + void initialize() const
  776 + {
  777 + Globals->modelSearch.append(Globals->sdkPath + "/share/openbr/models/transforms/");
  778 + }
  779 +
  780 +};
  781 +BR_REGISTER(Initializer, pathInitializer)
765 782  
766 783 #include "core.moc"
... ...
openbr/core/qtutils.cpp
... ... @@ -500,14 +500,15 @@ QString getAbsolutePath(const QString &amp;filename)
500 500 return QFileInfo(filename).absoluteFilePath();
501 501 }
502 502  
  503 +const int base_block = 100000000;
  504 +
503 505 BlockCompression::BlockCompression(QIODevice *_basis)
504 506 {
505   - blockSize = 100000000;
  507 + blockSize = base_block;
506 508 setBasis(_basis);
507 509 }
508 510  
509   -BlockCompression::BlockCompression() { blockSize = 100000000; };
510   -
  511 +BlockCompression::BlockCompression() { blockSize = base_block;};
511 512  
512 513 bool BlockCompression::open(QIODevice::OpenMode mode)
513 514 {
... ... @@ -521,14 +522,22 @@ bool BlockCompression::open(QIODevice::OpenMode mode)
521 522 blockWriter.setDevice(basis);
522 523  
523 524 if (mode & QIODevice::WriteOnly) {
524   - precompressedBlockWriter = new QBuffer;
525   - precompressedBlockWriter->open(QIODevice::ReadWrite);
  525 + precompressedBlockWriter.open(QIODevice::WriteOnly);
526 526 }
527 527 else if (mode & QIODevice::ReadOnly) {
  528 +
  529 + // Read an initial compressed block from the underlying QIODevice,
  530 + // decompress, and set up a reader on it
528 531 QByteArray compressedBlock;
529   - blockReader >> compressedBlock;
  532 + quint32 block_size;
  533 + blockReader >> block_size;
  534 + compressedBlock.resize(block_size);
  535 + int read_count = blockReader.readRawData(compressedBlock.data(), block_size);
  536 + if (read_count != block_size)
  537 + qFatal("Failed to read initial block");
530 538  
531 539 decompressedBlock = qUncompress(compressedBlock);
  540 +
532 541 decompressedBlockReader.setBuffer(&decompressedBlock);
533 542 decompressedBlockReader.open(QIODevice::ReadOnly);
534 543 }
... ... @@ -538,11 +547,17 @@ bool BlockCompression::open(QIODevice::OpenMode mode)
538 547  
539 548 void BlockCompression::close()
540 549 {
541   - // flush output buffer
542   - if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter) {
543   - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1);
544   - blockWriter << compressedBlock;
  550 + // flush output buffer, since we may have a partial block which hasn't been
  551 + // written to disk yet.
  552 + if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter.isOpen()) {
  553 + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer());
  554 + precompressedBlockWriter.close();
  555 +
  556 + quint32 bsize= compressedBlock.size();
  557 + blockWriter << bsize;
  558 + blockWriter.writeRawData(compressedBlock.data(), compressedBlock.size());
545 559 }
  560 + // close the underlying device.
546 561 basis->close();
547 562 }
548 563  
... ... @@ -557,8 +572,10 @@ void BlockCompression::setBasis(QIODevice *_basis)
557 572 // block from basis
558 573 qint64 BlockCompression::readData(char *data, qint64 remaining)
559 574 {
  575 + qint64 initial = remaining;
560 576 qint64 read = 0;
561 577 while (remaining > 0) {
  578 + // attempt to read the target amount of data
562 579 qint64 single_read = decompressedBlockReader.read(data, remaining);
563 580 if (single_read == -1)
564 581 qFatal("miss read");
... ... @@ -567,13 +584,21 @@ qint64 BlockCompression::readData(char *data, qint64 remaining)
567 584 read += single_read;
568 585 data += single_read;
569 586  
570   - // need a new block
  587 + // need a new block if we didn't get enough bytes from the previous read
571 588 if (remaining > 0) {
572 589 QByteArray compressedBlock;
573   - blockReader >> compressedBlock;
574   - if (compressedBlock.size() == 0) {
575   - return read;
576   - }
  590 +
  591 + // read the size of the next block
  592 + quint32 block_size;
  593 + blockReader >> block_size;
  594 + if (block_size == 0)
  595 + break;
  596 +
  597 + compressedBlock.resize(block_size);
  598 + int actualRead = blockReader.readRawData(compressedBlock.data(), block_size);
  599 + if (actualRead != block_size)
  600 + qFatal("Bad read on nominal block size: %d, only got %d", block_size, remaining);
  601 +
577 602 decompressedBlock = qUncompress(compressedBlock);
578 603  
579 604 decompressedBlockReader.close();
... ... @@ -581,7 +606,12 @@ qint64 BlockCompression::readData(char *data, qint64 remaining)
581 606 decompressedBlockReader.open(QIODevice::ReadOnly);
582 607 }
583 608 }
584   - return blockReader.atEnd() && !basis->isReadable() ? -1 : read;
  609 +
  610 + bool condition = blockReader.atEnd() && !basis->isReadable() ;
  611 + if (condition)
  612 + qWarning("Returning -1 from read");
  613 +
  614 + return condition ? -1 : read;
585 615 }
586 616  
587 617 bool BlockCompression::isSequential() const
... ... @@ -591,36 +621,57 @@ bool BlockCompression::isSequential() const
591 621  
592 622 qint64 BlockCompression::writeData(const char *data, qint64 remaining)
593 623 {
  624 + const char * endPoint = data + remaining;
  625 + qint64 initial = remaining;
  626 +
594 627 qint64 written = 0;
595 628  
596 629 while (remaining > 0) {
597 630 // how much more can be put in this buffer?
598   - qint64 capacity = blockSize - precompressedBlockWriter->pos();
  631 + qint64 capacity = blockSize - precompressedBlockWriter.pos();
  632 + if (capacity < 0)
  633 + qFatal("Negative capacity!!!");
599 634  
600 635 // don't try to write beyond capacity
601 636 qint64 write_size = qMin(capacity, remaining);
602 637  
603   - qint64 singleWrite = precompressedBlockWriter->write(data, write_size);
604   - // ignore the error case here, we consdier basis's failure mode the real
605   - // end case
  638 + qint64 singleWrite = precompressedBlockWriter.write(data, write_size);
  639 +
606 640 if (singleWrite == -1)
607   - singleWrite = 0;
  641 + qFatal("matrix write failure?");
608 642  
609 643 remaining -= singleWrite;
610 644 data += singleWrite;
611 645 written += singleWrite;
  646 + if (data > endPoint)
  647 + qFatal("Wrote past the end");
612 648  
613 649 if (remaining > 0) {
614   - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1);
  650 + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer(), -1);
615 651  
616   - if (compressedBlock.size() != 0)
617   - blockWriter << compressedBlock;
  652 + if (precompressedBlockWriter.buffer().size() != 0) {
  653 + quint32 block_size = compressedBlock.size();
  654 + blockWriter << block_size;
618 655  
619   - delete precompressedBlockWriter;
620   - precompressedBlockWriter = new QBuffer;
621   - precompressedBlockWriter->open(QIODevice::ReadWrite);
  656 + int write_count = blockWriter.writeRawData(compressedBlock.data(), block_size);
  657 + if (write_count != block_size)
  658 + qFatal("Didn't write enough data");
  659 + }
  660 + else
  661 + qFatal("serialized empty compressed block (?)");
  662 +
  663 + precompressedBlockWriter.close();
  664 + precompressedBlockWriter.open(QIODevice::WriteOnly);
622 665 }
623 666 }
  667 +
  668 + if (written != initial)
  669 + qFatal("didn't write enough bytes");
  670 +
  671 + bool condition = basis->isWritable();
  672 + if (!condition)
  673 + qWarning("Returning -1 from write");
  674 +
624 675 return basis->isWritable() ? written : -1;
625 676 }
626 677  
... ...
openbr/core/qtutils.h
... ... @@ -122,7 +122,7 @@ namespace QtUtils
122 122  
123 123 // write to a QByteArray, when max block sized is reached, compress and write
124 124 // it to basis
125   - QBuffer * precompressedBlockWriter;
  125 + QBuffer precompressedBlockWriter;
126 126 QDataStream blockWriter;
127 127 qint64 writeData(const char *data, qint64 remaining);
128 128 };
... ...
1   -Subproject commit e3aa915a5cfc3ee0332f566ae4f13370007964a1
  1 +Subproject commit cd22014f9bd446f26c501e06b1170441bf872408
... ...
openbr/openbr.cpp
... ... @@ -59,7 +59,7 @@ void br_cat(int num_input_galleries, const char *input_galleries[], const char *
59 59  
60 60 void br_cluster(int num_simmats, const char *simmats[], float aggressiveness, const char *csv)
61 61 {
62   - ClusterGallery(QtUtils::toStringList(num_simmats, simmats), aggressiveness, csv);
  62 + ClusterSimmat(QtUtils::toStringList(num_simmats, simmats), aggressiveness, csv);
63 63 }
64 64  
65 65 void br_combine_masks(int num_input_masks, const char *input_masks[], const char *output_mask, const char *method)
... ...
openbr/openbr_plugin.h
... ... @@ -754,6 +754,12 @@ public:
754 754 Q_PROPERTY(int crossValidate READ get_crossValidate WRITE set_crossValidate RESET reset_crossValidate)
755 755 BR_PROPERTY(int, crossValidate, 0)
756 756  
  757 + /*!
  758 + * \brief List of paths sub-models will be searched for on
  759 + */
  760 + Q_PROPERTY(QList<QString> modelSearch READ get_modelSearch WRITE set_modelSearch RESET reset_modelSearch)
  761 + BR_PROPERTY(QList<QString>, modelSearch, QList<QString>() )
  762 +
757 763 QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */
758 764 QTime startTime; /*!< \brief Used to estimate timeRemaining(). */
759 765  
... ...
openbr/plugins/classification/adaboost.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/opencvutils.h>
  19 +
  20 +using namespace cv;
  21 +
  22 +namespace br
  23 +{
  24 +
  25 +/*!
  26 + * \ingroup transforms
  27 + * \brief Wraps OpenCV's Ada Boost framework
  28 + * \author Scott Klum \cite sklum
  29 + * \brief http://docs.opencv.org/modules/ml/doc/boosting.html
  30 + */
  31 +class AdaBoostTransform : public Transform
  32 +{
  33 + Q_OBJECT
  34 + Q_ENUMS(Type)
  35 + Q_ENUMS(SplitCriteria)
  36 +
  37 + Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false)
  38 + Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false)
  39 + Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false)
  40 + Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false)
  41 + Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false)
  42 + Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false)
  43 + Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false)
  44 + Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false)
  45 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  46 + Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false)
  47 +
  48 +public:
  49 + enum Type { Discrete = CvBoost::DISCRETE,
  50 + Real = CvBoost::REAL,
  51 + Logit = CvBoost::LOGIT,
  52 + Gentle = CvBoost::GENTLE};
  53 +
  54 + enum SplitCriteria { Default = CvBoost::DEFAULT,
  55 + Gini = CvBoost::GINI,
  56 + Misclass = CvBoost::MISCLASS,
  57 + Sqerr = CvBoost::SQERR};
  58 +
  59 +private:
  60 + BR_PROPERTY(Type, type, Real)
  61 + BR_PROPERTY(SplitCriteria, splitCriteria, Default)
  62 + BR_PROPERTY(int, weakCount, 100)
  63 + BR_PROPERTY(float, trimRate, .95)
  64 + BR_PROPERTY(int, folds, 0)
  65 + BR_PROPERTY(int, maxDepth, 1)
  66 + BR_PROPERTY(bool, returnConfidence, true)
  67 + BR_PROPERTY(bool, overwriteMat, true)
  68 + BR_PROPERTY(QString, inputVariable, "Label")
  69 + BR_PROPERTY(QString, outputVariable, "")
  70 +
  71 + CvBoost boost;
  72 +
  73 + void train(const TemplateList &data)
  74 + {
  75 + Mat samples = OpenCVUtils::toMat(data.data());
  76 + Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable));
  77 +
  78 + Mat types = Mat(samples.cols + 1, 1, CV_8U);
  79 + types.setTo(Scalar(CV_VAR_NUMERICAL));
  80 + types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL;
  81 +
  82 + CvBoostParams params;
  83 + params.boost_type = type;
  84 + params.split_criteria = splitCriteria;
  85 + params.weak_count = weakCount;
  86 + params.weight_trim_rate = trimRate;
  87 + params.cv_folds = folds;
  88 + params.max_depth = maxDepth;
  89 +
  90 + boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(),
  91 + params);
  92 + }
  93 +
  94 + void project(const Template &src, Template &dst) const
  95 + {
  96 + dst = src;
  97 + float response;
  98 + if (returnConfidence) {
  99 + response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount;
  100 + } else {
  101 + response = boost.predict(src.m().reshape(1,1));
  102 + }
  103 +
  104 + if (overwriteMat) {
  105 + dst.m() = Mat(1, 1, CV_32F);
  106 + dst.m().at<float>(0, 0) = response;
  107 + } else {
  108 + dst.file.set(outputVariable, response);
  109 + }
  110 + }
  111 +
  112 + void load(QDataStream &stream)
  113 + {
  114 + OpenCVUtils::loadModel(boost,stream);
  115 + }
  116 +
  117 + void store(QDataStream &stream) const
  118 + {
  119 + OpenCVUtils::storeModel(boost,stream);
  120 + }
  121 +
  122 +
  123 + void init()
  124 + {
  125 + if (outputVariable.isEmpty())
  126 + outputVariable = inputVariable;
  127 + }
  128 +};
  129 +
  130 +BR_REGISTER(Transform, AdaBoostTransform)
  131 +
  132 +} // namespace br
  133 +
  134 +#include "classification/adaboost.moc"
... ...
openbr/plugins/dlib.cpp renamed to openbr/plugins/classification/dlib.cpp
1   -#include "openbr_internal.h"
  1 +#include "openbr/plugins/openbr_internal.h"
2 2 #include "openbr/core/qtutils.h"
3 3 #include "openbr/core/eigenutils.h"
4 4  
... ...
openbr/plugins/ebif.cpp renamed to openbr/plugins/classification/ebif.cpp
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
1 17 #include <opencv2/imgproc/imgproc.hpp>
2 18  
3   -#include "openbr_internal.h"
4   -#include "openbr/core/common.h"
5   -#include "openbr/core/opencvutils.h"
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/common.h>
  21 +#include <openbr/core/opencvutils.h>
6 22  
7 23 using namespace cv;
8 24  
... ... @@ -128,4 +144,4 @@ BR_REGISTER(Transform, EBIFTransform)
128 144  
129 145 } // namespace br
130 146  
131   -#include "ebif.moc"
  147 +#include "classification/ebif.moc"
... ...
openbr/plugins/tree.cpp renamed to openbr/plugins/classification/forest.cpp
1   -#include "openbr_internal.h"
2   -#include "openbr/core/opencvutils.h"
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/opencvutils.h>
3 19  
4   -using namespace std;
5 20 using namespace cv;
6 21  
7 22 namespace br
... ... @@ -250,113 +265,6 @@ class ForestInductionTransform : public ForestTransform
250 265  
251 266 BR_REGISTER(Transform, ForestInductionTransform)
252 267  
253   -/*!
254   - * \ingroup transforms
255   - * \brief Wraps OpenCV's Ada Boost framework
256   - * \author Scott Klum \cite sklum
257   - * \brief http://docs.opencv.org/modules/ml/doc/boosting.html
258   - */
259   -class AdaBoostTransform : public Transform
260   -{
261   - Q_OBJECT
262   - Q_ENUMS(Type)
263   - Q_ENUMS(SplitCriteria)
264   -
265   - Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false)
266   - Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false)
267   - Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false)
268   - Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false)
269   - Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false)
270   - Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false)
271   - Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false)
272   - Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false)
273   - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
274   - Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false)
275   -
276   -public:
277   - enum Type { Discrete = CvBoost::DISCRETE,
278   - Real = CvBoost::REAL,
279   - Logit = CvBoost::LOGIT,
280   - Gentle = CvBoost::GENTLE};
281   -
282   - enum SplitCriteria { Default = CvBoost::DEFAULT,
283   - Gini = CvBoost::GINI,
284   - Misclass = CvBoost::MISCLASS,
285   - Sqerr = CvBoost::SQERR};
286   -
287   -private:
288   - BR_PROPERTY(Type, type, Real)
289   - BR_PROPERTY(SplitCriteria, splitCriteria, Default)
290   - BR_PROPERTY(int, weakCount, 100)
291   - BR_PROPERTY(float, trimRate, .95)
292   - BR_PROPERTY(int, folds, 0)
293   - BR_PROPERTY(int, maxDepth, 1)
294   - BR_PROPERTY(bool, returnConfidence, true)
295   - BR_PROPERTY(bool, overwriteMat, true)
296   - BR_PROPERTY(QString, inputVariable, "Label")
297   - BR_PROPERTY(QString, outputVariable, "")
298   -
299   - CvBoost boost;
300   -
301   - void train(const TemplateList &data)
302   - {
303   - Mat samples = OpenCVUtils::toMat(data.data());
304   - Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable));
305   -
306   - Mat types = Mat(samples.cols + 1, 1, CV_8U);
307   - types.setTo(Scalar(CV_VAR_NUMERICAL));
308   - types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL;
309   -
310   - CvBoostParams params;
311   - params.boost_type = type;
312   - params.split_criteria = splitCriteria;
313   - params.weak_count = weakCount;
314   - params.weight_trim_rate = trimRate;
315   - params.cv_folds = folds;
316   - params.max_depth = maxDepth;
317   -
318   - boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(),
319   - params);
320   - }
321   -
322   - void project(const Template &src, Template &dst) const
323   - {
324   - dst = src;
325   - float response;
326   - if (returnConfidence) {
327   - response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount;
328   - } else {
329   - response = boost.predict(src.m().reshape(1,1));
330   - }
331   -
332   - if (overwriteMat) {
333   - dst.m() = Mat(1, 1, CV_32F);
334   - dst.m().at<float>(0, 0) = response;
335   - } else {
336   - dst.file.set(outputVariable, response);
337   - }
338   - }
339   -
340   - void load(QDataStream &stream)
341   - {
342   - OpenCVUtils::loadModel(boost,stream);
343   - }
344   -
345   - void store(QDataStream &stream) const
346   - {
347   - OpenCVUtils::storeModel(boost,stream);
348   - }
349   -
350   -
351   - void init()
352   - {
353   - if (outputVariable.isEmpty())
354   - outputVariable = inputVariable;
355   - }
356   -};
357   -
358   -BR_REGISTER(Transform, AdaBoostTransform)
359   -
360 268 } // namespace br
361 269  
362   -#include "tree.moc"
  270 +#include "classification/forest.moc"
... ...
openbr/plugins/ipc2013.cpp renamed to openbr/plugins/classification/ipc2013.cpp
1   -#include "openbr_internal.h"
2 1 #include <pxcaccelerator.h>
3 2 #include <pxcface.h>
4 3 #include <pxcimage.h>
5 4 #include <pxcsession.h>
6 5  
  6 +#include <openbr/plugins/openbr_internal.h>
  7 +
7 8 using namespace br;
8 9  
9 10 static PXCSession *pxcSession = NULL;
... ...
openbr/plugins/eigen3.cpp renamed to openbr/plugins/classification/lda.cpp
... ... @@ -15,12 +15,14 @@
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <Eigen/Dense>
  18 +#include <opencv2/imgproc/imgproc.hpp>
  19 +#include <opencv2/highgui/highgui.hpp>
18 20  
19   -#include "openbr_internal.h"
  21 +#include <openbr/plugins/openbr_internal.h>
20 22  
21   -#include "openbr/core/common.h"
22   -#include "openbr/core/eigenutils.h"
23   -#include "openbr/core/opencvutils.h"
  23 +#include <openbr/core/common.h>
  24 +#include <openbr/core/eigenutils.h>
  25 +#include <openbr/core/opencvutils.h>
24 26  
25 27 namespace br
26 28 {
... ... @@ -652,46 +654,609 @@ class SparseLDATransform : public Transform
652 654  
653 655 BR_REGISTER(Transform, SparseLDATransform)
654 656  
  657 +using namespace Eigen;
  658 +using namespace cv;
  659 +
655 660 /*!
656   - * \ingroup distances
657   - * \brief L1 distance computed using eigen.
  661 + * \ingroup transforms
  662 + * \brief Projects input into a within-class minimizing subspace.
  663 + *
  664 + * Like LDA but without the explicit between-class consideration.
  665 + *
  666 + * \par Compression
  667 + * Projection matricies can become quite large, resulting in proportionally large model files.
  668 + * WCDA automatically alleviates this issue with lossy compression of the projection matrix.
  669 + * Each element is stored as an 8-bit integer instead of a 32-bit float, resulting in a 75% reduction in the size of the projection matrix.
  670 + * A non-linear (sqrt) scaling is used because element values are distributed around 0, in affect allowing for higher precision storage of the more frequently occuring values.
  671 + *
658 672 * \author Josh Klontz \cite jklontz
659 673 */
660   -class L1Distance : public UntrainableDistance
  674 +class WCDATransform : public Transform
661 675 {
662 676 Q_OBJECT
  677 + Q_PROPERTY(float keep READ get_keep WRITE set_keep RESET reset_keep STORED false)
  678 + BR_PROPERTY(float, keep, 0.98)
  679 +
  680 + VectorXf mean;
  681 + MatrixXf projection;
  682 +
  683 + typedef Matrix<quint8, Dynamic, Dynamic> CompressedMatrix;
  684 + CompressedMatrix compressed;
  685 + float a, b;
663 686  
664   - float compare(const cv::Mat &a, const cv::Mat &b) const
  687 + static CompressedMatrix compress(MatrixXf src, float &a, float &b)
665 688 {
666   - const int size = a.rows * a.cols;
667   - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size);
668   - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size);
669   - return (aMap-bMap).cwiseAbs().sum();
  689 + for (int i=0; i<src.rows(); i++)
  690 + for (int j=0; j<src.cols(); j++) {
  691 + float &element = src(i, j);
  692 + element = sqrtf(fabsf(element)) * ((element >= 0) ? 1 : -1);
  693 + }
  694 + b = src.minCoeff();
  695 + a = (src.maxCoeff() - b) / 255;
  696 + return ((src.array() - b) / a).cast<quint8>();
670 697 }
  698 +
  699 + static MatrixXf decompress(const CompressedMatrix &src, float a, float b)
  700 + {
  701 + MatrixXf dst = src.cast<float>().array() * a + b;
  702 + for (int i=0; i<dst.rows(); i++)
  703 + for (int j=0; j<dst.cols(); j++) {
  704 + float &element = dst(i, j);
  705 + element = (element * element) * ((element >= 0) ? 1 : -1);
  706 + }
  707 + return dst;
  708 + }
  709 +
  710 + void train(const TemplateList &_templates)
  711 + {
  712 + // Relabel ensures that class values range from 0 to numClasses-1.
  713 + const TemplateList templates = TemplateList::relabel(_templates, "Label", false);
  714 + const int instances = templates.size();
  715 + const int dimsIn = templates.first().m().rows * templates.first().m().cols;
  716 +
  717 + // Map data into Eigen
  718 + MatrixXf data(dimsIn, instances);
  719 + for (int i=0; i<instances; i++)
  720 + data.col(i) = Map<const VectorXf>(templates[i].m().ptr<float>(), dimsIn);
  721 +
  722 + // Perform PCA dimensionality reduction
  723 + VectorXf pcaEvals;
  724 + MatrixXf pcaEvecs;
  725 + trainCore(data, keep, mean, pcaEvals, pcaEvecs);
  726 + data = pcaEvecs.transpose() * (data.colwise() - mean);
  727 +
  728 + // Get ground truth
  729 + const QList<int> classes = File::get<int>(templates, "Label");
  730 + const QMap<int, int> classCounts = templates.countValues<int>("Label");
  731 + const int numClasses = classCounts.size();
  732 +
  733 + // Compute and remove the class means
  734 + MatrixXf classMeans = MatrixXf::Zero(data.rows(), numClasses);
  735 + for (int i=0; i<instances; i++) classMeans.col(classes[i]) += data.col(i);
  736 + for (int i=0; i<numClasses; i++) classMeans.col(i) /= classCounts[i];
  737 + for (int i=0; i<instances; i++) data.col(i) -= classMeans.col(classes[i]);
  738 +
  739 + // Compute the within-class projection
  740 + VectorXf wcMean, wcEvals;
  741 + MatrixXf wcEvecs;
  742 + trainCore(data, keep, wcMean, wcEvals, wcEvecs);
  743 +
  744 + // This has the effect of whitening the within-class scatter.
  745 + // In effect, this minimizes the within-class variation energy.
  746 + for (int i=0; i<keep; i++)
  747 + wcEvecs.col(i) /= sqrt(wcEvals(i));
  748 +
  749 + projection = wcEvecs.transpose() * pcaEvecs.transpose();
  750 +
  751 + // Compress and restore the projection matrix
  752 + compressed = compress(projection, a, b);
  753 + projection = decompress(compressed, a, b);
  754 + }
  755 +
  756 + static void trainCore(MatrixXf data, float keep, VectorXf &mean, VectorXf &eVals, MatrixXf &eVecs)
  757 + {
  758 + const int dimsIn = data.rows();
  759 + const int instances = data.cols();
  760 + const bool dominantEigenEstimation = (dimsIn > instances);
  761 +
  762 + // Compute and remove mean
  763 + mean = data.rowwise().sum() / instances;
  764 + data.colwise() -= mean;
  765 +
  766 + // Calculate and normalize covariance matrix
  767 + MatrixXf cov;
  768 + if (dominantEigenEstimation) cov = data.transpose() * data;
  769 + else cov = data * data.transpose();
  770 + cov /= (instances-1);
  771 +
  772 + // Compute eigendecomposition, returning eigenvectors/eigenvalues in increasing order by eigenvalue.
  773 + SelfAdjointEigenSolver<MatrixXf> eSolver(cov);
  774 + VectorXf allEVals = eSolver.eigenvalues();
  775 + MatrixXf allEVecs = eSolver.eigenvectors();
  776 + if (dominantEigenEstimation)
  777 + allEVecs = data * allEVecs;
  778 +
  779 + if (keep < 1) {
  780 + // Keep eigenvectors that retain a certain energy percentage.
  781 + const float desiredEnergy = keep * allEVals.sum();
  782 + float currentEnergy = 0;
  783 + int i = 0;
  784 + while ((currentEnergy < desiredEnergy) && (i < allEVals.rows())) {
  785 + currentEnergy += allEVals(allEVals.rows()-(i+1));
  786 + i++;
  787 + }
  788 + keep = i;
  789 + } else {
  790 + if (keep > allEVals.rows()) {
  791 + qWarning("Insufficient samples, needed at least %d but only got %d.", (int)keep, (int)allEVals.rows());
  792 + keep = allEVals.rows();
  793 + }
  794 + }
  795 +
  796 + // Keep highest energy vectors
  797 + eVals = VectorXf((int)keep);
  798 + eVecs = MatrixXf(allEVecs.rows(), (int)keep);
  799 + for (int i=0; i<keep; i++) {
  800 + const int index = allEVals.rows()-(i+1);
  801 + eVals(i) = allEVals(index);
  802 + eVecs.col(i) = allEVecs.col(index) / allEVecs.col(index).norm();
  803 + }
  804 + }
  805 +
  806 + void project(const Template &src, Template &dst) const
  807 + {
  808 + dst = Mat(1, projection.rows(), CV_32FC1);
  809 + Map<const VectorXf> inMap(src.m().ptr<float>(), src.m().rows * src.m().cols);
  810 + Map<VectorXf> outMap(dst.m().ptr<float>(), projection.rows());
  811 + outMap = projection * (inMap - mean);
  812 + }
  813 +
  814 + void store(QDataStream &stream) const
  815 + {
  816 + stream << mean << compressed << a << b;
  817 + }
  818 +
  819 + void load(QDataStream &stream)
  820 + {
  821 + stream >> mean >> compressed >> a >> b;
  822 + projection = decompress(compressed, a, b);
  823 + }
  824 +};
  825 +
  826 +BR_REGISTER(Transform, WCDATransform)
  827 +
  828 +// For use in BBLDAAlignmentTransform
  829 +// A single decision boundary with gaussian distributed responses
  830 +struct DecisionBoundary
  831 +{
  832 + VectorXf function;
  833 + float positiveMean, negativeMean, positiveSD, negativeSD;
671 834 };
672 835  
673   -BR_REGISTER(Distance, L1Distance)
  836 +QDataStream &operator<<(QDataStream &stream, const DecisionBoundary &db)
  837 +{
  838 + return stream << db.function << db.positiveMean << db.negativeMean << db.positiveSD << db.negativeSD;
  839 +}
  840 +
  841 +QDataStream &operator>>(QDataStream &stream, DecisionBoundary &db)
  842 +{
  843 + return stream >> db.function >> db.positiveMean >> db.negativeMean >> db.positiveSD >> db.negativeSD;
  844 +}
674 845  
675 846 /*!
676   - * \ingroup distances
677   - * \brief L2 distance computed using eigen.
678   - * \author Josh Klontz \cite jklontz
  847 + * \ingroup transforms
  848 + * \brief Boosted Binary LDA classifier for local alignment.
679 849 */
680   -class L2Distance : public UntrainableDistance
  850 +class BBLDAAlignmentTransform : public MetaTransform
681 851 {
682 852 Q_OBJECT
  853 + Q_PROPERTY(QList<int> anchors READ get_anchors WRITE set_anchors RESET reset_anchors STORED false) // A list of two indicies to provide initial rotation and scaling of training data
  854 + Q_PROPERTY(QString detectionKey READ get_detectionKey WRITE set_detectionKey RESET reset_detectionKey STORED false) // Metadata key containing the detection bounding box
  855 + Q_PROPERTY(int iad READ get_iad WRITE set_iad RESET reset_iad STORED false) // Inter-anchor distance in pixels
  856 + Q_PROPERTY(float radius READ get_radius WRITE set_radius RESET reset_radius STORED false) // Kernel size as a fraction of IAD
  857 + Q_PROPERTY(int resolution READ get_resolution WRITE set_resolution RESET reset_resolution STORED false) // Project resolution for sampling rotation and scale
  858 + BR_PROPERTY(QList<int>, anchors, QList<int>())
  859 + BR_PROPERTY(QString, detectionKey, "FrontalFace")
  860 + BR_PROPERTY(int, iad, 16)
  861 + BR_PROPERTY(float, radius, 2)
  862 + BR_PROPERTY(int, resolution, 20)
  863 +
  864 + typedef Matrix<quint8, Dynamic, Dynamic> MatrixX8U;
  865 +
  866 + struct RegistrationMatrix
  867 + {
  868 + Mat src;
  869 + Point2f center;
  870 + double angle, scale;
  871 +
  872 + RegistrationMatrix(const Mat &src = Mat(), const Point2f &center = Point2f(), double angle = 0, double scale = 1)
  873 + : src(src)
  874 + , center(center)
  875 + , angle(angle)
  876 + , scale(scale)
  877 + {}
  878 +
  879 + Mat calculateRotationMatrix2D(int size) const
  880 + {
  881 + Mat rotationMatrix2D = getRotationMatrix2D(center, angle, scale);
  882 + rotationMatrix2D.at<double>(0, 2) -= (center.x - size / 2.0); // Adjust the center to the middle of the dst image
  883 + rotationMatrix2D.at<double>(1, 2) -= (center.y - size / 2.0);
  884 + return rotationMatrix2D;
  885 + }
  886 +
  887 + Point2f invert(double x, double y, int size) const
  888 + {
  889 + Mat m;
  890 + invertAffineTransform(calculateRotationMatrix2D(size), m);
  891 +
  892 + Mat src(1, 1, CV_64FC2);
  893 + src.ptr<double>()[0] = y; // According to the docs these should be specified in the opposite order ...
  894 + src.ptr<double>()[1] = x; // ... however running it seems to suggest this is the correct way
  895 +
  896 + Mat dst;
  897 + transform(src, dst, m);
  898 + return Point2f(dst.ptr<double>()[0], dst.ptr<double>()[1]);
  899 + }
  900 +
  901 + MatrixX8U warp(int size) const
  902 + {
  903 + const Mat rotationMatrix2D = calculateRotationMatrix2D(size);
  904 + Mat dst;
  905 + warpAffine(src, dst, rotationMatrix2D, Size(size, size), INTER_LINEAR, BORDER_REFLECT);
  906 + return Map<MatrixX8U>(dst.ptr<quint8>(), size, size);
  907 + }
  908 + };
  909 +
  910 + float rotationMax, scaleMin, scaleMax, xTranslationMax, yTranslationMin, yTranslationMax;
  911 + QList<DecisionBoundary> decisionBoundaries;
  912 +
  913 + static void show(const char *name, const MatrixX8U &data)
  914 + {
  915 + const Mat mat(data.rows(), data.cols(), CV_8UC1, (void*) data.data());
  916 + imshow(name, mat);
  917 + waitKey(-1);
  918 + }
  919 +
  920 + static void show(const char *name, MatrixXf data)
  921 + {
  922 + data.array() -= data.minCoeff();
  923 + data.array() *= (255 / data.maxCoeff());
  924 + show(name, MatrixX8U(data.cast<quint8>()));
  925 + }
  926 +
  927 + static void show(const char *name, VectorXf data)
  928 + {
  929 + MatrixXf resized = data;
  930 + const int size = int(sqrtf(float(data.rows())));
  931 + resized.resize(size, size);
  932 + show(name, resized);
  933 + }
  934 +
  935 + static MatrixXf getSample(const MatrixXf &registered, int j, int k, int kernelSize)
  936 + {
  937 + MatrixXf sample(registered.block(j, k, kernelSize, kernelSize));
  938 + const float norm = sample.norm();
  939 + if (norm > 0)
  940 + sample /= norm;
  941 + return sample;
  942 + }
  943 +
  944 + static MatrixXf getSample(const QList<MatrixXf> &registered, int i, int j, int k, int kernelSize)
  945 + {
  946 + return getSample(registered[i], j, k, kernelSize);
  947 + }
  948 +
  949 + static float IADError(const MatrixXf &responses, const MatrixXf &mask)
  950 + {
  951 + const int responseSize = sqrtf(responses.cols());
  952 + int numImages = 0;
  953 + float totalError = 0;
  954 + for (int i=0; i<responses.rows(); i++) {
  955 + float maxResponse = -std::numeric_limits<float>::max();
  956 + int maxX = -1;
  957 + int maxY = -1;
  958 + for (int j=0; j<responseSize; j++)
  959 + for (int k=0; k<responseSize; k++)
  960 + if (mask(i, j*responseSize + k) > 0) {
  961 + const float response = responses(i, j*responseSize+k);
  962 + if (response > maxResponse) {
  963 + maxResponse = response;
  964 + maxY = j;
  965 + maxX = k;
  966 + }
  967 + }
  968 + totalError += sqrtf(powf(maxX - responseSize/2, 2) + powf(maxY - responseSize/2, 2)) / responseSize;
  969 + numImages++;
  970 + }
  971 + return totalError / numImages;
  972 + }
  973 +
  974 + static bool isPositive(int j, int k, int responseSize)
  975 + {
  976 + return (abs(j - responseSize/2) <= 0) && (abs(k - responseSize/2) <= 0);
  977 + }
683 978  
684   - float compare(const cv::Mat &a, const cv::Mat &b) const
  979 + static MatrixXf /* output responses */ computeBoundaryRecursive(const QList<MatrixXf> &registered, int kernelSize, const MatrixXf &prior /* input responses */, QList<DecisionBoundary> &boundaries)
  980 + {
  981 + const int numImages = registered.size();
  982 + const int responseSize = registered.first().cols() - kernelSize + 1;
  983 + int positiveSamples = 0;
  984 + int negativeSamples = 0;
  985 +
  986 + // Compute weights, a weight of zero operates as a mask
  987 + MatrixXf weights(numImages, responseSize*responseSize);
  988 + float totalPositiveWeight = 0, totalNegativeWeight = 0;
  989 + for (int i=0; i<numImages; i++)
  990 + for (int j=0; j<responseSize; j++)
  991 + for (int k=0; k<responseSize; k++) {
  992 + const float probability = prior(i, j*responseSize+k);
  993 + const bool positive = isPositive(j, k, responseSize);
  994 + // Weight by probability ...
  995 + float weight = positive ? (2 - probability) // Subtracting from a number greater than 1 helps ensure that we don't overfit outliers
  996 + : probability;
  997 + // ... and by distance
  998 + const float distance = sqrtf(powf(j - responseSize/2, 2) + powf(k - responseSize/2, 2));
  999 + if (positive) weight *= 1 / (distance + 1);
  1000 + else weight *= distance;
  1001 + weights(i, j*responseSize+k) = weight;
  1002 + if (weight > 0) {
  1003 + if (positive) { totalPositiveWeight += weight; positiveSamples++; }
  1004 + else { totalNegativeWeight += weight; negativeSamples++; }
  1005 + }
  1006 + }
  1007 +
  1008 + // Normalize weights to preserve class sample ratio
  1009 + const float positiveWeightAdjustment = positiveSamples / totalPositiveWeight;
  1010 + const float negativeWeightAdjustment = negativeSamples / totalNegativeWeight;
  1011 + for (int i=0; i<numImages; i++)
  1012 + for (int j=0; j<responseSize; j++)
  1013 + for (int k=0; k<responseSize; k++)
  1014 + weights(i, j*responseSize+k) *= isPositive(j, k, responseSize) ? positiveWeightAdjustment : negativeWeightAdjustment;
  1015 +
  1016 + // Compute weighted class means
  1017 + MatrixXf positiveMean = MatrixXf::Zero(kernelSize, kernelSize);
  1018 + MatrixXf negativeMean = MatrixXf::Zero(kernelSize, kernelSize);
  1019 + for (int i=0; i<numImages; i++)
  1020 + for (int j=0; j<responseSize; j++)
  1021 + for (int k=0; k<responseSize; k++) {
  1022 + const MatrixXf sample(getSample(registered, i, j, k, kernelSize));
  1023 + const float weight = weights(i, j*responseSize+k);
  1024 + if (weight > 0) {
  1025 + if (isPositive(j, k, responseSize)) positiveMean += sample * weight;
  1026 + else negativeMean += sample * weight;
  1027 + }
  1028 + }
  1029 + positiveMean /= positiveSamples;
  1030 + negativeMean /= negativeSamples;
  1031 +
  1032 + // Compute weighted scatter matrix and decision boundary
  1033 + MatrixXf scatter = MatrixXf::Zero(kernelSize*kernelSize, kernelSize*kernelSize);
  1034 + for (int i=0; i<numImages; i++)
  1035 + for (int j=0; j<responseSize; j++)
  1036 + for (int k=0; k<responseSize; k++) {
  1037 + const float weight = weights(i, j*responseSize+k);
  1038 + if (weight > 0) {
  1039 + const MatrixXf &centeredSampleMatrix = getSample(registered, i, j, k, kernelSize) - (isPositive(j, k, responseSize) ? positiveMean : negativeMean);
  1040 + const Map<const VectorXf> centeredSample(centeredSampleMatrix.data(), kernelSize*kernelSize);
  1041 + scatter.noalias() += centeredSample * centeredSample.transpose() * weights(i, j*responseSize+k);
  1042 + }
  1043 + }
  1044 + scatter /= (positiveSamples + negativeSamples); // normalize for numerical stability
  1045 + DecisionBoundary db;
  1046 + db.function = scatter.inverse() * VectorXf(positiveMean - negativeMean); // fisher linear discriminant
  1047 +
  1048 + // Compute response values to decision boundary
  1049 + MatrixXf posterior(numImages, responseSize*responseSize);
  1050 + for (int i=0; i<numImages; i++)
  1051 + for (int j=0; j<responseSize; j++)
  1052 + for (int k=0; k<responseSize; k++)
  1053 + if (weights(i, j*responseSize + k) > 0) {
  1054 + const MatrixXf sample(getSample(registered, i, j, k, kernelSize));
  1055 + posterior(i, j*responseSize + k) = db.function.transpose() * Map<const VectorXf>(sample.data(), kernelSize*kernelSize);
  1056 + }
  1057 +
  1058 + // Compute class response means
  1059 + db.positiveMean = 0;
  1060 + db.negativeMean = 0;
  1061 + for (int i=0; i<numImages; i++)
  1062 + for (int j=0; j<responseSize; j++)
  1063 + for (int k=0; k<responseSize; k++)
  1064 + if (weights(i, j*responseSize + k) > 0) {
  1065 + const float response = posterior(i, j*responseSize + k);
  1066 + if (isPositive(j, k, responseSize)) db.positiveMean += response;
  1067 + else db.negativeMean += response;
  1068 + }
  1069 + db.positiveMean /= positiveSamples;
  1070 + db.negativeMean /= negativeSamples;
  1071 +
  1072 + // Compute class response standard deviations
  1073 + db.positiveSD = 0;
  1074 + db.negativeSD = 0;
  1075 + for (int i=0; i<numImages; i++)
  1076 + for (int j=0; j<responseSize; j++)
  1077 + for (int k=0; k<responseSize; k++)
  1078 + if (weights(i, j*responseSize + k) > 0) {
  1079 + const float response = posterior(i, j*responseSize + k);
  1080 + if (isPositive(j, k, responseSize)) db.positiveSD += powf(response-db.positiveMean, 2.f);
  1081 + else db.negativeSD += powf(response-db.negativeMean, 2.f);
  1082 + }
  1083 + db.positiveSD = sqrtf(db.positiveSD / positiveSamples);
  1084 + db.negativeSD = sqrtf(db.negativeSD / negativeSamples);
  1085 +
  1086 + // Normalize responses and propogating prior probabilities
  1087 + for (int i=0; i<numImages; i++)
  1088 + for (int j=0; j<responseSize; j++)
  1089 + for (int k=0; k<responseSize; k++) {
  1090 + float &response = posterior(i, j*responseSize + k);
  1091 + if (weights(i, j*responseSize + k) > 0) {
  1092 + const float positiveDensity = 1 / (sqrtf(2 * CV_PI) * db.positiveSD) * expf(-0.5 * powf((response - db.positiveMean) / db.positiveSD, 2.f));
  1093 + const float negativeDensity = 1 / (sqrtf(2 * CV_PI) * db.negativeSD) * expf(-0.5 * powf((response - db.negativeMean) / db.negativeSD, 2.f));
  1094 + response = prior(i, j*responseSize+k) * positiveDensity / (positiveDensity + negativeDensity);
  1095 + } else {
  1096 + response = 0;
  1097 + }
  1098 + }
  1099 + const float previousMeanError = IADError(prior, weights);
  1100 + const float meanError = IADError(posterior, weights);
  1101 + qDebug() << "Samples positive & negative:" << positiveSamples << negativeSamples;
  1102 + qDebug() << "Positive mean & stddev:" << db.positiveMean << db.positiveSD;
  1103 + qDebug() << "Negative mean & stddev:" << db.negativeMean << db.negativeSD;
  1104 + qDebug() << "Mean error before & after:" << previousMeanError << meanError;
  1105 +
  1106 + if (meanError < previousMeanError) {
  1107 + boundaries.append(db);
  1108 + return computeBoundaryRecursive(registered, kernelSize, posterior, boundaries);
  1109 + } else {
  1110 + return prior;
  1111 + }
  1112 + }
  1113 +
  1114 + void train(const TemplateList &data)
  1115 + {
  1116 + QList<RegistrationMatrix> registrationMatricies;
  1117 + {
  1118 + if (Globals->verbose)
  1119 + qDebug("Preprocessing training data...");
  1120 +
  1121 + rotationMax = -std::numeric_limits<float>::max();
  1122 + scaleMin = std::numeric_limits<float>::max();
  1123 + scaleMax = -std::numeric_limits<float>::max();
  1124 + xTranslationMax = -std::numeric_limits<float>::max();
  1125 + yTranslationMin = std::numeric_limits<float>::max();
  1126 + yTranslationMax = -std::numeric_limits<float>::max();
  1127 +
  1128 + foreach (const Template &t, data) {
  1129 + const QRectF detection = t.file.get<QRectF>(detectionKey);
  1130 + const QList<QPointF> points = t.file.points();
  1131 + const float length = sqrt(pow(points[anchors[1]].x() - points[anchors[0]].x(), 2) +
  1132 + pow(points[anchors[1]].y() - points[anchors[0]].y(), 2));
  1133 + const float rotation = atan2(points[anchors[1]].y() - points[anchors[0]].y(),
  1134 + points[anchors[1]].x() - points[anchors[0]].x()) * 180 / CV_PI;
  1135 + const float scale = length / detection.width();
  1136 + const float xCenter = (points[anchors[0]].x() + points[anchors[1]].x()) / 2;
  1137 + const float yCenter = (points[anchors[0]].y() + points[anchors[1]].y()) / 2;
  1138 + const float xTranslation = (xCenter - detection.x() - detection.width() /2) / detection.width();
  1139 + const float yTranslation = (yCenter - detection.y() - detection.height()/2) / detection.width();
  1140 +
  1141 + if (detection.contains(xCenter, yCenter) /* Sometimes the face detector gets the wrong face */) {
  1142 + rotationMax = max(rotationMax, fabsf(rotation));
  1143 + scaleMin = min(scaleMin, scale);
  1144 + scaleMax = max(scaleMax, scale);
  1145 + xTranslationMax = max(xTranslationMax, fabsf(xTranslation));
  1146 + yTranslationMin = min(yTranslationMin, yTranslation);
  1147 + yTranslationMax = max(yTranslationMax, yTranslation);
  1148 + }
  1149 +
  1150 + registrationMatricies.append(RegistrationMatrix(t, Point2f(xCenter, yCenter), rotation, iad / length));
  1151 + }
  1152 + }
  1153 +
  1154 + if (Globals->verbose)
  1155 + qDebug("Learning affine model ...");
  1156 +
  1157 + // Construct the registered training data for the landmark
  1158 + const int regionSize = 2 * iad * radius; // Train on a search size that is twice to the kernel size
  1159 + QList<MatrixXf> registered;
  1160 + foreach (const RegistrationMatrix &registrationMatrix, registrationMatricies)
  1161 + registered.append(registrationMatrix.warp(regionSize).cast<float>());
  1162 +
  1163 + // Boosted LDA
  1164 + const int numImages = registered.size();
  1165 + const int kernelSize = iad * radius;
  1166 + const int responseSize = regionSize - kernelSize + 1;
  1167 + const MatrixXf prior = MatrixXf::Ones(numImages, responseSize*responseSize);
  1168 + const MatrixXf responses = computeBoundaryRecursive(registered, kernelSize, prior, decisionBoundaries);
  1169 +
  1170 +// for (int i=0; i<numImages; i++) {
  1171 +// float maxResponse = -std::numeric_limits<float>::max();
  1172 +// int maxX = -1;
  1173 +// int maxY = -1;
  1174 +// for (int j=0; j<responseSize; j++)
  1175 +// for (int k=0; k<responseSize; k++) {
  1176 +// const float response = responses(i, j*responseSize+k);
  1177 +// if (response > maxResponse) {
  1178 +// maxResponse = response;
  1179 +// maxY = j;
  1180 +// maxX = k;
  1181 +// }
  1182 +// }
  1183 +
  1184 +// MatrixXf draw = registered[i];
  1185 +// const int r = 3;
  1186 +// maxX += kernelSize / 2;
  1187 +// maxY += kernelSize / 2;
  1188 +// for (int i=-r; i<=r; i++)
  1189 +// draw(regionSize/2 + i, regionSize/2) *= 2;
  1190 +// for (int i=-r; i<=r; i++)
  1191 +// draw(regionSize/2, regionSize/2 + i) *= 2;
  1192 +// for (int i=-r; i<=r; i++)
  1193 +// draw(maxX + i, maxY) /= 2;
  1194 +// for (int i=-r; i<=r; i++)
  1195 +// draw(maxX, maxY + i) /= 2;
  1196 +// show("draw", draw);
  1197 +// show("responses", VectorXf(responses.row(i)));
  1198 +// }
  1199 +
  1200 + if (Globals->verbose)
  1201 + qDebug("Learned %d function(s) with error %g", decisionBoundaries.size(), IADError(responses, prior));
  1202 + }
  1203 +
  1204 + void project(const Template &src, Template &dst) const
  1205 + {
  1206 + dst = src;
  1207 + const QRectF detection = src.file.get<QRectF>(detectionKey);
  1208 + RegistrationMatrix registrationMatrix(src, OpenCVUtils::toPoint(detection.center()));
  1209 +
  1210 + const int regionSize = iad * (1 + radius);
  1211 + const int kernelSize = iad * radius;
  1212 + const int responseSize = regionSize - kernelSize + 1;
  1213 + const float rotationStep = (2 * rotationMax) / (resolution - 1);
  1214 + const float scaleStep = (scaleMax - scaleMin) / (resolution - 1);
  1215 +
  1216 + float bestResponse = -std::numeric_limits<float>::max(), bestRotation = 0, bestScale = 0;
  1217 + int bestX = 0, bestY =0;
  1218 +
  1219 + for (float rotation = -rotationMax; rotation <= rotationMax; rotation += rotationStep) {
  1220 + registrationMatrix.angle = rotation;
  1221 + for (float scale = scaleMin; scale <= scaleMax; scale += scaleStep) {
  1222 + registrationMatrix.scale = iad / (scale * detection.width());
  1223 + const MatrixXf registered = registrationMatrix.warp(regionSize).cast<float>();
  1224 +
  1225 + for (int j=0; j<responseSize; j++)
  1226 + for (int k=0; k<responseSize; k++) {
  1227 + const MatrixXf sample = getSample(registered, j, k, kernelSize);
  1228 + float posterior = 1;
  1229 + foreach (const DecisionBoundary &db, decisionBoundaries) {
  1230 + const float response = db.function.transpose() * Map<const VectorXf>(sample.data(), kernelSize*kernelSize);
  1231 + const float positiveDensity = 1 / (sqrtf(2 * CV_PI) * db.positiveSD) * expf(-0.5 * powf((response - db.positiveMean) / db.positiveSD, 2.f));
  1232 + const float negativeDensity = 1 / (sqrtf(2 * CV_PI) * db.negativeSD) * expf(-0.5 * powf((response - db.negativeMean) / db.negativeSD, 2.f));
  1233 + posterior *= positiveDensity / (positiveDensity + negativeDensity);
  1234 + }
  1235 + if (posterior > bestResponse) {
  1236 + bestResponse = posterior;
  1237 + bestX = k + kernelSize/2;
  1238 + bestY = j + kernelSize/2;
  1239 + bestRotation = rotation;
  1240 + bestScale = scale;
  1241 + }
  1242 + }
  1243 + }
  1244 + }
  1245 + }
  1246 +
  1247 + void store(QDataStream &stream) const
  1248 + {
  1249 + stream << rotationMax << scaleMin << scaleMax << xTranslationMax << yTranslationMin << yTranslationMax << decisionBoundaries;
  1250 + }
  1251 +
  1252 + void load(QDataStream &stream)
685 1253 {
686   - const int size = a.rows * a.cols;
687   - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size);
688   - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size);
689   - return (aMap-bMap).squaredNorm();
  1254 + stream >> rotationMax >> scaleMin >> scaleMax >> xTranslationMax >> yTranslationMin >> yTranslationMax >> decisionBoundaries;
690 1255 }
691 1256 };
692 1257  
693   -BR_REGISTER(Distance, L2Distance)
  1258 +BR_REGISTER(Transform, BBLDAAlignmentTransform)
694 1259  
695 1260 } // namespace br
696 1261  
697   -#include "eigen3.moc"
  1262 +#include "classification/lda.moc"
... ...
openbr/plugins/liblinear.cpp renamed to openbr/plugins/classification/liblinear.cpp
... ... @@ -2,8 +2,8 @@
2 2 #include <opencv2/core/core.hpp>
3 3 #include <opencv2/ml/ml.hpp>
4 4  
5   -#include "openbr_internal.h"
6   -#include "openbr/core/opencvutils.h"
  5 +#include <openbr/plugins/openbr_internal.h>
  6 +#include <openbr/core/opencvutils.h>
7 7  
8 8 #include <linear.h>
9 9  
... ...
openbr/plugins/nn.cpp renamed to openbr/plugins/classification/mlp.cpp
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
1 17 #include <opencv2/ml/ml.hpp>
2 18  
3   -#include "openbr_internal.h"
4   -#include "openbr/core/qtutils.h"
5   -#include "openbr/core/opencvutils.h"
6   -#include "openbr/core/eigenutils.h"
7   -#include <QString>
8   -#include <QTemporaryFile>
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/opencvutils.h>
9 21  
10   -using namespace std;
11 22 using namespace cv;
12 23  
13 24 namespace br
14 25 {
15 26  
16   -static void storeMLP(const CvANN_MLP &mlp, QDataStream &stream)
17   -{
18   - // Create local file
19   - QTemporaryFile tempFile;
20   - tempFile.open();
21   - tempFile.close();
22   -
23   - // Save MLP to local file
24   - mlp.save(qPrintable(tempFile.fileName()));
25   -
26   - // Copy local file contents to stream
27   - tempFile.open();
28   - QByteArray data = tempFile.readAll();
29   - tempFile.close();
30   - stream << data;
31   -}
32   -
33   -static void loadMLP(CvANN_MLP &mlp, QDataStream &stream)
34   -{
35   - // Copy local file contents from stream
36   - QByteArray data;
37   - stream >> data;
38   -
39   - // Create local file
40   - QTemporaryFile tempFile(QDir::tempPath()+"/MLP");
41   - tempFile.open();
42   - tempFile.write(data);
43   - tempFile.close();
44   -
45   - // Load MLP from local file
46   - mlp.load(qPrintable(tempFile.fileName()));
47   -}
48   -
49 27 /*!
50 28 * \ingroup transforms
51 29 * \brief Wraps OpenCV's multi-layer perceptron framework
... ... @@ -124,12 +102,12 @@ private:
124 102  
125 103 void load(QDataStream &stream)
126 104 {
127   - loadMLP(mlp,stream);
  105 + OpenCVUtils::loadModel(mlp, stream);
128 106 }
129 107  
130 108 void store(QDataStream &stream) const
131 109 {
132   - storeMLP(mlp,stream);
  110 + OpenCVUtils::storeModel(mlp, stream);
133 111 }
134 112 };
135 113  
... ... @@ -137,4 +115,4 @@ BR_REGISTER(Transform, MLPTransform)
137 115  
138 116 } // namespace br
139 117  
140   -#include "nn.moc"
  118 +#include "classification/mlp.moc"
... ...
openbr/plugins/nt4.cpp renamed to openbr/plugins/classification/nt4.cpp
... ... @@ -20,8 +20,8 @@
20 20 #include <Bmp.h>
21 21 #include <NGrayscaleImage.h>
22 22  
23   -#include "core/resource.h"
24   -#include "core/opencvutils.h"
  23 +#include <openbr/core/resource.h>
  24 +#include <openbr/core/opencvutils.h>
25 25  
26 26 using namespace cv;
27 27 using namespace br;
... ... @@ -457,4 +457,4 @@ class NT4Compare : public Distance
457 457  
458 458 BR_REGISTER(Distance, NT4Compare)
459 459  
460   -#include "nt4.moc"
  460 +#include "classification/nt4.moc"
... ...
openbr/plugins/pp4.cpp renamed to openbr/plugins/classification/pp4.cpp
... ... @@ -6,7 +6,7 @@
6 6 #include <pittpatt_raw_image_io.h>
7 7 #include <pittpatt_license.h>
8 8 #include <openbr/openbr_plugin.h>
9   -#include "openbr_internal.h"
  9 +#include "openbr/plugins/openbr_internal.h"
10 10 #include "openbr/core/resource.h"
11 11  
12 12 #define TRY(CC) \
... ...
openbr/plugins/pp5.cpp renamed to openbr/plugins/classification/pp5.cpp
... ... @@ -11,7 +11,7 @@
11 11 #include <pittpatt_raw_image_io.h>
12 12 #include <pittpatt_sdk.h>
13 13 #include <pittpatt_license.h>
14   -#include "openbr_internal.h"
  14 +#include "openbr/plugins/openbr_internal.h"
15 15 #include "openbr/core/resource.h"
16 16  
17 17 #define TRY(CC) \
... ... @@ -593,4 +593,4 @@ class PP5GalleryTransform: public UntrainableMetaTransform
593 593  
594 594 BR_REGISTER(Transform, PP5GalleryTransform)
595 595  
596   -#include "plugins/pp5.moc"
  596 +#include "classification/pp5.moc"
... ...
openbr/plugins/svm.cpp renamed to openbr/plugins/classification/svm.cpp
... ... @@ -18,8 +18,8 @@
18 18 #include <opencv2/core/core.hpp>
19 19 #include <opencv2/ml/ml.hpp>
20 20  
21   -#include "openbr_internal.h"
22   -#include "openbr/core/opencvutils.h"
  21 +#include <openbr/plugins/openbr_internal.h>
  22 +#include <openbr/core/opencvutils.h>
23 23  
24 24 using namespace cv;
25 25  
... ... @@ -261,4 +261,4 @@ BR_REGISTER(Distance, SVMDistance)
261 261  
262 262 } // namespace br
263 263  
264   -#include "svm.moc"
  264 +#include "classification/svm.moc"
... ...
openbr/plugins/classification/turk.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Convenience class for training turk attribute regressors
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class TurkClassifierTransform : public Transform
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false)
  31 + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
  32 + Q_PROPERTY(bool isMeta READ get_isMeta WRITE set_isMeta RESET reset_isMeta STORED false)
  33 + BR_PROPERTY(QString, key, QString())
  34 + BR_PROPERTY(QStringList, values, QStringList())
  35 + BR_PROPERTY(bool, isMeta, false)
  36 +
  37 + Transform *child;
  38 +
  39 + void init()
  40 + {
  41 + QStringList classifiers;
  42 + foreach (const QString &value, values)
  43 + classifiers.append(QString("(SVM(RBF,EPS_SVR,returnDFVal=true,inputVariable=%1,outputVariable=predicted_%1)%2)").arg(key + "_" + value, isMeta ? QString("+Average+SaveMat(predicted_%1)").arg(value) : QString()));
  44 + child = Transform::make(classifiers.join("/") + (classifiers.size() > 1 ? "+Cat" : ""));
  45 + }
  46 +
  47 + void train(const QList<TemplateList> &data)
  48 + {
  49 + child->train(data);
  50 + }
  51 +
  52 + void project(const Template &src, Template &dst) const
  53 + {
  54 + child->project(src, dst);
  55 + }
  56 +
  57 + void store(QDataStream &stream) const
  58 + {
  59 + child->store(stream);
  60 + }
  61 +
  62 + void load(QDataStream &stream)
  63 + {
  64 + child->load(stream);
  65 + }
  66 +};
  67 +
  68 +BR_REGISTER(Transform, TurkClassifierTransform)
  69 +
  70 +} // namespace br
  71 +
  72 +#include "classification/turk.moc"
... ...
openbr/plugins/cluster/collectnn.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Collect nearest neighbors and append them to metadata.
  25 + * \author Charles Otto \cite caotto
  26 + */
  27 +class CollectNNTransform : public UntrainableMetaTransform
  28 +{
  29 + Q_OBJECT
  30 +
  31 + Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false)
  32 + BR_PROPERTY(int, keep, 20)
  33 +
  34 + void project(const Template &src, Template &dst) const
  35 + {
  36 + dst.file = src.file;
  37 + dst.clear();
  38 + dst.m() = cv::Mat();
  39 + Neighbors neighbors;
  40 + for (int i=0; i < src.m().cols;i++) {
  41 + // skip self compares
  42 + if (i == src.file.get<int>("FrameNumber"))
  43 + continue;
  44 + neighbors.append(Neighbor(i, src.m().at<float>(0,i)));
  45 + }
  46 + int actuallyKeep = std::min(keep, neighbors.size());
  47 + std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors);
  48 +
  49 + Neighbors selected = neighbors.mid(0, actuallyKeep);
  50 + dst.file.set("neighbors", QVariant::fromValue(selected));
  51 + }
  52 +};
  53 +
  54 +BR_REGISTER(Transform, CollectNNTransform)
  55 +
  56 +} // namespace br
  57 +
  58 +#include "cluster/collectnn.moc"
... ...
openbr/plugins/cluster/kmeans.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <opencv2/flann/flann.hpp>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/opencvutils.h>
  21 +
  22 +using namespace cv;
  23 +
  24 +namespace br
  25 +{
  26 +
  27 +/*!
  28 + * \ingroup transforms
  29 + * \brief Wraps OpenCV kmeans and flann.
  30 + * \author Josh Klontz \cite jklontz
  31 + */
  32 +class KMeansTransform : public Transform
  33 +{
  34 + Q_OBJECT
  35 + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false)
  36 + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false)
  37 + BR_PROPERTY(int, kTrain, 256)
  38 + BR_PROPERTY(int, kSearch, 1)
  39 +
  40 + Mat centers;
  41 + mutable QScopedPointer<flann::Index> index;
  42 + mutable QMutex mutex;
  43 +
  44 + void reindex()
  45 + {
  46 + index.reset(new flann::Index(centers, flann::LinearIndexParams()));
  47 + }
  48 +
  49 + void train(const TemplateList &data)
  50 + {
  51 + Mat bestLabels;
  52 + const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers);
  53 + qDebug("KMeans compactness = %f", compactness);
  54 + reindex();
  55 + }
  56 +
  57 + void project(const Template &src, Template &dst) const
  58 + {
  59 + QMutexLocker locker(&mutex);
  60 + Mat dists, indicies;
  61 + index->knnSearch(src, indicies, dists, kSearch);
  62 + dst = indicies.reshape(1, 1);
  63 + }
  64 +
  65 + void load(QDataStream &stream)
  66 + {
  67 + stream >> centers;
  68 + reindex();
  69 + }
  70 +
  71 + void store(QDataStream &stream) const
  72 + {
  73 + stream << centers;
  74 + }
  75 +};
  76 +
  77 +BR_REGISTER(Transform, KMeansTransform)
  78 +
  79 +} // namespace br
  80 +
  81 +#include "cluster/kmeans.moc"
... ...
openbr/plugins/cluster.cpp renamed to openbr/plugins/cluster/knn.cpp
... ... @@ -14,12 +14,8 @@
14 14 * limitations under the License. *
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17   -#include <opencv2/flann/flann.hpp>
18   -
19   -#include "openbr_internal.h"
20   -#include "openbr/core/common.h"
21   -#include "openbr/core/opencvutils.h"
22   -#include <fstream>
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/common.h>
23 19  
24 20 using namespace cv;
25 21  
... ... @@ -28,58 +24,6 @@ namespace br
28 24  
29 25 /*!
30 26 * \ingroup transforms
31   - * \brief Wraps OpenCV kmeans and flann.
32   - * \author Josh Klontz \cite jklontz
33   - */
34   -class KMeansTransform : public Transform
35   -{
36   - Q_OBJECT
37   - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false)
38   - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false)
39   - BR_PROPERTY(int, kTrain, 256)
40   - BR_PROPERTY(int, kSearch, 1)
41   -
42   - Mat centers;
43   - mutable QScopedPointer<flann::Index> index;
44   - mutable QMutex mutex;
45   -
46   - void reindex()
47   - {
48   - index.reset(new flann::Index(centers, flann::LinearIndexParams()));
49   - }
50   -
51   - void train(const TemplateList &data)
52   - {
53   - Mat bestLabels;
54   - const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers);
55   - qDebug("KMeans compactness = %f", compactness);
56   - reindex();
57   - }
58   -
59   - void project(const Template &src, Template &dst) const
60   - {
61   - QMutexLocker locker(&mutex);
62   - Mat dists, indicies;
63   - index->knnSearch(src, indicies, dists, kSearch);
64   - dst = indicies.reshape(1, 1);
65   - }
66   -
67   - void load(QDataStream &stream)
68   - {
69   - stream >> centers;
70   - reindex();
71   - }
72   -
73   - void store(QDataStream &stream) const
74   - {
75   - stream << centers;
76   - }
77   -};
78   -
79   -BR_REGISTER(Transform, KMeansTransform)
80   -
81   -/*!
82   - * \ingroup transforms
83 27 * \brief K nearest neighbors classifier.
84 28 * \author Josh Klontz \cite jklontz
85 29 */
... ... @@ -151,148 +95,6 @@ class KNNTransform : public Transform
151 95  
152 96 BR_REGISTER(Transform, KNNTransform)
153 97  
154   -/*!
155   - * \ingroup transforms
156   - * \brief Chooses k random points to be centroids.
157   - * \author Austin Blanton \cite imaus10
158   - * \see KMeansTransform
159   - */
160   -class RandomCentroidsTransform : public Transform
161   -{
162   - Q_OBJECT
163   - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false)
164   - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false)
165   - BR_PROPERTY(int, kTrain, 256)
166   - BR_PROPERTY(int, kSearch, 1)
167   -
168   - Mat centers;
169   - mutable QScopedPointer<flann::Index> index;
170   - mutable QMutex mutex;
171   -
172   - void reindex()
173   - {
174   - index.reset(new flann::Index(centers, flann::LinearIndexParams()));
175   - }
176   -
177   - void train(const TemplateList &data)
178   - {
179   - Mat flat = OpenCVUtils::toMatByRow(data.data());
180   - QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true);
181   - foreach (const int &idx, sample)
182   - centers.push_back(flat.row(idx));
183   - reindex();
184   - }
185   -
186   - void project(const Template &src, Template &dst) const
187   - {
188   - QMutexLocker locker(&mutex);
189   - Mat dists, indicies;
190   - index->knnSearch(src, indicies, dists, kSearch);
191   - dst = indicies.reshape(1, 1);
192   - }
193   -
194   - void load(QDataStream &stream)
195   - {
196   - stream >> centers;
197   - reindex();
198   - }
199   -
200   - void store(QDataStream &stream) const
201   - {
202   - stream << centers;
203   - }
204   -};
205   -
206   -BR_REGISTER(Transform, RandomCentroidsTransform)
207   -
208   -class RegInitializer : public Initializer
209   -{
210   - Q_OBJECT
211   -
212   - void initialize() const
213   - {
214   - qRegisterMetaType<br::Neighbors>();
215   - }
216   -};
217   -BR_REGISTER(Initializer, RegInitializer)
218   -
219   -class CollectNNTransform : public UntrainableMetaTransform
220   -{
221   - Q_OBJECT
222   -
223   - Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false)
224   - BR_PROPERTY(int, keep, 20)
225   -
226   - void project(const Template &src, Template &dst) const
227   - {
228   - dst.file = src.file;
229   - dst.clear();
230   - dst.m() = cv::Mat();
231   - Neighbors neighbors;
232   - for (int i=0; i < src.m().cols;i++) {
233   - // skip self compares
234   - if (i == src.file.get<int>("FrameNumber"))
235   - continue;
236   - neighbors.append(Neighbor(i, src.m().at<float>(0,i)));
237   - }
238   - int actuallyKeep = std::min(keep, neighbors.size());
239   - std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors);
240   -
241   - Neighbors selected = neighbors.mid(0, actuallyKeep);
242   - dst.file.set("neighbors", QVariant::fromValue(selected));
243   - }
244   -};
245   -BR_REGISTER(Transform, CollectNNTransform)
246   -
247   -class LogNNTransform : public TimeVaryingTransform
248   -{
249   - Q_OBJECT
250   -
251   - Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false)
252   - BR_PROPERTY(QString, fileName, "")
253   -
254   - std::fstream fout;
255   -
256   - void projectUpdate(const Template &src, Template &dst)
257   - {
258   - dst = src;
259   -
260   - if (!dst.file.contains("neighbors")) {
261   - fout << std::endl;
262   - return;
263   - }
264   -
265   - Neighbors neighbors = dst.file.get<Neighbors>("neighbors");
266   - if (neighbors.isEmpty() ) {
267   - fout << std::endl;
268   - return;
269   - }
270   -
271   - QString aLine;
272   - aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second));
273   - for (int i=1; i < neighbors.size();i++)
274   - aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second));
275   -
276   - fout << qPrintable(aLine) << std::endl;
277   - }
278   -
279   - void init()
280   - {
281   - if (!fileName.isEmpty())
282   - fout.open(qPrintable(fileName), std::ios_base::out);
283   - }
284   -
285   - void finalize(TemplateList &output)
286   - {
287   - (void) output;
288   - fout.close();
289   - }
290   -
291   -public:
292   - LogNNTransform() : TimeVaryingTransform(false, false) {}
293   -};
294   -BR_REGISTER(Transform, LogNNTransform)
295   -
296 98 } // namespace br
297 99  
298   -#include "cluster.moc"
  100 +#include "cluster/knn.moc"
... ...
openbr/plugins/cluster/lognn.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <fstream>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup transforms
  26 + * \brief Log nearest neighbors to specified file.
  27 + * \author Charles Otto \cite caotto
  28 + */
  29 +class LogNNTransform : public TimeVaryingTransform
  30 +{
  31 + Q_OBJECT
  32 +
  33 + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false)
  34 + BR_PROPERTY(QString, fileName, "")
  35 +
  36 + std::fstream fout;
  37 +
  38 + void projectUpdate(const Template &src, Template &dst)
  39 + {
  40 + dst = src;
  41 +
  42 + if (!dst.file.contains("neighbors")) {
  43 + fout << std::endl;
  44 + return;
  45 + }
  46 +
  47 + Neighbors neighbors = dst.file.get<Neighbors>("neighbors");
  48 + if (neighbors.isEmpty() ) {
  49 + fout << std::endl;
  50 + return;
  51 + }
  52 +
  53 + QString aLine;
  54 + aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second));
  55 + for (int i=1; i < neighbors.size();i++)
  56 + aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second));
  57 +
  58 + fout << qPrintable(aLine) << std::endl;
  59 + }
  60 +
  61 + void init()
  62 + {
  63 + if (!fileName.isEmpty())
  64 + fout.open(qPrintable(fileName), std::ios_base::out);
  65 + }
  66 +
  67 + void finalize(TemplateList &output)
  68 + {
  69 + (void) output;
  70 + fout.close();
  71 + }
  72 +
  73 +public:
  74 + LogNNTransform() : TimeVaryingTransform(false, false) {}
  75 +};
  76 +
  77 +BR_REGISTER(Transform, LogNNTransform)
  78 +
  79 +} // namespace br
  80 +
  81 +#include "cluster/lognn.moc"
... ...
openbr/plugins/cluster/randomcentroids.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <opencv2/flann/flann.hpp>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/common.h>
  21 +#include <openbr/core/opencvutils.h>
  22 +
  23 +using namespace cv;
  24 +
  25 +namespace br
  26 +{
  27 +
  28 +/*!
  29 + * \ingroup transforms
  30 + * \brief Chooses k random points to be centroids.
  31 + * \author Austin Blanton \cite imaus10
  32 + * \see KMeansTransform
  33 + */
  34 +class RandomCentroidsTransform : public Transform
  35 +{
  36 + Q_OBJECT
  37 + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false)
  38 + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false)
  39 + BR_PROPERTY(int, kTrain, 256)
  40 + BR_PROPERTY(int, kSearch, 1)
  41 +
  42 + Mat centers;
  43 + mutable QScopedPointer<flann::Index> index;
  44 + mutable QMutex mutex;
  45 +
  46 + void reindex()
  47 + {
  48 + index.reset(new flann::Index(centers, flann::LinearIndexParams()));
  49 + }
  50 +
  51 + void train(const TemplateList &data)
  52 + {
  53 + Mat flat = OpenCVUtils::toMatByRow(data.data());
  54 + QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true);
  55 + foreach (const int &idx, sample)
  56 + centers.push_back(flat.row(idx));
  57 + reindex();
  58 + }
  59 +
  60 + void project(const Template &src, Template &dst) const
  61 + {
  62 + QMutexLocker locker(&mutex);
  63 + Mat dists, indicies;
  64 + index->knnSearch(src, indicies, dists, kSearch);
  65 + dst = indicies.reshape(1, 1);
  66 + }
  67 +
  68 + void load(QDataStream &stream)
  69 + {
  70 + stream >> centers;
  71 + reindex();
  72 + }
  73 +
  74 + void store(QDataStream &stream) const
  75 + {
  76 + stream << centers;
  77 + }
  78 +};
  79 +
  80 +BR_REGISTER(Transform, RandomCentroidsTransform)
  81 +
  82 +} //namespace br
  83 +
  84 +#include "cluster/randomcentroids.moc"
... ...
openbr/plugins/dlib.cmake renamed to openbr/plugins/cmake/dlib.cmake
... ... @@ -5,7 +5,7 @@ if(${BR_WITH_DLIB})
5 5  
6 6 add_definitions(-DDLIB_NO_GUI_SUPPORT)
7 7  
8   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/dlib.cpp)
  8 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/classification/dlib.cpp)
9 9 set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${DLib_DIR}/dlib/all/source.cpp)
10 10  
11 11 #install(DIRECTORY ${DLib_DIR}/models/ DESTINATION share/openbr/models/dlib)
... ...
openbr/plugins/cmake/eigen3.cmake 0 → 100644
  1 +set(BR_WITH_EIGEN3 ON CACHE BOOL "Build Eigen3 plugins")
  2 +
  3 +if(${BR_WITH_EIGEN3})
  4 + find_package(Eigen3 REQUIRED)
  5 + install(FILES ${EIGEN3_LICENSE} RENAME Eigen3 DESTINATION share/openbr/licenses)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/lda.cpp)
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/distance/L1.cpp)
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/distance/L2.cpp)
  10 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp)
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/integralsampler.cpp)
  12 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/recursiveintegralsampler.cpp)
  13 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/consolidatedetections.cpp)
  14 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/delaunay.cpp)
  15 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/procrustes.cpp)
  16 +endif()
... ...
openbr/plugins/ipc2013.cmake renamed to openbr/plugins/cmake/ipc2013.cmake
... ... @@ -2,7 +2,8 @@ set(BR_WITH_IPC2013 OFF CACHE BOOL &quot;Build with Intel Perceptual Computing SDK 20
2 2  
3 3 if(${BR_WITH_IPC2013})
4 4 find_package(IPC2013 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/ipc2013.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${IPC2013_LIBS})
7 6 install(DIRECTORY ${IPC2013_DIR}/bin/x64/ DESTINATION bin)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/ipc2013.cpp)
8 9 endif()
... ...
openbr/plugins/jni.cmake renamed to openbr/plugins/cmake/jni.cmake
... ... @@ -3,10 +3,10 @@ set(BR_WITH_JAVA OFF CACHE BOOL &quot;Use Java Code&quot;)
3 3 if (${BR_WITH_JAVA})
4 4 find_package(JNI REQUIRED)
5 5 find_package(JAVA REQUIRED)
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/jni.cpp)
7 6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES})
8 7  
9 8 include_directories(${JAVA_INCLUDE_PATH})
10 9 include_directories(${JAVA_INCLUDE_PATH2})
11   -
  10 +else()
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/jni.cpp)
12 12 endif()
... ...
openbr/plugins/cmake/libav.cmake 0 → 100644
  1 +set(BR_WITH_LIBAV OFF CACHE BOOL "Build with LibAV")
  2 +
  3 +if(${BR_WITH_LIBAV})
  4 + find_package(LibAV REQUIRED)
  5 + include_directories(${LIBAV_INCLUDE_DIR})
  6 + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${LIBAV_LIBRARIES})
  7 +
  8 + foreach(LIBAV_LIB ${LIBAV_LIBRARIES})
  9 + install(FILES ${LIBAV_LIB} DESTINATION lib)
  10 + endforeach()
  11 +else()
  12 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/keyframes.cpp)
  13 +endif()
... ...
openbr/plugins/liblinear.cmake renamed to openbr/plugins/cmake/liblinear.cmake
... ... @@ -3,5 +3,6 @@ set(BR_WITH_LIBLINEAR OFF CACHE BOOL &quot;Build with LibLinear&quot;)
3 3 if(${BR_WITH_LIBLINEAR})
4 4 find_package(LibLinear REQUIRED)
5 5 set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${LibLinear_SRC})
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/liblinear.cpp)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/liblinear.cpp)
7 8 endif()
... ...
openbr/plugins/likely.cmake renamed to openbr/plugins/cmake/likely.cmake
... ... @@ -2,6 +2,9 @@ set(BR_WITH_LIKELY OFF CACHE BOOL &quot;Build with Likely&quot;)
2 2  
3 3 if(${BR_WITH_LIKELY})
4 4 find_package(Likely REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/likely.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS})
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/likely.cpp)
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/lmat.cpp)
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lmat.cpp)
7 10 endif()
... ...
openbr/plugins/mongoose.cmake renamed to openbr/plugins/cmake/mongoose.cmake
1 1 set(BR_WITH_MONGOOSE OFF CACHE BOOL "Build with Mongoose")
2 2 if(${BR_WITH_MONGOOSE})
3 3 find_package(Mongoose)
4   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/mongoose.cpp ${MONGOOSE_SRC})
  4 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${MONGOOSE_SRC})
5 5 install(FILES ${MONGOOSE_LICENSE} RENAME mongoose DESTINATION share/openbr/licenses)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/mongoose.cpp)
6 8 endif()
... ...
openbr/plugins/qtnetwork.cmake renamed to openbr/plugins/cmake/network.cmake
... ... @@ -3,6 +3,10 @@ if(${BR_WITH_QTNETWORK})
3 3 find_package(Qt5Network)
4 4 find_package(HttpParser)
5 5 set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Network)
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/qtnetwork.cpp ${HTTPPARSER_SRC})
  6 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${HTTPPARSER_SRC})
7 7 install(FILES ${HTTPPARSER_LICENSE} RENAME http-parser DESTINATION share/openbr/licenses)
  8 +else()
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/url.cpp)
  10 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/post.cpp)
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/post.cpp)
8 12 endif()
... ...
openbr/plugins/nt4.cmake renamed to openbr/plugins/cmake/nt4.cmake
... ... @@ -2,7 +2,8 @@ set(BR_WITH_NT4 OFF CACHE BOOL &quot;Build with Neurotec Biometric 4&quot;)
2 2  
3 3 if(${BR_WITH_NT4})
4 4 find_package(NT4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/nt4.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${NT4_LIBS})
7 6 install(DIRECTORY ${NT4_DIR_LIB}/ DESTINATION lib)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/nt4.cpp)
8 9 endif()
... ...
openbr/plugins/pp4.cmake renamed to openbr/plugins/cmake/pp4.cmake
... ... @@ -2,8 +2,9 @@ set(BR_WITH_PP4 OFF CACHE BOOL &quot;Build with PittPatt 4&quot;)
2 2  
3 3 if(${BR_WITH_PP4})
4 4 find_package(PP4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS})
7 6 install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib)
8 7 install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4)
  8 +else()
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp4.cpp)
9 10 endif()
... ...
openbr/plugins/pp5.cmake renamed to openbr/plugins/cmake/pp5.cmake
... ... @@ -2,7 +2,6 @@ set(BR_WITH_PP5 OFF CACHE BOOL &quot;Build with PittPatt 5&quot;)
2 2  
3 3 if(${BR_WITH_PP5})
4 4 find_package(PP5 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp5.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP5_LIBS})
7 6  
8 7 if(WIN32)
... ... @@ -12,4 +11,6 @@ if(${BR_WITH_PP5})
12 11 endif()
13 12  
14 13 install(DIRECTORY ${PP5_DIR}/models/ DESTINATION share/openbr/models/pp5)
  14 +else()
  15 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp5.cpp)
15 16 endif()
... ...
openbr/plugins/cmake/show.cmake 0 → 100644
  1 +if(${BR_EMBEDDED})
  2 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gui/show.cpp)
  3 +endif()
... ...
openbr/plugins/stasm4.cmake renamed to openbr/plugins/cmake/stasm4.cmake
... ... @@ -2,14 +2,9 @@ set(BR_WITH_STASM4 ON CACHE BOOL &quot;Build with Stasm&quot;)
2 2  
3 3 if(${BR_WITH_STASM4})
4 4 find_package(Stasm4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/stasm4.cpp)
6   - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Stasm4_LIBS})
7   -
8   - if(WIN32)
9   - install(DIRECTORY ${Stasm_DIR}/build/ DESTINATION bin)
10   - else()
11   - install(DIRECTORY ${Stasm_DIR}/build/ DESTINATION lib)
12   - endif()
13   -
  5 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${Stasm_SRC})
14 6 install(DIRECTORY ${Stasm_DIR}/data/ DESTINATION share/openbr/models/stasm)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/stasm4.cpp)
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp)
15 10 endif()
... ...
openbr/plugins/algorithms.cpp renamed to openbr/plugins/core/algorithms.cpp
... ... @@ -14,7 +14,7 @@
14 14 * limitations under the License. *
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17   -#include "openbr_internal.h"
  17 +#include <openbr/plugins/openbr_internal.h>
18 18  
19 19 namespace br
20 20 {
... ... @@ -43,7 +43,7 @@ class AlgorithmsInitializer : public Initializer
43 43 Globals->abbreviations.insert("OpenBR", "FaceRecognition");
44 44 Globals->abbreviations.insert("GenderEstimation", "GenderClassification");
45 45 Globals->abbreviations.insert("AgeEstimation", "AgeRegression");
46   - Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+Bin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+Bin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1");
  46 + Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+HistBin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+HistBin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1");
47 47 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)");
48 48 Globals->abbreviations.insert("4SF", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Cat+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)");
49 49  
... ... @@ -55,9 +55,9 @@ class AlgorithmsInitializer : public Initializer
55 55 Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard");
56 56 Globals->abbreviations.insert("ShowMotionSegmentation", "DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard");
57 57  
58   - Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
59   - Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");
60   - Globals->abbreviations.insert("HOGHOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+(OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
  58 + Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
  59 + Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");
  60 + Globals->abbreviations.insert("HOGHOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+(OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
61 61  
62 62 // Generic Image Processing
63 63 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
... ... @@ -66,7 +66,7 @@ class AlgorithmsInitializer : public Initializer
66 66 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)");
67 67 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2");
68 68 Globals->abbreviations.insert("ImageSimilarity", "Open+EnsureChannels(3)+Resize(256,256)+SplitChannels+RectRegions(64,64,64,64)+Hist(256,0,8)+Cat:NegativeLogPlusOne(L2)");
69   - 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)");
  69 + Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+HistBin(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)");
70 70 Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)");
71 71  
72 72 // Hash
... ... @@ -89,7 +89,7 @@ class AlgorithmsInitializer : public Initializer
89 89 // Transforms
90 90 Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)");
91 91 Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))");
92   - Globals->abbreviations.insert("DenseHOG", "Gradient+RectRegions(8,8,6,6)+Bin(0,360,8)+Hist(8)");
  92 + Globals->abbreviations.insert("DenseHOG", "Gradient+RectRegions(8,8,6,6)+HistBin(0,360,8)+Hist(8)");
93 93 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)");
94 94 Globals->abbreviations.insert("DenseSIFT2", "(Grid(5,5)+SIFTDescriptor(12)+ByRow)");
95 95 Globals->abbreviations.insert("FaceRecognitionRegistration", "ASEFEyes+Affine(88,88,0.25,0.35)");
... ... @@ -108,4 +108,4 @@ BR_REGISTER(Initializer, AlgorithmsInitializer)
108 108  
109 109 } // namespace br
110 110  
111   -#include "algorithms.moc"
  111 +#include "core/algorithms.moc"
... ...
openbr/plugins/core/align.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2015 Noblis *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <opencv2/opencv.hpp>
  18 +#include "openbr/plugins/openbr_internal.h"
  19 +#include "openbr/core/qtutils.h"
  20 +#include "openbr/core/opencvutils.h"
  21 +#include "openbr/core/eigenutils.h"
  22 +#include "openbr/core/common.h"
  23 +#include <QString>
  24 +#include <Eigen/SVD>
  25 +#include <Eigen/Dense>
  26 +
  27 +using namespace std;
  28 +using namespace cv;
  29 +using namespace Eigen;
  30 +
  31 +namespace br
  32 +{
  33 +
  34 +/*!
  35 + * \ingroup transforms
  36 + * \brief Improved procrustes alignment of points, to include a post processing scaling of points
  37 + * to faciliate subsequent texture mapping.
  38 + * \author Brendan Klare \cite bklare
  39 + * \param width Width of output coordinate space (before padding)
  40 + * \param padding Amount of padding around the coordinate space
  41 + * \param useFirst whether or not to use the first instance as the reference object
  42 + */
  43 +class ProcrustesAlignTransform : public Transform
  44 +{
  45 + Q_OBJECT
  46 +
  47 + Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false)
  48 + Q_PROPERTY(float padding READ get_padding WRITE set_padding RESET reset_padding STORED false)
  49 + Q_PROPERTY(bool useFirst READ get_useFirst WRITE set_useFirst RESET reset_useFirst STORED false)
  50 + BR_PROPERTY(float, width, 80)
  51 + BR_PROPERTY(float, padding, 8)
  52 + BR_PROPERTY(bool, useFirst, false)
  53 +
  54 +
  55 + Eigen::MatrixXf referenceShape;
  56 + float minX;
  57 + float minY;
  58 + float maxX;
  59 + float maxY;
  60 + float aspectRatio;
  61 +
  62 + void init() {
  63 + aspectRatio = 0;
  64 + }
  65 +
  66 + static MatrixXf getRotation(MatrixXf ref, MatrixXf sample) {
  67 + MatrixXf R = sample.transpose() * ref;
  68 + JacobiSVD<MatrixXf> svd(R, ComputeFullU | ComputeFullV);
  69 + R = svd.matrixU() * svd.matrixV().transpose();
  70 + return R;
  71 + }
  72 +
  73 + //Converts x y points in a single vector to two column matrix
  74 + static MatrixXf vectorToMatrix(MatrixXf vector) {
  75 + int n = vector.rows();
  76 + MatrixXf matrix(n / 2, 2);
  77 + for (int i = 0; i < n / 2; i++) {
  78 + for (int j = 0; j < 2; j++) {
  79 + matrix(i, j) = vector(i * 2 + j);
  80 + }
  81 + }
  82 + return matrix;
  83 + }
  84 +
  85 + static MatrixXf matrixToVector(MatrixXf matrix) {
  86 + int n2 = matrix.rows();
  87 + MatrixXf vector(n2 * 2, 1);
  88 + for (int i = 0; i < n2; i++) {
  89 + for (int j = 0; j < 2; j++) {
  90 + vector(i * 2 + j) = matrix(i, j);
  91 + }
  92 + }
  93 + return vector;
  94 + }
  95 +
  96 + void train(const TemplateList &data)
  97 + {
  98 + MatrixXf points(data[0].file.points().size() * 2, data.size());
  99 +
  100 + // Normalize all sets of points
  101 + int skip = 0;
  102 + for (int j = 0; j < data.size(); j++) {
  103 + QList<QPointF> imagePoints = data[j].file.points();
  104 + if (imagePoints.size() == 0) {
  105 + skip++;
  106 + continue;
  107 + }
  108 +
  109 + float meanX = 0,
  110 + meanY = 0;
  111 + for (int i = 0; i < imagePoints.size(); i++) {
  112 + points(i * 2, j - skip) = imagePoints[i].x();
  113 + points(i * 2 + 1, j - skip) = imagePoints[i].y();
  114 +
  115 + meanX += imagePoints[i].x();
  116 + meanY += imagePoints[i].y();
  117 + }
  118 +
  119 + meanX /= imagePoints.size();
  120 + meanY /= imagePoints.size();
  121 +
  122 + for (int i = 0; i < imagePoints.size(); i++) {
  123 + points(i * 2, j - skip) -= meanX;
  124 + points(i * 2 + 1, j - skip) -= meanY;
  125 + }
  126 + }
  127 +
  128 + points = MatrixXf(points.leftCols(data.size() - skip));
  129 +
  130 + //normalize scale
  131 + for (int i = 0; i < points.cols(); i++)
  132 + points.col(i) = points.col(i) / points.col(i).norm();
  133 +
  134 + //Normalize rotation
  135 + if (!useFirst) {
  136 + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols());
  137 + } else {
  138 + referenceShape = vectorToMatrix(points.col(0));
  139 + }
  140 +
  141 + for (int i = 0; i < points.cols(); i++) {
  142 + MatrixXf p = vectorToMatrix(points.col(i));
  143 + MatrixXf R = getRotation(referenceShape, p);
  144 + points.col(i) = matrixToVector(p * R);
  145 + }
  146 +
  147 + //Choose crop boundaries and adjustments that captures most data
  148 + MatrixXf minXs(points.cols(),1);
  149 + MatrixXf minYs(points.cols(),1);
  150 + MatrixXf maxXs(points.cols(),1);
  151 + MatrixXf maxYs(points.cols(),1);
  152 + for (int j = 0; j < points.cols(); j++) {
  153 + minX = FLT_MAX,
  154 + minY = FLT_MAX,
  155 + maxX = -FLT_MAX,
  156 + maxY = -FLT_MAX;
  157 + for (int i = 0; i < points.rows(); i++) {
  158 + if (i % 2 == 0) {
  159 + if (points(i,j) > maxX)
  160 + maxX = points(i, j);
  161 + if (points(i,j) < minX)
  162 + minX = points(i, j);
  163 + } else {
  164 + if (points(i,j) > maxY)
  165 + maxY = points(i, j);
  166 + if (points(i,j) < minY)
  167 + minY = points(i, j);
  168 + }
  169 + }
  170 +
  171 + minXs(j) = minX;
  172 + maxXs(j) = maxX;
  173 + minYs(j) = minY;
  174 + maxYs(j) = maxY;
  175 + }
  176 +
  177 + minX = minXs.mean() - 0 * EigenUtils::stddev(minXs);
  178 + minY = minYs.mean() - 0 * EigenUtils::stddev(minYs);
  179 + maxX = maxXs.mean() + 0 * EigenUtils::stddev(maxXs);
  180 + maxY = maxYs.mean() + 0 * EigenUtils::stddev(maxYs);
  181 + aspectRatio = (maxX - minX) / (maxY - minY);
  182 + }
  183 +
  184 + void project(const Template &src, Template &dst) const
  185 + {
  186 + QList<QPointF> imagePoints = src.file.points();
  187 + if (imagePoints.size() == 0) {
  188 + dst.file.fte = true;
  189 + qDebug() << "No points for file " << src.file.name;
  190 + return;
  191 + }
  192 +
  193 + MatrixXf p(imagePoints.size() * 2, 1);
  194 + for (int i = 0; i < imagePoints.size(); i++) {
  195 + p(i * 2) = imagePoints[i].x();
  196 + p(i * 2 + 1) = imagePoints[i].y();
  197 + }
  198 + p = vectorToMatrix(p);
  199 +
  200 + //Normalize translation
  201 + p.col(0) = p.col(0) - MatrixXf::Ones(p.rows(),1) * (p.col(0).sum() / p.rows());
  202 + p.col(1) = p.col(1) - MatrixXf::Ones(p.rows(),1) * (p.col(1).sum() / p.rows());
  203 +
  204 + //Normalize scale
  205 + p /= matrixToVector(p).norm();
  206 +
  207 + //Normalize rotation
  208 + MatrixXf R = getRotation(referenceShape, p);
  209 + p = p * R;
  210 +
  211 + //Translate and scale into output space and store in output list
  212 + QList<QPointF> procrustesPoints;
  213 + for (int i = 0; i < p.rows(); i++)
  214 + procrustesPoints.append( QPointF(
  215 + (p(i, 0) - minX) / (maxX - minX) * (width - 1) + padding,
  216 + (p(i, 1) - minY) / (maxY - minY) * (qRound( width / aspectRatio) - 1) + padding));
  217 +
  218 + dst = src;
  219 + dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints);
  220 + dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding)));
  221 + dst.file.set("ProcrustesPadding", padding);
  222 + }
  223 +
  224 + void store(QDataStream &stream) const
  225 + {
  226 + stream << referenceShape;
  227 + stream << minX;
  228 + stream << minY;
  229 + stream << maxX;
  230 + stream << maxY;
  231 + stream << aspectRatio;
  232 + }
  233 +
  234 + void load(QDataStream &stream)
  235 + {
  236 + stream >> referenceShape;
  237 + stream >> minX;
  238 + stream >> minY;
  239 + stream >> maxX;
  240 + stream >> maxY;
  241 + stream >> aspectRatio;
  242 + }
  243 +};
  244 +BR_REGISTER(Transform, ProcrustesAlignTransform)
  245 +
  246 +/*!
  247 + * \ingroup transforms
  248 + * \brief Maps texture from one set of points to another. Assumes that points are rigidly transformed
  249 + * \author Brendan Klare \cite bklare
  250 + * \author Scott Klum \cite sklum
  251 + */
  252 +class TextureMapTransform : public UntrainableTransform
  253 +{
  254 + Q_OBJECT
  255 +
  256 +public:
  257 + static QRectF getBounds(const QList<QPointF> &points, int dstPadding)
  258 + {
  259 + float srcMinX = FLT_MAX;
  260 + float srcMinY = FLT_MAX;
  261 + float srcMaxX = -FLT_MAX;
  262 + float srcMaxY = -FLT_MAX;
  263 + foreach (const QPointF &point, points) {
  264 + if (point.x() < srcMinX) srcMinX = point.x();
  265 + if (point.y() < srcMinY) srcMinY = point.y();
  266 + if (point.x() > srcMaxX) srcMaxX = point.x();
  267 + if (point.y() > srcMaxY) srcMaxY = point.y();
  268 + }
  269 +
  270 + const float padding = (srcMaxX - srcMinX) / 80 * dstPadding;
  271 + return QRectF(qRound(srcMinX - padding), qRound(srcMinY - padding), qRound(srcMaxX - srcMinX + 2 * padding), qRound(srcMaxY - srcMinY + 2 * padding));
  272 + }
  273 +
  274 + static int getVertexIndex(const QPointF &trianglePts, const QList<QPointF> &pts)
  275 + {
  276 + for (int i = 0; i < pts.size(); i++)
  277 + // Check points using single precision accuracy to avoid potential rounding error
  278 + if ((float(trianglePts.x()) == float(pts[i].x())) && (float(trianglePts.y()) == float(pts[i].y())))
  279 + return i;
  280 + qFatal("Couldn't identify index of requested point!");
  281 + return -1;
  282 + }
  283 +
  284 + static QList<QPointF> addBounds(QList<QPointF> points, const QRectF &bound)
  285 + {
  286 + points.append(bound.topLeft());
  287 + points.append(QPointF(bound.right() - 1, bound.top()));
  288 + points.append(QPointF(bound.left(), bound.bottom() - 1));
  289 + points.append(QPointF(bound.right() - 1, bound.bottom() - 1));
  290 + return points;
  291 + }
  292 +
  293 + static QList<QPointF> removeBounds(const QList<QPointF> &points)
  294 + {
  295 + return points.mid(0, points.size() - 4);
  296 + }
  297 +
  298 + //Expand out bounds placed at end of point list by addBounds
  299 + static QList<QPointF> expandBounds(QList<QPointF> points, int pad)
  300 + {
  301 + const int n = points.size();
  302 + points[n-4] = QPointF(points[n-4].x() - pad, points[n-4].y() - pad);
  303 + points[n-3] = QPointF(points[n-3].x() + pad, points[n-3].y() - pad);
  304 + points[n-2] = QPointF(points[n-2].x() - pad, points[n-2].y() + pad);
  305 + points[n-1] = QPointF(points[n-1].x() + pad, points[n-1].y() + pad);
  306 + return points;
  307 + }
  308 +
  309 + //Contract in bounds placed at end of point list by addBounds
  310 + static QList<QPointF> contractBounds(QList<QPointF> points, int pad)
  311 + {
  312 + const int n = points.size();
  313 + points[n-4] = QPointF(points[n-4].x() + pad, points[n-4].y() + pad);
  314 + points[n-3] = QPointF(points[n-3].x() - pad, points[n-3].y() + pad);
  315 + points[n-2] = QPointF(points[n-2].x() + pad, points[n-2].y() - pad);
  316 + points[n-1] = QPointF(points[n-1].x() - pad, points[n-1].y() - pad);
  317 + return points;
  318 + }
  319 +
  320 + static QList<QList<int> > getTriangulation(const QList<QPointF> &points, const QRectF &bound)
  321 + {
  322 + Subdiv2D subdiv(OpenCVUtils::toRect(bound));
  323 + foreach (const QPointF &point, points) {
  324 + if (!bound.contains(point))
  325 + return QList<QList<int> >();
  326 + subdiv.insert(OpenCVUtils::toPoint(point));
  327 + }
  328 +
  329 +
  330 + vector<Vec6f> triangleList;
  331 + subdiv.getTriangleList(triangleList);
  332 +
  333 + QList<QList<int> > triangleIndices;
  334 + foreach (const Vec6f &triangle, triangleList) {
  335 + bool valid = true;
  336 + const QPointF vertices[3] = { QPointF(triangle[0], triangle[1]),
  337 + QPointF(triangle[2], triangle[3]),
  338 + QPointF(triangle[4], triangle[5]) };
  339 + for (int j = 0; j < 3; j++)
  340 + if (vertices[j].x() > bound.right() || vertices[j].y() > bound.bottom() || vertices[j].x() < bound.left() || vertices[j].y() < bound.top()) {
  341 + valid = false;
  342 + break;
  343 + }
  344 +
  345 + if (valid) {
  346 + QList<int> tri;
  347 + for (int j = 0; j < 3; j++)
  348 + tri.append(getVertexIndex(vertices[j], points));
  349 + triangleIndices.append(tri);
  350 + }
  351 + }
  352 +
  353 + return triangleIndices;
  354 + }
  355 +
  356 +private:
  357 + void project(const Template &src, Template &dst) const
  358 + {
  359 + QList<QPointF> dstPoints = dst.file.getList<QPointF>("ProcrustesPoints");
  360 + QList<QPointF> srcPoints = dst.file.points();
  361 + if (dstPoints.empty() || srcPoints.empty()) {
  362 + dst = src;
  363 + if (Globals->verbose) {
  364 + qWarning("Delauney triangulation failed because points or rects are empty.");
  365 + dst.file.fte = true;
  366 + }
  367 + return;
  368 + }
  369 +
  370 + QRectF dstBound = dst.file.get<QRectF>("ProcrustesBound");
  371 + dstPoints = addBounds(dstPoints, dstBound);
  372 +
  373 + /*Add a wider bound for triangulation to prevent border triangles from being missing*/
  374 + QRectF srcBound = getBounds(srcPoints, dst.file.get<int>("ProcrustesPadding") + 20);
  375 + srcPoints = addBounds(srcPoints, srcBound);
  376 + QList<QList<int> > triIndices = getTriangulation(srcPoints, srcBound);
  377 +
  378 + /*Remove wider bound for texture mapping*/
  379 + srcPoints = removeBounds(srcPoints);
  380 + srcBound = getBounds(srcPoints, dst.file.get<int>("ProcrustesPadding"));
  381 + srcPoints = addBounds(srcPoints, srcBound);
  382 +
  383 + int dstWidth = dstBound.width() + dstBound.x();
  384 + int dstHeight = dstBound.height() + dstBound.y();
  385 + dst.m() = Mat::zeros(dstHeight, dstWidth, src.m().type());
  386 + for (int i = 0; i < triIndices.size(); i++) {
  387 + Point2f srcPoint1[3];
  388 + Point2f dstPoint1[3];
  389 + for (int j = 0; j < 3; j++) {
  390 + srcPoint1[j] = OpenCVUtils::toPoint(srcPoints[triIndices[i][j]]);
  391 + dstPoint1[j] = OpenCVUtils::toPoint(dstPoints[triIndices[i][j]]);
  392 + }
  393 +
  394 + Mat buffer(dstHeight, dstWidth, src.m().type());
  395 + warpAffine(src.m(), buffer, getAffineTransform(srcPoint1, dstPoint1), Size(dstBound.width(), dstBound.height()));
  396 +
  397 + Mat mask = Mat::zeros(dstHeight, dstWidth, CV_8UC1);
  398 + Point maskPoints[1][3];
  399 + maskPoints[0][0] = dstPoint1[0];
  400 + maskPoints[0][1] = dstPoint1[1];
  401 + maskPoints[0][2] = dstPoint1[2];
  402 + const Point* ppt = { maskPoints[0] };
  403 + fillConvexPoly(mask, ppt, 3, Scalar(255, 255, 255), 8);
  404 +
  405 + for (int i = 0; i < dstHeight; i++) {
  406 + for (int j = 0; j < dstWidth; j++) {
  407 + if (mask.at<uchar>(i,j) == 255) {
  408 + if (dst.m().type() == CV_32FC3 || dst.m().type() == CV_8UC3)
  409 + dst.m().at<cv::Vec3b>(i,j) = buffer.at<cv::Vec3b>(i,j);
  410 + else if (dst.m().type() == CV_32F)
  411 + dst.m().at<float>(i,j) = buffer.at<float>(i,j);
  412 + else if (dst.m().type() == CV_8U)
  413 + dst.m().at<uchar>(i,j) = buffer.at<uchar>(i,j);
  414 + else
  415 + qFatal("Unsupported pixel format.");
  416 + }
  417 + }
  418 + }
  419 +
  420 + }
  421 +
  422 + dst.file = src.file;
  423 + dst.file.clearPoints();
  424 + dst.file.clearRects();
  425 + dst.file.remove("ProcrustesPoints");
  426 + dst.file.remove("ProcrustesPadding");
  427 + dst.file.remove("ProcrustesBounds");
  428 + }
  429 +};
  430 +
  431 +BR_REGISTER(Transform, TextureMapTransform)
  432 +
  433 +// SynthesizePointsTransform helper class
  434 +struct TriangleIndicies
  435 +{
  436 + int indicies[3];
  437 +
  438 + TriangleIndicies()
  439 + {
  440 + indicies[0] = 0;
  441 + indicies[1] = 0;
  442 + indicies[2] = 0;
  443 + }
  444 +
  445 + TriangleIndicies(QList<int> indexList)
  446 + {
  447 + assert(indexList.size() == 3);
  448 + qSort(indexList);
  449 + indicies[0] = indexList[0];
  450 + indicies[1] = indexList[1];
  451 + indicies[2] = indexList[2];
  452 + }
  453 +};
  454 +
  455 +inline bool operator==(const TriangleIndicies &a, const TriangleIndicies &b)
  456 +{
  457 + return (a.indicies[0] == b.indicies[0]) && (a.indicies[1] == b.indicies[1]) && (a.indicies[2] == b.indicies[2]);
  458 +}
  459 +
  460 +inline uint qHash(const TriangleIndicies &key)
  461 +{
  462 + return ::qHash(key.indicies[0]) ^ ::qHash(key.indicies[1]) ^ ::qHash(key.indicies[2]);
  463 +}
  464 +
  465 +QDataStream &operator<<(QDataStream &stream, const TriangleIndicies &ti)
  466 +{
  467 + return stream << ti.indicies[0] << ti.indicies[1] << ti.indicies[2];
  468 +}
  469 +
  470 +QDataStream &operator>>(QDataStream &stream, TriangleIndicies &ti)
  471 +{
  472 + return stream >> ti.indicies[0] >> ti.indicies[1] >> ti.indicies[2];
  473 +}
  474 +
  475 +/*!
  476 + * \ingroup transforms
  477 + * \brief Synthesize additional points via triangulation.
  478 + * \author Josh Klontz \cite jklontz
  479 + */
  480 + class SynthesizePointsTransform : public MetadataTransform
  481 + {
  482 + Q_OBJECT
  483 + Q_PROPERTY(float minRelativeDistance READ get_minRelativeDistance WRITE set_minRelativeDistance RESET reset_minRelativeDistance STORED false)
  484 + BR_PROPERTY(float, minRelativeDistance, 0) // [0, 1] range controlling whether or not to nearby synthetic points.
  485 + // 0 = keep all points, 1 = keep only the most distance point.
  486 +
  487 + QList<TriangleIndicies> triangles;
  488 +
  489 + void train(const TemplateList &data)
  490 + {
  491 + // Because not all triangulations are the same, we have to decide on a canonical set of triangles at training time.
  492 + QHash<TriangleIndicies, int> counts;
  493 + foreach (const Template &datum, data) {
  494 +
  495 + const QList<QPointF> points = datum.file.points();
  496 + if (points.size() == 0)
  497 + continue;
  498 + const QList< QList<int> > triangulation = TextureMapTransform::getTriangulation(points, TextureMapTransform::getBounds(points, 10));
  499 + if (triangulation.empty())
  500 + continue;
  501 +
  502 + foreach (const QList<int> &indicies, triangulation)
  503 + counts[TriangleIndicies(indicies)]++;
  504 + }
  505 +
  506 + triangles.clear();
  507 + QHash<TriangleIndicies, int>::const_iterator i = counts.constBegin();
  508 + while (i != counts.constEnd()) {
  509 + if (3 * i.value() > data.size())
  510 + triangles.append(i.key()); // Keep triangles that occur in at least a third of the training instances
  511 + ++i;
  512 + }
  513 +
  514 + if (minRelativeDistance > 0) { // Discard relatively small triangles
  515 + QVector<float> averageMinDistances(triangles.size());
  516 + foreach (const Template &datum, data) {
  517 + File dst;
  518 + projectMetadata(datum.file, dst);
  519 + const QList<QPointF> points = dst.points();
  520 +
  521 + QVector<float> minDistances(triangles.size());
  522 + for (int i=0; i<triangles.size(); i++) {
  523 + // Work backwards so that we can also consider distances between synthetic points
  524 + const QPointF &point = points[points.size()-1-i];
  525 + float minDistance = std::numeric_limits<float>::max();
  526 + for (int j=0; j<points.size()-1-i; j++)
  527 + minDistance = min(minDistance, sqrtf(powf(point.x() - points[j].x(), 2.f) + powf(point.y() - points[j].y(), 2.f)));
  528 + minDistances[triangles.size()-1-i] = minDistance;
  529 + }
  530 +
  531 + const float maxMinDistance = Common::Max(minDistances);
  532 + for (int i=0; i<minDistances.size(); i++)
  533 + averageMinDistances[i] += (minDistances[i] / maxMinDistance);
  534 + }
  535 +
  536 + const float maxAverageMinDistance = Common::Max(averageMinDistances);
  537 + for (int i=averageMinDistances.size()-1; i>=0; i--)
  538 + if (averageMinDistances[i] / maxAverageMinDistance < minRelativeDistance)
  539 + triangles.removeAt(i);
  540 + }
  541 +
  542 + if (Globals->verbose)
  543 + qDebug() << "Kept" << triangles.size() << "of" << counts.size() << "triangles.";
  544 + }
  545 +
  546 + void projectMetadata(const File &src, File &dst) const
  547 + {
  548 + QList<QPointF> points = src.points();
  549 + if (points.size() == 0) {
  550 + dst.fte = true;
  551 + return;
  552 + }
  553 +
  554 + foreach (const TriangleIndicies &triangle, triangles) {
  555 + const QPointF &p0 = points[triangle.indicies[0]];
  556 + const QPointF &p1 = points[triangle.indicies[1]];
  557 + const QPointF &p2 = points[triangle.indicies[2]];
  558 + points.append((p0 + p1 + p2) / 3 /* append the centroid of the triangle */);
  559 + }
  560 + dst.setPoints(points);
  561 + }
  562 +
  563 + void store(QDataStream &stream) const
  564 + {
  565 + stream << triangles;
  566 + }
  567 +
  568 + void load(QDataStream &stream)
  569 + {
  570 + stream >> triangles;
  571 + }
  572 + };
  573 + BR_REGISTER(Transform, SynthesizePointsTransform)
  574 +
  575 +/*!
  576 + * \ingroup initializers
  577 + * \brief Initialize Procrustes croppings
  578 + * \author Brendan Klare \cite bklare
  579 + */
  580 +class ProcrustesInitializer : public Initializer
  581 +{
  582 + Q_OBJECT
  583 +
  584 + void initialize() const
  585 + {
  586 + Globals->abbreviations.insert("ProcrustesStasmFace","SelectPoints([17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76])+ProcrustesAlign(padding=6,width=120)+TextureMap+Resize(96,96)");
  587 + Globals->abbreviations.insert("ProcrustesStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)");
  588 + Globals->abbreviations.insert("ProcrustesStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=10)+TextureMap+Resize(36,48)");
  589 + Globals->abbreviations.insert("ProcrustesStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)");
  590 + Globals->abbreviations.insert("ProcrustesStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=12)+TextureMap+Resize(36,48)");
  591 + Globals->abbreviations.insert("ProcrustesStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=10)+TextureMap+Resize(36,48)");
  592 + Globals->abbreviations.insert("ProcrustesStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(36,48)");
  593 +
  594 + Globals->abbreviations.insert("ProcrustesEyes","SelectPoints([19,20,21,22,23,24,25,26,27,28,29,30])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)");
  595 + Globals->abbreviations.insert("ProcrustesNose","SelectPoints([12,13,14,15,16,17,18])+ProcrustesAlign(padding=30)+TextureMap+Resize(36,48)");
  596 + Globals->abbreviations.insert("ProcrustesMouth","SelectPoints([31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50])+ProcrustesAlign(padding=6)+TextureMap+Resize(36,48)");
  597 + Globals->abbreviations.insert("ProcrustesBrow","SelectPoints([0,1,2,3,4,5,6,7,8,9])+ProcrustesAlign(padding=6)+TextureMap+Resize(24,48)");
  598 + Globals->abbreviations.insert("ProcrustesFace","ProcrustesAlign(padding=6,width=120)+TextureMap+Resize(96,96)");
  599 +
  600 + Globals->abbreviations.insert("ProcrustesLargeStasmFace","ProcrustesAlign(padding=18)+TextureMap+Resize(480,480)");
  601 + Globals->abbreviations.insert("ProcrustesLargeStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)");
  602 + Globals->abbreviations.insert("ProcrustesLargeStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=10)+TextureMap+Resize(360,480)");
  603 + Globals->abbreviations.insert("ProcrustesLargeStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)");
  604 + Globals->abbreviations.insert("ProcrustesLargeStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=12)+TextureMap+Resize(360,480)");
  605 + Globals->abbreviations.insert("ProcrustesLargeStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=20)+TextureMap+Resize(360,480)");
  606 + Globals->abbreviations.insert("ProcrustesLargeStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(360,480)");
  607 + }
  608 +};
  609 +BR_REGISTER(Initializer, ProcrustesInitializer)
  610 +
  611 +} // namespace br
  612 +
  613 +#include "align.moc"
... ...
openbr/plugins/core/attributealgorithms.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup initializers
  24 + * \brief Initializes global abbreviations with implemented algorithms for attributes
  25 + * \author Babatunde Ogunfemi \cite baba1472
  26 + */
  27 +class AttributeAlgorithmsInitializer : public Initializer
  28 +{
  29 + Q_OBJECT
  30 +
  31 + void initialize() const
  32 + {
  33 + // Constants
  34 + QString BASE="Open+PP5Register+Rename(PP5_Landmark0_Right_Eye,Affine_0)+Rename(PP5_Landmark1_Left_Eye,Affine_1)+Affine(192,240,.345,.475)+Cvt(Gray)+Stasm(false,true,[(66.24,114),(125.76,114)])";
  35 + QString SUBSPACE ="Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,4,4)+Hist(59)+Cat+PCA(0.95)";
  36 +
  37 + QString NOSE="RectFromStasmNoseWithBridge+ROI+Resize(36,24)+" + SUBSPACE;
  38 + QString MOUTH="RectFromStasmMouth+ROI+Resize(24,36)+" + SUBSPACE;
  39 + QString EYES="RectFromStasmEyes+ROI+Resize(24,36)+" + SUBSPACE;
  40 + QString HAIR="RectFromStasmHair+ROI+Resize(24,36)+" + SUBSPACE;
  41 + QString BROW="RectFromStasmBrow+ROI+Resize(24,36)+" + SUBSPACE;
  42 + QString JAW="RectFromStasmJaw+ROI+Resize(36,36)+" + SUBSPACE;
  43 + QString FACE = "Crop(24,30,144,190)+Resize(36,36)+" + SUBSPACE;
  44 +
  45 + // All Attributes
  46 + Globals->abbreviations.insert("AllAttributes", "AttributeBrow/AttributeMouth/AttributeEyes/AttributeFace/AttributeHair/AttributeNose/AttributeJaw");
  47 + Globals->abbreviations.insert("AllAttributesMatching", "(AttributeBrow)/(AttributeMouth)/(AttributeEyes)/(AttributeFace)/(AttributeHair)/(AttributeNose)/(AttributeJaw):AttributeMatch");
  48 +
  49 + //Individual Attributes
  50 + Globals->abbreviations.insert("AttributeBrow", "(" + BASE+ "+" + BROW + "+"
  51 + "TurkClassifier(eyebrowposition,[closebrows,highbrows],3)/"
  52 + "TurkClassifier(unibrow,[unibrow],3)/"
  53 + "TurkClassifier(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3)/"
  54 + "TurkClassifier(thickeyebrows,[thickeyebrows,lighteyebrows],3))");
  55 + Globals->abbreviations.insert("AttributeMouth", "(" + BASE + "+" + MOUTH + "+"
  56 + "TurkClassifier(smiling,[smiling],3)/"
  57 + "TurkClassifier(lipthickness,[cherry,big,small],3)/"
  58 + "TurkClassifier(mouthbite,[underbite,overbite],3)/"
  59 + "TurkClassifier(mouthopen,[closed,noteeth,halfteeth,allteeth],3)/"
  60 + "TurkClassifier(mouthwidth,[small,wide],3)/"
  61 + "TurkClassifier(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3)/"
  62 + "TurkClassifier(mouthasymmetry,[asymmetrical],3))");
  63 + Globals->abbreviations.insert("AttributeEyes", "(" + BASE + "+" + EYES + "+ "
  64 + "TurkClassifier(eyeseparation,[close,wide],3)/"
  65 + "TurkClassifier(eyeslant,[slant2,slant1,wild],3)/"
  66 + "TurkClassifier(benteyes,[bent])/"
  67 + "TurkClassifier(eyecolor,[darkeyes,lighteyes],3)/"
  68 + "TurkClassifier(baggyeyes,[baggy],3)/"
  69 + "TurkClassifier(almondeyes,[almond],3)/"
  70 + "TurkClassifier(buriedeyes,[buriedeyes],3)/"
  71 + "TurkClassifier(sleepyeyes,[sleepy],3)/"
  72 + "TurkClassifier(lineeyes,[line],3)/"
  73 + "TurkClassifier(roundeyes,[round],3)/"
  74 + "TurkClassifier(sharpeyes,[sharp],3)/"
  75 + "TurkClassifier(smalleyes,[smalleyes],3)/"
  76 + "TurkClassifier(glasses,[glasses],3)/"
  77 + "TurkClassifier(eyelashvisibility,[feweyelashes],3))");
  78 + Globals->abbreviations.insert("AttributeFace", "(" + BASE + "+" + FACE + "+"
  79 + "TurkClassifier(gender,[male],3)/"
  80 + "TurkClassifier(faceshape,[round,triangular,rectangular],3)/"
  81 + "TurkClassifier(cheekdensity,[puffy,in,normal],3)/"
  82 + "TurkClassifier(facemarks,[scars,moles,normal],3)/"
  83 + "TurkClassifier(facelength,[long],3)/"
  84 + "TurkClassifier(nosetoeyedist,[short,long],3)/"
  85 + "TurkClassifier(nosetomouthdist,[long,small],3))");
  86 + Globals->abbreviations.insert("AttributeHair", "(" + BASE + "+" + HAIR + "+"
  87 + "TurkClassifier(foreheadwrinkles,[wrinkled],3)/"
  88 + "TurkClassifier(foreheadsize,[smallforehead,largeforehead],3)/"
  89 + "TurkClassifier(haircolor,[darkhair,lighthair,greyhair],3)/"
  90 + "TurkClassifier(hairdensity,[thick,bald,thin,halfbald],3)/"
  91 + "TurkClassifier(widowspeak,[widowspeak],3)/"
  92 + "TurkClassifier(hairstyle,[curlyhair],3))");
  93 + Globals->abbreviations.insert("AttributeNose", "(" + BASE + "+" + NOSE + "+"
  94 + "TurkClassifier(noseorientation,[upnose,downnose],3)/"
  95 + "TurkClassifier(nosewidth,[small,thick],3)/"
  96 + "TurkClassifier(nosesize,[smallnose,bignose],3)/"
  97 + "TurkClassifier(brokennose,[broken],3))");
  98 + Globals->abbreviations.insert("AttributeJaw", "(" + BASE + "+" + JAW + "+"
  99 + "TurkClassifier(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3)/"
  100 + "TurkClassifier(chinsize,[shortchin,longchin],3))");
  101 + Globals->abbreviations.insert("AttributeMatch", "Fuse(["
  102 + "Turk(eyebrowposition,[closebrows,highbrows],3),"
  103 + "Turk(unibrow,[unibrow],3),"
  104 + "Turk(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3),"
  105 + "Turk(thickeyebrows,[thickeyebrows,lighteyebrows],3),"
  106 + "Turk(smiling,[smiling],3),"
  107 + "Turk(lipthickness,[cherry,big,small],3),"
  108 + "Turk(mouthbite,[underbite,overbite],3),"
  109 + "Turk(mouthopen,[closed,noteeth,halfteeth,allteeth],3),"
  110 + "Turk(mouthwidth,[small,wide],3),"
  111 + "Turk(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3),"
  112 + "Turk(mouthasymmetry,[asymmetrical],3),"
  113 + "Turk(eyeseparation,[close,wide],3),"
  114 + "Turk(eyeslant,[slant2,slant1,wild],3),"
  115 + "Turk(benteyes,[bent],3),"
  116 + "Turk(eyecolor,[darkeyes,lighteyes],3),"
  117 + "Turk(baggyeyes,[baggy],3),"
  118 + "Turk(almondeyes,[almond],3),"
  119 + "Turk(buriedeyes,[buriedeyes],3),"
  120 + "Turk(sleepyeyes,[sleepy],3),"
  121 + "Turk(lineeyes,[line],3),"
  122 + "Turk(roundeyes,[round],3),"
  123 + "Turk(sharpeyes,[sharp],3),"
  124 + "Turk(smalleyes,[smalleyes],3),"
  125 + "Turk(glasses,[glasses],3),"
  126 + "Turk(eyelashvisibility,[feweyelashes],3),"
  127 + "Turk(gender,[male],3),"
  128 + "Turk(faceshape,[round,triangular,rectangular],3),"
  129 + "Turk(cheekdensity,[puffy,in,normal],3),"
  130 + "Turk(facemarks,[scars,moles,normal],3),"
  131 + "Turk(facelength,[long],3),"
  132 + "Turk(nosetoeyedist,[short,long],3),"
  133 + "Turk(nosetomouthdist,[long,small],3),"
  134 + "Turk(foreheadwrinkles,[wrinkled],3),"
  135 + "Turk(foreheadsize,[smallforehead,largeforehead],3),"
  136 + "Turk(haircolor,[darkhair,lighthair,greyhair],3),"
  137 + "Turk(hairdensity,[thick,bald,thin,halfbald],3),"
  138 + "Turk(widowspeak,[widowspeak],3),"
  139 + "Turk(hairstyle,[curlyhair],3),"
  140 + "Turk(noseorientation,[upnose,downnose],3),"
  141 + "Turk(nosewidth,[small,thick],3),"
  142 + "Turk(nosesize,[smallnose,bignose],3),"
  143 + "Turk(brokennose,[broken],3),"
  144 + "Turk(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3),"
  145 + "Turk(chinsize,[shortchin,longchin],3)])");
  146 + }
  147 +};
  148 +
  149 +BR_REGISTER(Initializer, AttributeAlgorithmsInitializer)
  150 +
  151 +} // namespace br
  152 +
  153 +#include "core/attributealgorithms.moc"
... ...
openbr/plugins/core/cache.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Caches br::Transform::project() results.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class CacheTransform : public MetaTransform
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  31 + BR_PROPERTY(br::Transform*, transform, NULL)
  32 +
  33 + static QHash<QString, Template> cache;
  34 + static QMutex cacheLock;
  35 +
  36 +public:
  37 + ~CacheTransform()
  38 + {
  39 + if (cache.isEmpty()) return;
  40 +
  41 + // Write to cache
  42 + QFile file("Cache");
  43 + if (!file.open(QFile::WriteOnly))
  44 + qFatal("Unable to open %s for writing.", qPrintable(file.fileName()));
  45 + QDataStream stream(&file);
  46 + stream << cache;
  47 + file.close();
  48 + }
  49 +
  50 +private:
  51 + void init()
  52 + {
  53 + if (!transform) return;
  54 +
  55 + trainable = transform->trainable;
  56 + if (!cache.isEmpty()) return;
  57 +
  58 + // Read from cache
  59 + QFile file("Cache");
  60 + if (file.exists()) {
  61 + if (!file.open(QFile::ReadOnly))
  62 + qFatal("Unable to open %s for reading.", qPrintable(file.fileName()));
  63 + QDataStream stream(&file);
  64 + stream >> cache;
  65 + file.close();
  66 + }
  67 + }
  68 +
  69 + void train(const QList<TemplateList> &data)
  70 + {
  71 + transform->train(data);
  72 + }
  73 +
  74 + void project(const Template &src, Template &dst) const
  75 + {
  76 + const QString &file = src.file;
  77 + if (cache.contains(file)) {
  78 + dst = cache[file];
  79 + } else {
  80 + transform->project(src, dst);
  81 + cacheLock.lock();
  82 + cache[file] = dst;
  83 + cacheLock.unlock();
  84 + }
  85 + }
  86 +};
  87 +
  88 +QHash<QString, Template> CacheTransform::cache;
  89 +QMutex CacheTransform::cacheLock;
  90 +
  91 +BR_REGISTER(Transform, CacheTransform)
  92 +
  93 +} // namespace br
  94 +
  95 +#include "core/cache.moc"
... ...
openbr/plugins/core/contract.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief It's like the opposite of ExpandTransform, but not really
  25 + * \author Charles Otto \cite caotto
  26 + *
  27 + * Given a set of templatelists as input, concatenate them onto a single Template
  28 + */
  29 +class ContractTransform : public UntrainableMetaTransform
  30 +{
  31 + Q_OBJECT
  32 +
  33 + virtual void project(const TemplateList &src, TemplateList &dst) const
  34 + {
  35 + if (src.empty()) return;
  36 + Template out;
  37 +
  38 + foreach (const Template &t, src) {
  39 + out.merge(t);
  40 + }
  41 + out.file.clearRects();
  42 + foreach (const Template &t, src) {
  43 + if (!t.file.rects().empty())
  44 + out.file.appendRects(t.file.rects());
  45 + }
  46 + dst.clear();
  47 + dst.append(out);
  48 + }
  49 +
  50 + virtual void project(const Template &src, Template &dst) const
  51 + {
  52 + qFatal("this has gone bad");
  53 + (void) src; (void) dst;
  54 + }
  55 +};
  56 +
  57 +BR_REGISTER(Transform, ContractTransform)
  58 +
  59 +} // namespace br
  60 +
  61 +#include "core/contract.moc"
... ...
openbr/plugins/validate.cpp renamed to openbr/plugins/core/crossvalidate.cpp
1   -#include <QFutureSynchronizer>
2   -#include <QtConcurrentRun>
3   -#include "openbr_internal.h"
4   -#include "openbr/core/common.h"
5   -#include <openbr/core/qtutils.h>
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/common.h>
6 21  
7 22 namespace br
8 23 {
... ... @@ -134,138 +149,6 @@ class CrossValidateTransform : public MetaTransform
134 149  
135 150 BR_REGISTER(Transform, CrossValidateTransform)
136 151  
137   -/*!
138   - * \ingroup distances
139   - * \brief Cross validate a distance metric.
140   - * \author Josh Klontz \cite jklontz
141   - */
142   -class CrossValidateDistance : public UntrainableDistance
143   -{
144   - Q_OBJECT
145   -
146   - float compare(const Template &a, const Template &b) const
147   - {
148   - static const QString key("Partition"); // More efficient to preallocate this
149   - const int partitionA = a.file.get<int>(key, 0);
150   - const int partitionB = b.file.get<int>(key, 0);
151   - return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0;
152   - }
153   -};
154   -
155   -BR_REGISTER(Distance, CrossValidateDistance)
156   -
157   -/*!
158   - * \ingroup distances
159   - * \brief Checks target metadata against filters.
160   - * \author Josh Klontz \cite jklontz
161   - */
162   -class FilterDistance : public UntrainableDistance
163   -{
164   - Q_OBJECT
165   -
166   - float compare(const Template &a, const Template &b) const
167   - {
168   - (void) b; // Query template isn't checked
169   - foreach (const QString &key, Globals->filters.keys()) {
170   - bool keep = false;
171   - const QString metadata = a.file.get<QString>(key, "");
172   - if (Globals->filters[key].isEmpty()) continue;
173   - if (metadata.isEmpty()) return -std::numeric_limits<float>::max();
174   - foreach (const QString &value, Globals->filters[key]) {
175   - if (metadata == value) {
176   - keep = true;
177   - break;
178   - }
179   - }
180   - if (!keep) return -std::numeric_limits<float>::max();
181   - }
182   - return 0;
183   - }
184   -};
185   -
186   -BR_REGISTER(Distance, FilterDistance)
187   -
188   -/*!
189   - * \ingroup distances
190   - * \brief Checks target metadata against query metadata.
191   - * \author Scott Klum \cite sklum
192   - */
193   -class MetadataDistance : public UntrainableDistance
194   -{
195   - Q_OBJECT
196   -
197   - Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false)
198   - BR_PROPERTY(QStringList, filters, QStringList())
199   -
200   - float compare(const Template &a, const Template &b) const
201   - {
202   - foreach (const QString &key, filters) {
203   - QString aValue = a.file.get<QString>(key, QString());
204   - QString bValue = b.file.get<QString>(key, QString());
205   -
206   - // The query value may be a range. Let's check.
207   - if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF()));
208   -
209   - if (aValue.isEmpty() || bValue.isEmpty()) continue;
210   -
211   - bool keep = false;
212   - bool ok;
213   -
214   - QPointF range = QtUtils::toPoint(bValue,&ok);
215   -
216   - if (ok) /* Range */ {
217   - int value = range.x();
218   - int upperBound = range.y();
219   -
220   - while (value <= upperBound) {
221   - if (aValue == QString::number(value)) {
222   - keep = true;
223   - break;
224   - }
225   - value++;
226   - }
227   - }
228   - else if (aValue == bValue) keep = true;
229   -
230   - if (!keep) return -std::numeric_limits<float>::max();
231   - }
232   - return 0;
233   - }
234   -};
235   -
236   -
237   -BR_REGISTER(Distance, MetadataDistance)
238   -
239   -/*!
240   - * \ingroup distances
241   - * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key.
242   - * \author Scott Klum \cite sklum
243   - */
244   -class RejectDistance : public UntrainableDistance
245   -{
246   - Q_OBJECT
247   -
248   - Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
249   - BR_PROPERTY(QStringList, keys, QStringList())
250   - Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false)
251   - BR_PROPERTY(bool, rejectIfContains, false)
252   -
253   - float compare(const Template &a, const Template &b) const
254   - {
255   - // We don't look at the query
256   - (void) b;
257   -
258   - foreach (const QString &key, keys)
259   - if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
260   - return -std::numeric_limits<float>::max();
261   -
262   - return 0;
263   - }
264   -};
265   -
266   -
267   -BR_REGISTER(Distance, RejectDistance)
268   -
269 152 } // namespace br
270 153  
271   -#include "validate.moc"
  154 +#include "core/crossvalidate.moc"
... ...
openbr/plugins/core/discard.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Removes all template's matrices.
  25 + * \see IdentityTransform FirstTransform RestTransform RemoveTransform
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class DiscardTransform : public UntrainableMetaTransform
  29 +{
  30 + Q_OBJECT
  31 +
  32 + void project(const Template &src, Template &dst) const
  33 + {
  34 + dst.file = src.file;
  35 + }
  36 +};
  37 +
  38 +BR_REGISTER(Transform, DiscardTransform)
  39 +
  40 +} // namespace br
  41 +
  42 +#include "core/discard.moc"
... ...
openbr/plugins/core/discardtemplates.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +class DiscardTemplatesTransform : public UntrainableMetaTransform
  23 +{
  24 + Q_OBJECT
  25 +
  26 + void project(const Template &src, Template &dst) const
  27 + {
  28 + (void) src; (void) dst;
  29 + qFatal("Incorrect project called on DiscardTemplatesTransform");
  30 + }
  31 + void project(const TemplateList &src, TemplateList &dst) const
  32 + {
  33 + (void) src;
  34 + dst.clear();
  35 + }
  36 +};
  37 +
  38 +BR_REGISTER(Transform, DiscardTemplatesTransform)
  39 +
  40 +} // namespace br
  41 +
  42 +#include "core/discardtemplates.moc"
... ...
openbr/plugins/core/distributetemplate.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +static void _projectList(const Transform *transform, const TemplateList *src, TemplateList *dst)
  25 +{
  26 + transform->project(*src, *dst);
  27 +}
  28 +
  29 +class DistributeTemplateTransform : public MetaTransform
  30 +{
  31 + Q_OBJECT
  32 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  33 + BR_PROPERTY(br::Transform*, transform, NULL)
  34 +
  35 +public:
  36 +
  37 + Transform *smartCopy(bool &newTransform)
  38 + {
  39 + if (!transform->timeVarying()) {
  40 + newTransform = false;
  41 + return this;
  42 + }
  43 + newTransform = true;
  44 +
  45 + DistributeTemplateTransform *output = new DistributeTemplateTransform;
  46 + bool newChild = false;
  47 + output->transform = transform->smartCopy(newChild);
  48 + if (newChild)
  49 + output->transform->setParent(output);
  50 +
  51 + return output;
  52 + }
  53 +
  54 + void train(const QList<TemplateList> &data)
  55 + {
  56 + if (!transform->trainable) {
  57 + qWarning("Attempted to train untrainable transform, nothing will happen.");
  58 + return;
  59 + }
  60 +
  61 + QList<TemplateList> separated;
  62 + foreach (const TemplateList &list, data) {
  63 + foreach (const Template &t, list) {
  64 + separated.append(TemplateList());
  65 + separated.last().append(t);
  66 + }
  67 + }
  68 +
  69 + transform->train(separated);
  70 + }
  71 +
  72 + void project(const Template &src, Template &dst) const
  73 + {
  74 + TemplateList input;
  75 + input.append(src);
  76 + TemplateList output;
  77 + project(input, output);
  78 +
  79 + if (output.size() != 1) qFatal("output contains more than 1 template");
  80 + else dst = output[0];
  81 + }
  82 +
  83 + // For each input template, form a single element TemplateList, push all those
  84 + // lists through transform, and form dst by concatenating the results.
  85 + // Process the single elemnt templates in parallel if parallelism is enabled.
  86 + void project(const TemplateList &src, TemplateList &dst) const
  87 + {
  88 + // Pre-allocate output for each template
  89 + QList<TemplateList> output_buffer;
  90 + output_buffer.reserve(src.size());
  91 +
  92 + // Can't declare this local to the loop because it would go out of scope
  93 + QList<TemplateList> input_buffer;
  94 + input_buffer.reserve(src.size());
  95 +
  96 + QFutureSynchronizer<void> futures;
  97 +
  98 + for (int i =0; i < src.size();i++) {
  99 + input_buffer.append(TemplateList());
  100 + output_buffer.append(TemplateList());
  101 + }
  102 + QList<QFuture<void> > temp;
  103 + temp.reserve(src.size());
  104 + for (int i=0; i<src.size(); i++) {
  105 + input_buffer[i].append(src[i]);
  106 +
  107 + if (Globals->parallelism > 1) temp.append(QtConcurrent::run(_projectList, transform, &input_buffer[i], &output_buffer[i]));
  108 + else _projectList(transform, &input_buffer[i], &output_buffer[i]);
  109 + }
  110 + // We add the futures in reverse order, since in Qt 5.1 at least the
  111 + // waiting thread will wait on them in the order added (which for uniform priority
  112 + // threads is the order of execution), and we want the waiting thread to go in the opposite order
  113 + // so that it can steal runnables and do something besides wait.
  114 + for (int i = temp.size() - 1; i >= 0; i--) {
  115 + futures.addFuture(temp[i]);
  116 + }
  117 +
  118 + futures.waitForFinished();
  119 +
  120 + for (int i=0; i<src.size(); i++) dst.append(output_buffer[i]);
  121 + }
  122 +
  123 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  124 + {
  125 + this->project(src, dst);
  126 + return;
  127 + }
  128 +
  129 + void init()
  130 + {
  131 + if (!transform)
  132 + return;
  133 +
  134 + trainable = transform->trainable;
  135 + }
  136 +
  137 +};
  138 +BR_REGISTER(Transform, DistributeTemplateTransform)
  139 +
  140 +} // namespace br
  141 +
  142 +#include "core/distributetemplate.moc"
... ...
openbr/plugins/core/downsampletraining.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +static TemplateList Downsample(const TemplateList &templates, int classes, int instances, float fraction, const QString &inputVariable, const QStringList &gallery, const QStringList &subjects)
  23 +{
  24 + // Return early when no downsampling is required
  25 + if ((classes == std::numeric_limits<int>::max()) &&
  26 + (instances == std::numeric_limits<int>::max()) &&
  27 + (fraction >= 1) &&
  28 + (gallery.isEmpty()) &&
  29 + (subjects.isEmpty()))
  30 + return templates;
  31 +
  32 + const bool atLeast = instances < 0;
  33 + instances = abs(instances);
  34 +
  35 + QList<QString> allLabels = File::get<QString>(templates, inputVariable);
  36 +
  37 + QList<QString> uniqueLabels = allLabels.toSet().toList();
  38 + qSort(uniqueLabels);
  39 +
  40 + QMap<QString,int> counts = templates.countValues<QString>(inputVariable, instances != std::numeric_limits<int>::max());
  41 +
  42 + if ((instances != std::numeric_limits<int>::max()) && (classes != std::numeric_limits<int>::max()))
  43 + foreach (const QString &label, counts.keys())
  44 + if (counts[label] < instances)
  45 + counts.remove(label);
  46 +
  47 + uniqueLabels = counts.keys();
  48 + if ((classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < classes))
  49 + qWarning("Downsample requested %d classes but only %d are available.", classes, uniqueLabels.size());
  50 +
  51 + QList<QString> selectedLabels = uniqueLabels;
  52 + if (classes < uniqueLabels.size()) {
  53 + std::random_shuffle(selectedLabels.begin(), selectedLabels.end());
  54 + selectedLabels = selectedLabels.mid(0, classes);
  55 + }
  56 +
  57 + TemplateList downsample;
  58 + for (int i=0; i<selectedLabels.size(); i++) {
  59 + const QString selectedLabel = selectedLabels[i];
  60 + QList<int> indices;
  61 + for (int j=0; j<allLabels.size(); j++)
  62 + if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false)) && (!templates.value(j).file.get<bool>("PossibleFTE", false)))
  63 + indices.append(j);
  64 +
  65 + std::random_shuffle(indices.begin(), indices.end());
  66 + const int max = atLeast ? indices.size() : std::min(indices.size(), instances);
  67 + for (int j=0; j<max; j++)
  68 + downsample.append(templates.value(indices[j]));
  69 + }
  70 +
  71 + if (fraction < 1) {
  72 + std::random_shuffle(downsample.begin(), downsample.end());
  73 + downsample = downsample.mid(0, downsample.size()*fraction);
  74 + }
  75 +
  76 + if (!gallery.isEmpty())
  77 + for (int i=downsample.size()-1; i>=0; i--)
  78 + if (!gallery.contains(downsample[i].file.get<QString>("Gallery")))
  79 + downsample.removeAt(i);
  80 +
  81 + if (!subjects.isEmpty())
  82 + for (int i=downsample.size()-1; i>=0; i--)
  83 + if (subjects.contains(downsample[i].file.get<QString>(inputVariable)))
  84 + downsample.removeAt(i);
  85 +
  86 + return downsample;
  87 +}
  88 +
  89 +class DownsampleTrainingTransform : public Transform
  90 +{
  91 + Q_OBJECT
  92 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED true)
  93 + Q_PROPERTY(int classes READ get_classes WRITE set_classes RESET reset_classes STORED false)
  94 + Q_PROPERTY(int instances READ get_instances WRITE set_instances RESET reset_instances STORED false)
  95 + Q_PROPERTY(float fraction READ get_fraction WRITE set_fraction RESET reset_fraction STORED false)
  96 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  97 + Q_PROPERTY(QStringList gallery READ get_gallery WRITE set_gallery RESET reset_gallery STORED false)
  98 + Q_PROPERTY(QStringList subjects READ get_subjects WRITE set_subjects RESET reset_subjects STORED false)
  99 + BR_PROPERTY(br::Transform*, transform, NULL)
  100 + BR_PROPERTY(int, classes, std::numeric_limits<int>::max())
  101 + BR_PROPERTY(int, instances, std::numeric_limits<int>::max())
  102 + BR_PROPERTY(float, fraction, 1)
  103 + BR_PROPERTY(QString, inputVariable, "Label")
  104 + BR_PROPERTY(QStringList, gallery, QStringList())
  105 + BR_PROPERTY(QStringList, subjects, QStringList())
  106 +
  107 +
  108 + Transform *simplify(bool &newTForm)
  109 + {
  110 + Transform *res = transform->simplify(newTForm);
  111 + return res;
  112 + }
  113 +
  114 + void project(const Template &src, Template &dst) const
  115 + {
  116 + transform->project(src,dst);
  117 + }
  118 +
  119 +
  120 + void train(const TemplateList &data)
  121 + {
  122 + if (!transform || !transform->trainable)
  123 + return;
  124 +
  125 + TemplateList downsampled = Downsample(data, classes, instances, fraction, inputVariable, gallery, subjects);
  126 +
  127 + transform->train(downsampled);
  128 + }
  129 +};
  130 +
  131 +BR_REGISTER(Transform, DownsampleTrainingTransform)
  132 +
  133 +} // namespace br
  134 +
  135 +#include "core/downsampletraining.moc"
... ...
openbr/plugins/core/event.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +class EventTransform : public UntrainableMetaTransform
  23 +{
  24 + Q_OBJECT
  25 + Q_PROPERTY(QString eventName READ get_eventName WRITE set_eventName RESET reset_eventName STORED false)
  26 + BR_PROPERTY(QString, eventName, "")
  27 +
  28 + TemplateEvent event;
  29 +
  30 + void project(const Template &src, Template &dst) const
  31 + {
  32 + dst = src;
  33 + event.pulseSignal(dst);
  34 + }
  35 +
  36 + TemplateEvent *getEvent(const QString &name)
  37 + {
  38 + return name == eventName ? &event : NULL;
  39 + }
  40 +};
  41 +
  42 +BR_REGISTER(Transform, EventTransform)
  43 +
  44 +} // namespace br
  45 +
  46 +#include "core/event.moc"
... ...
openbr/plugins/core/expand.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +static TemplateList Expanded(const TemplateList &templates)
  23 +{
  24 + TemplateList expanded;
  25 + foreach (const Template &t, templates) {
  26 + const bool enrollAll = t.file.get<bool>("enrollAll");
  27 + if (t.isEmpty()) {
  28 + if (!enrollAll)
  29 + expanded.append(t);
  30 + continue;
  31 + }
  32 +
  33 + const QList<QPointF> points = t.file.points();
  34 + const QList<QRectF> rects = t.file.rects();
  35 + if (points.size() % t.size() != 0) qFatal("Uneven point count.");
  36 + if (rects.size() % t.size() != 0) qFatal("Uneven rect count.");
  37 + const int pointStep = points.size() / t.size();
  38 + const int rectStep = rects.size() / t.size();
  39 +
  40 + for (int i=0; i<t.size(); i++) {
  41 + expanded.append(Template(t.file, t[i]));
  42 + expanded.last().file.setRects(rects.mid(i*rectStep, rectStep));
  43 + expanded.last().file.setPoints(points.mid(i*pointStep, pointStep));
  44 + }
  45 + }
  46 + return expanded;
  47 +}
  48 +
  49 +/*!
  50 + * \ingroup transforms
  51 + * \brief Performs an expansion step on input templatelists
  52 + * \author Josh Klontz \cite jklontz
  53 + *
  54 + * Each matrix in an input Template is expanded into its own template.
  55 + *
  56 + * \see PipeTransform
  57 + */
  58 +class ExpandTransform : public UntrainableMetaTransform
  59 +{
  60 + Q_OBJECT
  61 +
  62 + virtual void project(const TemplateList &src, TemplateList &dst) const
  63 + {
  64 + dst = Expanded(src);
  65 + }
  66 +
  67 + virtual void project(const Template &src, Template &dst) const
  68 + {
  69 + dst = src;
  70 + qDebug("Called Expand project(Template,Template), nothing will happen");
  71 + }
  72 +};
  73 +
  74 +BR_REGISTER(Transform, ExpandTransform)
  75 +
  76 +} // namespace br
  77 +
  78 +#include "core/expand.moc"
... ...
openbr/plugins/core/first.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Removes all but the first matrix from the template.
  25 + * \see IdentityTransform DiscardTransform RestTransform RemoveTransform
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class FirstTransform : public UntrainableMetaTransform
  29 +{
  30 + Q_OBJECT
  31 +
  32 + void project(const Template &src, Template &dst) const
  33 + {
  34 + // AggregateFrames will leave the Template empty
  35 + // if it hasn't filled up the buffer
  36 + // so we gotta anticipate an empty Template
  37 + if (src.empty()) return;
  38 + dst.file = src.file;
  39 + dst = src.m();
  40 + }
  41 +};
  42 +
  43 +BR_REGISTER(Transform, FirstTransform)
  44 +
  45 +} // namespace br
  46 +
  47 +#include "core/first.moc"
... ...
openbr/plugins/core/fork.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +static void _train(Transform *transform, const QList<TemplateList> *data)
  25 +{
  26 + transform->train(*data);
  27 +}
  28 +
  29 +/*!
  30 + * \ingroup transforms
  31 + * \brief Transforms in parallel.
  32 + * \author Josh Klontz \cite jklontz
  33 + *
  34 + * The source br::Template is seperately given to each transform and the results are appended together.
  35 + *
  36 + * \see PipeTransform
  37 + */
  38 +class ForkTransform : public CompositeTransform
  39 +{
  40 + Q_OBJECT
  41 +
  42 + void train(const QList<TemplateList> &data)
  43 + {
  44 + if (!trainable) return;
  45 + QFutureSynchronizer<void> futures;
  46 + for (int i=0; i<transforms.size(); i++)
  47 + futures.addFuture(QtConcurrent::run(_train, transforms[i], &data));
  48 + futures.waitForFinished();
  49 + }
  50 +
  51 + // same as _project, but calls projectUpdate on sub-transforms
  52 + void projectupdate(const Template &src, Template &dst)
  53 + {
  54 + foreach (Transform *f, transforms) {
  55 + try {
  56 + Template res;
  57 + f->projectUpdate(src, res);
  58 + dst.merge(res);
  59 + } catch (...) {
  60 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  61 + dst = Template(src.file);
  62 + dst.file.fte = true;
  63 + break;
  64 + }
  65 + }
  66 + }
  67 +
  68 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  69 + {
  70 + dst.reserve(src.size());
  71 + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file));
  72 + foreach (Transform *f, transforms) {
  73 + TemplateList m;
  74 + f->projectUpdate(src, m);
  75 + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size.");
  76 + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]);
  77 + }
  78 + }
  79 +
  80 + // this is probably going to go bad, fork transform probably won't work well in a variable
  81 + // input/output scenario
  82 + virtual void finalize(TemplateList &output)
  83 + {
  84 + output.clear();
  85 + // For each transform,
  86 + for (int i = 0; i < transforms.size(); i++)
  87 + {
  88 + // Collect any final templates
  89 + TemplateList last_set;
  90 + transforms[i]->finalize(last_set);
  91 + if (last_set.empty())
  92 + continue;
  93 +
  94 + if (output.empty()) output = last_set;
  95 + else
  96 + {
  97 + // is the number of templates received from this transform consistent with the number
  98 + // received previously? If not we can't do anything coherent here.
  99 + if (last_set.size() != output.size())
  100 + qFatal("mismatched template list sizes in ForkTransform");
  101 + for (int j = 0; j < output.size(); j++) {
  102 + output[j].append(last_set[j]);
  103 + }
  104 + }
  105 + }
  106 + }
  107 +
  108 +protected:
  109 +
  110 + // Apply each transform to src, concatenate the results
  111 + void _project(const Template &src, Template &dst) const
  112 + {
  113 + foreach (const Transform *f, transforms) {
  114 + try {
  115 + dst.merge((*f)(src));
  116 + } catch (...) {
  117 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  118 + dst = Template(src.file);
  119 + dst.file.fte = true;
  120 + break;
  121 + }
  122 + }
  123 + }
  124 +
  125 + void _project(const TemplateList &src, TemplateList &dst) const
  126 + {
  127 + dst.reserve(src.size());
  128 + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file));
  129 + foreach (const Transform *f, transforms) {
  130 + TemplateList m;
  131 + f->project(src, m);
  132 + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size.");
  133 + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]);
  134 + }
  135 + }
  136 +
  137 +};
  138 +
  139 +BR_REGISTER(Transform, ForkTransform)
  140 +
  141 +} // namespace br
  142 +
  143 +#include "core/fork.moc"
... ...
openbr/plugins/core/fte.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/common.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup transforms
  25 + * \brief Flags images that failed to enroll based on the specified transform.
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class FTETransform : public Transform
  29 +{
  30 + Q_OBJECT
  31 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  32 + Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min)
  33 + Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max)
  34 + BR_PROPERTY(br::Transform*, transform, NULL)
  35 + BR_PROPERTY(float, min, -std::numeric_limits<float>::max())
  36 + BR_PROPERTY(float, max, std::numeric_limits<float>::max())
  37 +
  38 + void train(const TemplateList &data)
  39 + {
  40 + transform->train(data);
  41 +
  42 + TemplateList projectedData;
  43 + transform->project(data, projectedData);
  44 +
  45 + QList<float> vals;
  46 + foreach (const Template &t, projectedData) {
  47 + if (!t.file.contains(transform->objectName()))
  48 + qFatal("Matrix metadata missing key %s.", qPrintable(transform->objectName()));
  49 + vals.append(t.file.get<float>(transform->objectName()));
  50 + }
  51 + float q1, q3;
  52 + Common::Median(vals, &q1, &q3);
  53 + min = q1 - 1.5 * (q3 - q1);
  54 + max = q3 + 1.5 * (q3 - q1);
  55 + }
  56 +
  57 + void project(const Template &src, Template &dst) const
  58 + {
  59 + Template projectedSrc;
  60 + transform->project(src, projectedSrc);
  61 + const float val = projectedSrc.file.get<float>(transform->objectName());
  62 +
  63 + dst = src;
  64 + dst.file.set(transform->objectName(), val);
  65 + dst.file.set("PossibleFTE", (val < min) || (val > max));
  66 + }
  67 +};
  68 +
  69 +BR_REGISTER(Transform, FTETransform)
  70 +
  71 +} // namespace br
  72 +
  73 +#include "core/fte.moc"
... ...
openbr/plugins/core/gallerycompare.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/opencvutils.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup transforms
  25 + * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance.
  26 + * dst will contain a 1 by n vector of scores.
  27 + * \author Charles Otto \cite caotto
  28 + */
  29 +class GalleryCompareTransform : public Transform
  30 +{
  31 + Q_OBJECT
  32 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true)
  33 + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
  34 + BR_PROPERTY(br::Distance*, distance, NULL)
  35 + BR_PROPERTY(QString, galleryName, "")
  36 +
  37 + TemplateList gallery;
  38 +
  39 + void project(const Template &src, Template &dst) const
  40 + {
  41 + dst = src;
  42 + if (gallery.isEmpty())
  43 + return;
  44 +
  45 + QList<float> line = distance->compare(gallery, src);
  46 + dst.m() = OpenCVUtils::toMat(line, 1);
  47 + }
  48 +
  49 + void init()
  50 + {
  51 + if (!galleryName.isEmpty())
  52 + gallery = TemplateList::fromGallery(galleryName);
  53 + }
  54 +
  55 + void train(const TemplateList &data)
  56 + {
  57 + gallery = data;
  58 + }
  59 +
  60 + void store(QDataStream &stream) const
  61 + {
  62 + br::Object::store(stream);
  63 + stream << gallery;
  64 + }
  65 +
  66 + void load(QDataStream &stream)
  67 + {
  68 + br::Object::load(stream);
  69 + stream >> gallery;
  70 + }
  71 +
  72 +public:
  73 + GalleryCompareTransform() : Transform(false, true) {}
  74 +};
  75 +
  76 +BR_REGISTER(Transform, GalleryCompareTransform)
  77 +
  78 +} // namespace br
  79 +
  80 +#include "core/gallerycompare.moc"
... ...
openbr/plugins/core/identity.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief A no-op transform.
  25 + * \see DiscardTransform FirstTransform RestTransform RemoveTransform
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class IdentityTransform : public UntrainableMetaTransform
  29 +{
  30 + Q_OBJECT
  31 +
  32 + void project(const Template &src, Template &dst) const
  33 + {
  34 + dst = src;
  35 + }
  36 +};
  37 +
  38 +BR_REGISTER(Transform, IdentityTransform)
  39 +
  40 +} // namespace br
  41 +
  42 +#include "core/identity.moc"
... ...
openbr/plugins/core/independent.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +using namespace cv;
  22 +
  23 +namespace br
  24 +{
  25 +
  26 +/*!
  27 + * \ingroup transforms
  28 + * \brief Clones the transform so that it can be applied independently.
  29 + * \author Josh Klontz \cite jklontz
  30 + * \em Independent transforms expect single-matrix templates.
  31 + */
  32 +class IndependentTransform : public MetaTransform
  33 +{
  34 + Q_OBJECT
  35 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
  36 + BR_PROPERTY(br::Transform*, transform, NULL)
  37 +
  38 + QList<Transform*> transforms;
  39 +
  40 + QString description(bool expanded) const
  41 + {
  42 + return transform->description(expanded);
  43 + }
  44 +
  45 + // can't use general setPropertyRecursive because of transforms oddness
  46 + bool setPropertyRecursive(const QString &name, QVariant value)
  47 + {
  48 + if (br::Object::setExistingProperty(name, value))
  49 + return true;
  50 +
  51 + if (!transform->setPropertyRecursive(name, value))
  52 + return false;
  53 +
  54 + for (int i=0;i < transforms.size();i++)
  55 + transforms[i]->setPropertyRecursive(name, value);
  56 +
  57 + return true;
  58 + }
  59 +
  60 + Transform *simplify(bool &newTransform)
  61 + {
  62 + newTransform = false;
  63 + bool newChild = false;
  64 + Transform *temp = transform->simplify(newChild);
  65 + if (temp == transform) {
  66 + return this;
  67 + }
  68 + IndependentTransform* indep = new IndependentTransform();
  69 + indep->transform = temp;
  70 +
  71 + IndependentTransform *test = dynamic_cast<IndependentTransform *> (temp);
  72 + if (test) {
  73 + // child was independent? this changes things...
  74 + indep->transform = test->transform;
  75 + for (int i=0; i < transforms.size(); i++) {
  76 + bool newThing = false;
  77 + IndependentTransform *probe = dynamic_cast<IndependentTransform *> (transforms[i]->simplify(newThing));
  78 + indep->transforms.append(probe->transform);
  79 + if (newThing)
  80 + probe->setParent(indep);
  81 + }
  82 + indep->file = indep->transform->file;
  83 + indep->trainable = indep->transform->trainable;
  84 + indep->setObjectName(indep->transform->objectName());
  85 +
  86 + return indep;
  87 + }
  88 +
  89 + if (newChild)
  90 + indep->transform->setParent(indep);
  91 +
  92 + for (int i=0; i < transforms.size();i++) {
  93 + bool subTform = false;
  94 + indep->transforms.append(transforms[i]->simplify(subTform));
  95 + if (subTform)
  96 + indep->transforms[i]->setParent(indep);
  97 + }
  98 +
  99 + indep->file = indep->transform->file;
  100 + indep->trainable = indep->transform->trainable;
  101 + indep->setObjectName(indep->transform->objectName());
  102 +
  103 + return indep;
  104 + }
  105 +
  106 + void init()
  107 + {
  108 + transforms.clear();
  109 + if (transform == NULL)
  110 + return;
  111 +
  112 + transform->setParent(this);
  113 + transforms.append(transform);
  114 + file = transform->file;
  115 + trainable = transform->trainable;
  116 + setObjectName(transform->objectName());
  117 + }
  118 +
  119 + Transform *clone() const
  120 + {
  121 + IndependentTransform *independentTransform = new IndependentTransform();
  122 + independentTransform->transform = transform->clone();
  123 + independentTransform->init();
  124 + return independentTransform;
  125 + }
  126 +
  127 + bool timeVarying() const { return transform->timeVarying(); }
  128 +
  129 + static void _train(Transform *transform, const TemplateList *data)
  130 + {
  131 + transform->train(*data);
  132 + }
  133 +
  134 + void train(const TemplateList &data)
  135 + {
  136 + // Don't bother if the transform is untrainable
  137 + if (!trainable) return;
  138 +
  139 + QList<TemplateList> templatesList;
  140 + foreach (const Template &t, data) {
  141 + if ((templatesList.size() != t.size()) && !templatesList.isEmpty())
  142 + qWarning("Independent::train (%s) template %s of size %d differs from expected size %d.", qPrintable(objectName()), qPrintable(t.file.name), t.size(), templatesList.size());
  143 + while (templatesList.size() < t.size())
  144 + templatesList.append(TemplateList());
  145 + for (int i=0; i<t.size(); i++)
  146 + templatesList[i].append(Template(t.file, t[i]));
  147 + }
  148 +
  149 + while (transforms.size() < templatesList.size())
  150 + transforms.append(transform->clone());
  151 +
  152 + QFutureSynchronizer<void> futures;
  153 + for (int i=0; i<templatesList.size(); i++)
  154 + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i]));
  155 + futures.waitForFinished();
  156 + }
  157 +
  158 + void project(const Template &src, Template &dst) const
  159 + {
  160 + dst.file = src.file;
  161 + QList<Mat> mats;
  162 + for (int i=0; i<src.size(); i++) {
  163 + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst);
  164 + mats.append(dst);
  165 + dst.clear();
  166 + }
  167 + dst.append(mats);
  168 + }
  169 +
  170 + void projectUpdate(const Template &src, Template &dst)
  171 + {
  172 + dst.file = src.file;
  173 + QList<Mat> mats;
  174 + for (int i=0; i<src.size(); i++) {
  175 + transforms[i%transforms.size()]->projectUpdate(Template(src.file, src[i]), dst);
  176 + mats.append(dst);
  177 + dst.clear();
  178 + }
  179 + dst.append(mats);
  180 + }
  181 +
  182 + void finalize(TemplateList &out)
  183 + {
  184 + if (transforms.empty())
  185 + return;
  186 +
  187 + transforms[0]->finalize(out);
  188 + for (int i=1; i < transforms.size(); i++) {
  189 + TemplateList temp;
  190 + transforms[i]->finalize(temp);
  191 +
  192 + for (int j=0; j < out.size(); j++)
  193 + out[j].append(temp[j]);
  194 + }
  195 + }
  196 +
  197 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  198 + {
  199 + dst.reserve(src.size());
  200 + foreach (const Template &t, src) {
  201 + dst.append(Template());
  202 + projectUpdate(t, dst.last());
  203 + }
  204 + }
  205 +
  206 + void store(QDataStream &stream) const
  207 + {
  208 + const int size = transforms.size();
  209 + stream << size;
  210 + for (int i=0; i<size; i++)
  211 + transforms[i]->store(stream);
  212 + }
  213 +
  214 + void load(QDataStream &stream)
  215 + {
  216 + int size;
  217 + stream >> size;
  218 + while (transforms.size() < size)
  219 + transforms.append(transform->clone());
  220 + for (int i=0; i<size; i++)
  221 + transforms[i]->load(stream);
  222 + }
  223 +};
  224 +
  225 +BR_REGISTER(Transform, IndependentTransform)
  226 +
  227 +} // namespace br
  228 +
  229 +#include "core/independent.moc"
... ...
openbr/plugins/jni.cpp renamed to openbr/plugins/core/jni.cpp
1 1 //Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables
2 2  
3 3 #include <limits>
4   -#include "openbr_internal.h"
5   -#include "openbr/core/resource.h"
  4 +#include <openbr/plugins/openbr_internal.h>
  5 +#include <openbr/core/resource.h>
6 6 #include <jni.h>
7 7  
8 8 namespace br
... ...
openbr/plugins/likely.cpp renamed to openbr/plugins/core/likely.cpp
1   -#include <likely.h>
2   -#include <likely/opencv.hpp>
3   -
4   -#include "openbr/core/opencvutils.h"
5   -#include "openbr_internal.h"
  1 +#include <openbr/plugins/openbr_internal.h>
6 2  
7 3 namespace br
8 4 {
... ... @@ -57,68 +53,6 @@ public:
57 53  
58 54 BR_REGISTER(Transform, LikelyTransform)
59 55  
60   -/*!
61   - * \ingroup formats
62   - * \brief Likely matrix format
63   - *
64   - * www.liblikely.org
65   - * \author Josh Klontz \cite jklontz
66   - */
67   -class lmatFormat : public Format
68   -{
69   - Q_OBJECT
70   -
71   - Template read() const
72   - {
73   - const likely_const_mat m = likely_read(qPrintable(file.name), likely_file_guess);
74   - const Template result(likelyToOpenCVMat(m));
75   - likely_release_mat(m);
76   - return result;
77   - }
78   -
79   - void write(const Template &t) const
80   - {
81   - const likely_const_mat m = likelyFromOpenCVMat(t);
82   - likely_write(m, qPrintable(file.name));
83   - likely_release_mat(m);
84   - }
85   -};
86   -
87   -BR_REGISTER(Format, lmatFormat)
88   -
89   -/*!
90   - * \ingroup formats
91   - * \brief Likely matrix format
92   - *
93   - * www.liblikely.org
94   - * \author Josh Klontz \cite jklontz
95   - */
96   -class lmatGallery : public Gallery
97   -{
98   - Q_OBJECT
99   - QList<cv::Mat> mats;
100   -
101   - ~lmatGallery()
102   - {
103   - const likely_const_mat m = likelyFromOpenCVMat(OpenCVUtils::toMatByRow(mats));
104   - likely_write(m, qPrintable(file.name));
105   - likely_release_mat(m);
106   - }
107   -
108   - TemplateList readBlock(bool *done)
109   - {
110   - *done = true;
111   - qFatal("Not supported.");
112   - }
113   -
114   - void write(const Template &t)
115   - {
116   - mats.append(t);
117   - }
118   -};
119   -
120   -BR_REGISTER(Gallery, lmatGallery)
121   -
122 56 } // namespace br
123 57  
124   -#include "likely.moc"
  58 +#include "core/likely.moc"
... ...
openbr/plugins/core/loadstore.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/qtutils.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup transforms
  25 + * \brief Caches transform training.
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class LoadStoreTransform : public MetaTransform
  29 +{
  30 + Q_OBJECT
  31 + Q_PROPERTY(QString transformString READ get_transformString WRITE set_transformString RESET reset_transformString STORED false)
  32 + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false)
  33 + BR_PROPERTY(QString, transformString, "Identity")
  34 + BR_PROPERTY(QString, fileName, QString())
  35 +
  36 +public:
  37 + Transform *transform;
  38 +
  39 + LoadStoreTransform() : transform(NULL) {}
  40 +
  41 + QString description(bool expanded = false) const
  42 + {
  43 + if (expanded) {
  44 + QString res = transform->description(expanded);
  45 + return res;
  46 + }
  47 + return br::Object::description(expanded);
  48 + }
  49 +
  50 + Transform *simplify(bool &newTForm)
  51 + {
  52 + Transform *res = transform->simplify(newTForm);
  53 + return res;
  54 + }
  55 +
  56 + QList<Object *> getChildren() const
  57 + {
  58 + QList<Object *> rval;
  59 + rval.append(transform);
  60 + return rval;
  61 + }
  62 +private:
  63 +
  64 + void init()
  65 + {
  66 + if (transform != NULL) return;
  67 + if (fileName.isEmpty()) fileName = QRegExp("^[_a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString);
  68 +
  69 + if (!tryLoad())
  70 + transform = make(transformString);
  71 + else
  72 + trainable = false;
  73 + }
  74 +
  75 + bool timeVarying() const
  76 + {
  77 + return transform->timeVarying();
  78 + }
  79 +
  80 + void train(const QList<TemplateList> &data)
  81 + {
  82 + if (QFileInfo(getFileName()).exists())
  83 + return;
  84 +
  85 + transform->train(data);
  86 +
  87 + qDebug("Storing %s", qPrintable(fileName));
  88 + QtUtils::BlockCompression compressedOut;
  89 + QFile fout(fileName);
  90 + QtUtils::touchDir(fout);
  91 + compressedOut.setBasis(&fout);
  92 +
  93 + QDataStream stream(&compressedOut);
  94 + QString desc = transform->description();
  95 +
  96 + if (!compressedOut.open(QFile::WriteOnly))
  97 + qFatal("Failed to open %s for writing.", qPrintable(file));
  98 +
  99 + stream << desc;
  100 + transform->store(stream);
  101 + compressedOut.close();
  102 + }
  103 +
  104 + void project(const Template &src, Template &dst) const
  105 + {
  106 + transform->project(src, dst);
  107 + }
  108 +
  109 + void project(const TemplateList &src, TemplateList &dst) const
  110 + {
  111 + transform->project(src, dst);
  112 + }
  113 +
  114 + void projectUpdate(const Template &src, Template &dst)
  115 + {
  116 + transform->projectUpdate(src, dst);
  117 + }
  118 +
  119 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  120 + {
  121 + transform->projectUpdate(src, dst);
  122 + }
  123 +
  124 + void finalize(TemplateList &output)
  125 + {
  126 + transform->finalize(output);
  127 + }
  128 +
  129 + QString getFileName() const
  130 + {
  131 + if (QFileInfo(fileName).exists()) return fileName;
  132 +
  133 + foreach(const QString &path, Globals->modelSearch) {
  134 + const QString file = path + "/" + fileName;
  135 + if (QFileInfo(file).exists())
  136 + return file;
  137 + }
  138 + return QString();
  139 + }
  140 +
  141 + bool tryLoad()
  142 + {
  143 + const QString file = getFileName();
  144 + if (file.isEmpty()) return false;
  145 +
  146 + qDebug("Loading %s", qPrintable(file));
  147 + QFile fin(file);
  148 + QtUtils::BlockCompression reader(&fin);
  149 + if (!reader.open(QIODevice::ReadOnly)) {
  150 + if (QFileInfo(file).exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file));
  151 + else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file));
  152 + }
  153 +
  154 + QDataStream stream(&reader);
  155 + stream >> transformString;
  156 +
  157 + transform = Transform::make(transformString);
  158 + transform->load(stream);
  159 +
  160 + return true;
  161 + }
  162 +};
  163 +
  164 +BR_REGISTER(Transform, LoadStoreTransform)
  165 +
  166 +} // namespace br
  167 +
  168 +#include "core/loadstore.moc"
... ...
openbr/plugins/core/pipe.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup Transforms
  26 + * \brief Transforms in series.
  27 + * \author Josh Klontz \cite jklontz
  28 + *
  29 + * The source br::Template is given to the first transform and the resulting br::Template is passed to the next transform, etc.
  30 + *
  31 + * \see ExpandTransform
  32 + * \see ForkTransform
  33 + */
  34 +class PipeTransform : public CompositeTransform
  35 +{
  36 + Q_OBJECT
  37 +
  38 + void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex)
  39 + {
  40 + TemplateList ftes;
  41 + for (int i=startIndex; i<stopIndex; i++) {
  42 + TemplateList res;
  43 + transforms[i]->project(*srcdst, res);
  44 +
  45 + splitFTEs(res, ftes);
  46 + *srcdst = res;
  47 + }
  48 + }
  49 +
  50 + void train(const QList<TemplateList> &data)
  51 + {
  52 + if (!trainable) return;
  53 +
  54 + QList<TemplateList> dataLines(data);
  55 +
  56 + int i = 0;
  57 + while (i < transforms.size()) {
  58 + // Conditional statement covers likely case that first transform is untrainable
  59 + if (transforms[i]->trainable) {
  60 + qDebug() << "Training " << transforms[i]->description() << "\n...";
  61 + transforms[i]->train(dataLines);
  62 + }
  63 +
  64 + // if the transform is time varying, we can't project it in parallel
  65 + if (transforms[i]->timeVarying()) {
  66 + qDebug() << "Projecting " << transforms[i]->description() << "\n...";
  67 + for (int j=0; j < dataLines.size();j++) {
  68 + TemplateList junk;
  69 + splitFTEs(dataLines[j], junk);
  70 +
  71 + transforms[i]->projectUpdate(dataLines[j], dataLines[j]);
  72 + }
  73 +
  74 + // advance i since we already projected for this stage.
  75 + i++;
  76 +
  77 + // the next stage might be trainable, so continue to evaluate it.
  78 + continue;
  79 + }
  80 +
  81 + // We project through any subsequent untrainable transforms at once
  82 + // as a memory optimization in case any of these intermediate
  83 + // transforms allocate a lot of memory (like OpenTransform)
  84 + // then we don't want all the training templates to be processed
  85 + // by that transform at once if we can avoid it.
  86 + int nextTrainableTransform = i+1;
  87 + while ((nextTrainableTransform < transforms.size()) &&
  88 + !transforms[nextTrainableTransform]->trainable &&
  89 + !transforms[nextTrainableTransform]->timeVarying())
  90 + nextTrainableTransform++;
  91 +
  92 + // No more trainable transforms? Don't need any more projects then
  93 + if (nextTrainableTransform == transforms.size())
  94 + break;
  95 +
  96 + fprintf(stderr, "Projecting %s", qPrintable(transforms[i]->description()));
  97 + for (int j=i+1; j < nextTrainableTransform; j++)
  98 + fprintf(stderr,"+%s", qPrintable(transforms[j]->description()));
  99 + fprintf(stderr, "\n...\n");
  100 + fflush(stderr);
  101 +
  102 + QFutureSynchronizer<void> futures;
  103 + for (int j=0; j < dataLines.size(); j++)
  104 + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &dataLines[j], i, nextTrainableTransform));
  105 + futures.waitForFinished();
  106 +
  107 + i = nextTrainableTransform;
  108 + }
  109 + }
  110 +
  111 + void projectUpdate(const Template &src, Template &dst)
  112 + {
  113 + dst = src;
  114 + foreach (Transform *f, transforms) {
  115 + try {
  116 + f->projectUpdate(dst);
  117 + if (dst.file.fte)
  118 + break;
  119 + } catch (...) {
  120 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  121 + dst = Template(src.file);
  122 + dst.file.fte = true;
  123 + break;
  124 + }
  125 + }
  126 + }
  127 +
  128 + // For time varying transforms, parallel execution over individual templates
  129 + // won't work.
  130 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  131 + {
  132 + TemplateList ftes;
  133 + dst = src;
  134 + foreach (Transform *f, transforms) {
  135 + TemplateList res;
  136 + f->projectUpdate(dst, res);
  137 + splitFTEs(res, ftes);
  138 + dst = res;
  139 + }
  140 + dst.append(ftes);
  141 + }
  142 +
  143 + virtual void finalize(TemplateList &output)
  144 + {
  145 + output.clear();
  146 + // For each transform,
  147 + for (int i = 0; i < transforms.size(); i++)
  148 + {
  149 +
  150 + // Collect any final templates
  151 + TemplateList last_set;
  152 + transforms[i]->finalize(last_set);
  153 + if (last_set.empty())
  154 + continue;
  155 + // Push any templates received through the remaining transforms in the sequence
  156 + for (int j = (i+1); j < transforms.size();j++)
  157 + {
  158 + transforms[j]->projectUpdate(last_set);
  159 + }
  160 + // append the result to the output set
  161 + output.append(last_set);
  162 + }
  163 + }
  164 +
  165 + void init()
  166 + {
  167 + QList<Transform *> flattened;
  168 + for (int i=0;i < transforms.size(); i++)
  169 + {
  170 + PipeTransform *probe = dynamic_cast<PipeTransform *> (transforms[i]);
  171 + if (!probe) {
  172 + flattened.append(transforms[i]);
  173 + continue;
  174 + }
  175 + for (int j=0; j < probe->transforms.size(); j++)
  176 + flattened.append(probe->transforms[j]);
  177 + }
  178 + transforms = flattened;
  179 +
  180 + CompositeTransform::init();
  181 + }
  182 +
  183 +protected:
  184 + // Template list project -- process templates in parallel through Transform::project
  185 + // or if parallelism is disabled, handle them sequentially
  186 + void _project(const TemplateList &src, TemplateList &dst) const
  187 + {
  188 + TemplateList ftes;
  189 + dst = src;
  190 + foreach (const Transform *f, transforms) {
  191 + TemplateList res;
  192 + f->project(dst, res);
  193 + splitFTEs(res, ftes);
  194 + dst = res;
  195 + }
  196 + dst.append(ftes);
  197 + }
  198 +
  199 + // Single template const project, pass the template through each sub-transform, one after the other
  200 + virtual void _project(const Template &src, Template &dst) const
  201 + {
  202 + dst = src;
  203 + foreach (const Transform *f, transforms) {
  204 + try {
  205 + dst >> *f;
  206 + if (dst.file.fte)
  207 + break;
  208 + } catch (...) {
  209 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  210 + dst = Template(src.file);
  211 + dst.file.fte = true;
  212 + }
  213 + }
  214 + }
  215 +};
  216 +
  217 +BR_REGISTER(Transform, PipeTransform)
  218 +
  219 +} // namespace br
  220 +
  221 +#include "core/pipe.moc"
... ...
openbr/plugins/process.cpp renamed to openbr/plugins/core/processwrapper.cpp
1   -
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 16  
3 17 #include <QBuffer>
4 18 #include <QCoreApplication>
... ... @@ -9,8 +23,8 @@
9 23 #include <QUuid>
10 24 #include <QWaitCondition>
11 25  
12   -#include "openbr_internal.h"
13   -#include "openbr/core/opencvutils.h"
  26 +#include <openbr/plugins/openbr_internal.h>
  27 +#include <openbr/core/opencvutils.h>
14 28  
15 29 using namespace cv;
16 30  
... ... @@ -658,4 +672,4 @@ BR_REGISTER(Transform, ProcessWrapperTransform)
658 672  
659 673 }
660 674  
661   -#include "process.moc"
  675 +#include "core/processwrapper.moc"
... ...
openbr/plugins/core/progresscounter.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QElapsedTimer>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/qtutils.h>
  21 +
  22 +namespace br
  23 +{
  24 +
  25 +class ProgressCounterTransform : public TimeVaryingTransform
  26 +{
  27 + Q_OBJECT
  28 +
  29 + Q_PROPERTY(qint64 totalProgress READ get_totalProgress WRITE set_totalProgress RESET reset_totalProgress STORED false)
  30 + BR_PROPERTY(qint64, totalProgress, 1)
  31 +
  32 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  33 + {
  34 + dst = src;
  35 +
  36 + qint64 elapsed = timer.elapsed();
  37 + int last_frame = -2;
  38 + if (!dst.empty()) {
  39 + for (int i=0;i < dst.size();i++) {
  40 + int frame = dst[i].file.get<int>("FrameNumber", -1);
  41 + if (frame == last_frame && frame != -1)
  42 + continue;
  43 +
  44 + // Use 1 as the starting index for progress output
  45 + Globals->currentProgress = dst[i].file.get<qint64>("progress",0)+1;
  46 + dst[i].file.remove("progress");
  47 + last_frame = frame;
  48 +
  49 + Globals->currentStep++;
  50 + }
  51 + }
  52 +
  53 + // updated every second
  54 + if (elapsed > 1000) {
  55 + Globals->printStatus();
  56 + timer.start();
  57 + }
  58 +
  59 + return;
  60 + }
  61 +
  62 + void train(const TemplateList& data)
  63 + {
  64 + (void) data;
  65 + }
  66 +
  67 + void finalize(TemplateList &data)
  68 + {
  69 + (void) data;
  70 + float p = br_progress();
  71 + qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep);
  72 + timer.start();
  73 + Globals->startTime.start();
  74 + Globals->currentStep = 0;
  75 + Globals->currentProgress = 0;
  76 + Globals->totalSteps = totalProgress;
  77 + }
  78 +
  79 + void init()
  80 + {
  81 + timer.start();
  82 + Globals->startTime.start();
  83 + Globals->currentProgress = 0;
  84 + Globals->currentStep = 0;
  85 + Globals->totalSteps = totalProgress;
  86 + }
  87 +
  88 +public:
  89 + ProgressCounterTransform() : TimeVaryingTransform(false,false) {}
  90 + QElapsedTimer timer;
  91 +};
  92 +
  93 +BR_REGISTER(Transform, ProgressCounterTransform)
  94 +
  95 +} // namespace br
  96 +
  97 +#include "core/progresscounter.moc"
... ...
openbr/plugins/core/propagate.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Ensures that a template will be propogated.
  9 + * \author Scott Klum \cite sklum
  10 + */
  11 +class PropagateTransform : public UntrainableMetaTransform
  12 +{
  13 + Q_OBJECT
  14 +
  15 + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED true)
  16 + BR_PROPERTY(br::Transform *, transform, NULL)
  17 +
  18 + void project(const Template &src, Template &dst) const
  19 + {
  20 + transform->project(src,dst);
  21 + if (dst.isEmpty())
  22 + dst = src;
  23 + }
  24 +};
  25 +
  26 +BR_REGISTER(Transform, PropagateTransform)
  27 +
  28 +} // namespace br
  29 +
  30 +#include "core/propagate.moc"
... ...
openbr/plugins/core/registrar.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup initializers
  24 + * \brief Register custom objects with Qt meta object system.
  25 + * \author Charles Otto \cite caotto
  26 + */
  27 +class Registrar : public Initializer
  28 +{
  29 + Q_OBJECT
  30 +
  31 + void initialize() const
  32 + {
  33 + qRegisterMetaType<br::Neighbors>();
  34 + }
  35 +};
  36 +
  37 +BR_REGISTER(Initializer, Registrar)
  38 +
  39 +} // namespace br
  40 +
  41 +#include "core/registrar.moc"
... ...
openbr/plugins/core/remove.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Removes the matrix from the template at the specified index.
  25 + * \author Josh Klontz \cite jklontz
  26 + * \see IdentityTransform DiscardTransform FirstTransform RestTransform
  27 + */
  28 +//! [example_transform]
  29 +class RemoveTransform : public UntrainableMetaTransform
  30 +{
  31 + Q_OBJECT
  32 + Q_PROPERTY(int index READ get_index WRITE set_index RESET reset_index STORED false)
  33 + BR_PROPERTY(int, index, 0)
  34 +
  35 + void project(const Template &src, Template &dst) const
  36 + {
  37 + dst = src;
  38 + dst.removeAt(index);
  39 + }
  40 +};
  41 +
  42 +BR_REGISTER(Transform, RemoveTransform)
  43 +//! [example_transform]
  44 +
  45 +} // namespace br
  46 +
  47 +#include "core/remove.moc"
... ...
openbr/plugins/core/rest.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Removes the first matrix from the template.
  25 + * \see IdentityTransform DiscardTransform FirstTransform RemoveTransform
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class RestTransform : public UntrainableMetaTransform
  29 +{
  30 + Q_OBJECT
  31 +
  32 + void project(const Template &src, Template &dst) const
  33 + {
  34 + dst = src;
  35 + dst.removeFirst();
  36 + }
  37 +};
  38 +
  39 +BR_REGISTER(Transform, RestTransform)
  40 +
  41 +} // namespace br
  42 +
  43 +#include "core/rest.moc"
... ...
openbr/plugins/core/schrodinger.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief Generates two templates, one of which is passed through a transform and the other
  25 + * is not. No cats were harmed in the making of this transform.
  26 + * \author Scott Klum \cite sklum
  27 + */
  28 +class SchrodingerTransform : public MetaTransform
  29 +{
  30 + Q_OBJECT
  31 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  32 + BR_PROPERTY(br::Transform*, transform, NULL)
  33 +
  34 +public:
  35 + void train(const TemplateList &data)
  36 + {
  37 + transform->train(data);
  38 + }
  39 +
  40 + void project(const TemplateList &src, TemplateList &dst) const
  41 + {
  42 + foreach(const Template &t, src) {
  43 + dst.append(t);
  44 + Template u;
  45 + transform->project(t,u);
  46 + dst.append(u);
  47 + }
  48 + }
  49 +
  50 + void project(const Template &src, Template &dst) const {
  51 + TemplateList temp;
  52 + project(TemplateList() << src, temp);
  53 + if (!temp.isEmpty()) dst = temp.first();
  54 + }
  55 +
  56 +};
  57 +BR_REGISTER(Transform, SchrodingerTransform)
  58 +
  59 +} // namespace br
  60 +
  61 +#include "core/schrodinger.moc"
... ...
openbr/plugins/core/singleton.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup transforms
  24 + * \brief A globally shared transform.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class SingletonTransform : public MetaTransform
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
  31 + BR_PROPERTY(QString, description, "Identity")
  32 +
  33 + static QMutex mutex;
  34 + static QHash<QString,Transform*> transforms;
  35 + static QHash<QString,int> trainingReferenceCounts;
  36 + static QHash<QString,TemplateList> trainingData;
  37 +
  38 + Transform *transform;
  39 +
  40 + void init()
  41 + {
  42 + QMutexLocker locker(&mutex);
  43 + if (!transforms.contains(description)) {
  44 + transforms.insert(description, make(description));
  45 + trainingReferenceCounts.insert(description, 0);
  46 + }
  47 +
  48 + transform = transforms[description];
  49 + trainingReferenceCounts[description]++;
  50 + }
  51 +
  52 + void train(const TemplateList &data)
  53 + {
  54 + QMutexLocker locker(&mutex);
  55 + trainingData[description].append(data);
  56 + trainingReferenceCounts[description]--;
  57 + if (trainingReferenceCounts[description] > 0) return;
  58 + transform->train(trainingData[description]);
  59 + trainingData[description].clear();
  60 + }
  61 +
  62 + void project(const Template &src, Template &dst) const
  63 + {
  64 + transform->project(src, dst);
  65 + }
  66 +
  67 + void store(QDataStream &stream) const
  68 + {
  69 + if (transform->parent() == this)
  70 + transform->store(stream);
  71 + }
  72 +
  73 + void load(QDataStream &stream)
  74 + {
  75 + if (transform->parent() == this)
  76 + transform->load(stream);
  77 + }
  78 +};
  79 +
  80 +QMutex SingletonTransform::mutex;
  81 +QHash<QString,Transform*> SingletonTransform::transforms;
  82 +QHash<QString,int> SingletonTransform::trainingReferenceCounts;
  83 +QHash<QString,TemplateList> SingletonTransform::trainingData;
  84 +
  85 +BR_REGISTER(Transform, SingletonTransform)
  86 +
  87 +} // namespace br
  88 +
  89 +#include "core/singleton.moc"
... ...
openbr/plugins/stream.cpp renamed to openbr/plugins/core/stream.cpp
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
1 17 #include <fstream>
2 18 #include <QReadWriteLock>
3 19 #include <QWaitCondition>
... ... @@ -8,10 +24,11 @@
8 24 #include <QtConcurrent>
9 25 #include <opencv/highgui.h>
10 26 #include <opencv2/highgui/highgui.hpp>
11   -#include "openbr_internal.h"
12   -#include "openbr/core/common.h"
13   -#include "openbr/core/opencvutils.h"
14   -#include "openbr/core/qtutils.h"
  27 +
  28 +#include <openbr/plugins/openbr_internal.h>
  29 +#include <openbr/core/common.h>
  30 +#include <openbr/core/opencvutils.h>
  31 +#include <openbr/core/qtutils.h>
15 32  
16 33 using namespace cv;
17 34 using namespace std;
... ... @@ -1360,5 +1377,5 @@ BR_REGISTER(Transform, StreamTransform)
1360 1377  
1361 1378 } // namespace br
1362 1379  
1363   -#include "stream.moc"
  1380 +#include "core/stream.moc"
1364 1381  
... ...
openbr/plugins/crop.cpp deleted
1   -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2   - * Copyright 2012 The MITRE Corporation *
3   - * *
4   - * Licensed under the Apache License, Version 2.0 (the "License"); *
5   - * you may not use this file except in compliance with the License. *
6   - * You may obtain a copy of the License at *
7   - * *
8   - * http://www.apache.org/licenses/LICENSE-2.0 *
9   - * *
10   - * Unless required by applicable law or agreed to in writing, software *
11   - * distributed under the License is distributed on an "AS IS" BASIS, *
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13   - * See the License for the specific language governing permissions and *
14   - * limitations under the License. *
15   - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16   -
17   -#include <opencv2/imgproc/imgproc.hpp>
18   -#include "openbr_internal.h"
19   -
20   -#include "openbr/core/opencvutils.h"
21   -
22   -using namespace cv;
23   -
24   -namespace br
25   -{
26   -
27   -/*!
28   - * \ingroup transforms
29   - * \brief Crops about the specified region of interest.
30   - * \author Josh Klontz \cite jklontz
31   - */
32   -class CropTransform : public UntrainableTransform
33   -{
34   - Q_OBJECT
35   - Q_PROPERTY(int x READ get_x WRITE set_x RESET reset_x STORED false)
36   - Q_PROPERTY(int y READ get_y WRITE set_y RESET reset_y STORED false)
37   - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false)
38   - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false)
39   - BR_PROPERTY(int, x, 0)
40   - BR_PROPERTY(int, y, 0)
41   - BR_PROPERTY(int, width, -1)
42   - BR_PROPERTY(int, height, -1)
43   -
44   - void project(const Template &src, Template &dst) const
45   - {
46   - dst = Mat(src, Rect(x, y, width < 1 ? src.m().cols-x-abs(width) : width, height < 1 ? src.m().rows-y-abs(height) : height));
47   - }
48   -};
49   -
50   -BR_REGISTER(Transform, CropTransform)
51   -
52   -/*!
53   - * \ingroup transforms
54   - * \brief Crops the rectangular regions of interest.
55   - * \author Josh Klontz \cite jklontz
56   - */
57   -class ROITransform : public UntrainableTransform
58   -{
59   - Q_OBJECT
60   - Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false)
61   - BR_PROPERTY(QString, propName, "")
62   -
63   - void project(const Template &src, Template &dst) const
64   - {
65   - if (!propName.isEmpty()) {
66   - QRectF rect = src.file.get<QRectF>(propName);
67   - dst += src.m()(OpenCVUtils::toRect(rect));
68   - } else if (!src.file.rects().empty()) {
69   - foreach (const QRectF &rect, src.file.rects())
70   - dst += src.m()(OpenCVUtils::toRect(rect));
71   - } else if (src.file.contains(QStringList() << "X" << "Y" << "Width" << "Height")) {
72   - dst += src.m()(Rect(src.file.get<int>("X"),
73   - src.file.get<int>("Y"),
74   - src.file.get<int>("Width"),
75   - src.file.get<int>("Height")));
76   - } else {
77   - dst = src;
78   - if (Globals->verbose)
79   - qWarning("No rects present in file.");
80   - }
81   - }
82   -};
83   -
84   -BR_REGISTER(Transform, ROITransform)
85   -
86   -/*!
87   - * \ingroup transforms
88   - * \brief Crops the rectangular regions of interest from given points and sizes.
89   - * \author Austin Blanton \cite imaus10
90   - */
91   -class ROIFromPtsTransform : public UntrainableTransform
92   -{
93   - Q_OBJECT
94   - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false)
95   - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false)
96   - BR_PROPERTY(int, width, 1)
97   - BR_PROPERTY(int, height, 1)
98   -
99   - void project(const Template &src, Template &dst) const
100   - {
101   - foreach (const QPointF &pt, src.file.points()) {
102   - int x = pt.x() - (width/2);
103   - int y = pt.y() - (height/2);
104   - dst += src.m()(Rect(x, y, width, height));
105   - }
106   - }
107   -};
108   -
109   -BR_REGISTER(Transform, ROIFromPtsTransform)
110   -
111   -/*!
112   - * \ingroup transforms
113   - * \brief Resize the template
114   - * \author Josh Klontz \cite jklontz
115   - * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement.
116   - * \param preserveAspect If true, the image will be sized per specification, but
117   - * a border will be applied to preserve aspect ratio.
118   - */
119   -class ResizeTransform : public UntrainableTransform
120   -{
121   - Q_OBJECT
122   - Q_ENUMS(Method)
123   -
124   -public:
125   - /*!< */
126   - enum Method { Near = INTER_NEAREST,
127   - Area = INTER_AREA,
128   - Bilin = INTER_LINEAR,
129   - Cubic = INTER_CUBIC,
130   - Lanczo = INTER_LANCZOS4};
131   -
132   -private:
133   - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false)
134   - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false)
135   - Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false)
136   - Q_PROPERTY(bool preserveAspect READ get_preserveAspect WRITE set_preserveAspect RESET reset_preserveAspect STORED false)
137   - BR_PROPERTY(int, rows, -1)
138   - BR_PROPERTY(int, columns, -1)
139   - BR_PROPERTY(Method, method, Bilin)
140   - BR_PROPERTY(bool, preserveAspect, false)
141   -
142   - void project(const Template &src, Template &dst) const
143   - {
144   - if (!preserveAspect)
145   - resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method);
146   - else {
147   - float inRatio = (float) src.m().rows / src.m().cols;
148   - float outRatio = (float) rows / columns;
149   - dst = Mat::zeros(rows, columns, src.m().type());
150   - if (outRatio > inRatio) {
151   - float heightAR = src.m().rows * inRatio / outRatio;
152   - Mat buffer;
153   - resize(src, buffer, Size(columns, heightAR), 0, 0, method);
154   - buffer.copyTo(dst.m()(Rect(0, (rows - heightAR) / 2, columns, heightAR)));
155   - } else {
156   - float widthAR = src.m().cols / inRatio * outRatio;
157   - Mat buffer;
158   - resize(src, buffer, Size(widthAR, rows), 0, 0, method);
159   - buffer.copyTo(dst.m()(Rect((columns - widthAR) / 2, 0, widthAR, rows)));
160   - }
161   - }
162   - }
163   -};
164   -
165   -BR_REGISTER(Transform, ResizeTransform)
166   -
167   -/*!
168   - * \ingroup transforms
169   - * \brief Limit the size of the template
170   - * \author Josh Klontz \cite jklontz
171   - */
172   -class LimitSizeTransform : public UntrainableTransform
173   -{
174   - Q_OBJECT
175   - Q_PROPERTY(int max READ get_max WRITE set_max RESET reset_max STORED false)
176   - BR_PROPERTY(int, max, -1)
177   -
178   - void project(const Template &src, Template &dst) const
179   - {
180   - const Mat &m = src;
181   - if (m.rows > m.cols)
182   - if (m.rows > max) resize(m, dst, Size(std::max(1, m.cols * max / m.rows), max));
183   - else dst = m;
184   - else
185   - if (m.cols > max) resize(m, dst, Size(max, std::max(1, m.rows * max / m.cols)));
186   - else dst = m;
187   - }
188   -};
189   -
190   -BR_REGISTER(Transform, LimitSizeTransform)
191   -
192   -/*!
193   - * \ingroup transforms
194   - * \brief Enforce a multiple of \em n columns.
195   - * \author Josh Klontz \cite jklontz
196   - */
197   -class DivTransform : public UntrainableTransform
198   -{
199   - Q_OBJECT
200   - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false)
201   - BR_PROPERTY(int, n, 1)
202   -
203   - void project(const Template &src, Template &dst) const
204   - {
205   - dst = Mat(src, Rect(0,0,n*(src.m().cols/n),src.m().rows));
206   - }
207   -};
208   -
209   -BR_REGISTER(Transform, DivTransform)
210   -
211   -/*!
212   - * \ingroup transforms
213   - * \brief Crop out black borders
214   - * \author Josh Klontz \cite jklontz
215   - */
216   -class CropBlackTransform : public UntrainableTransform
217   -{
218   - Q_OBJECT
219   -
220   - void project(const Template &src, Template &dst) const
221   - {
222   - Mat gray;
223   - OpenCVUtils::cvtGray(src, gray);
224   -
225   - int xStart = 0;
226   - while (xStart < gray.cols) {
227   - if (mean(gray.col(xStart))[0] >= 1) break;
228   - xStart++;
229   - }
230   -
231   - int xEnd = gray.cols - 1;
232   - while (xEnd >= 0) {
233   - if (mean(gray.col(xEnd))[0] >= 1) break;
234   - xEnd--;
235   - }
236   -
237   - int yStart = 0;
238   - while (yStart < gray.rows) {
239   - if (mean(gray.col(yStart))[0] >= 1) break;
240   - yStart++;
241   - }
242   -
243   - int yEnd = gray.rows - 1;
244   - while (yEnd >= 0) {
245   - if (mean(gray.col(yEnd))[0] >= 1) break;
246   - yEnd--;
247   - }
248   -
249   - dst = src.m()(Rect(xStart, yStart, xEnd-xStart, yEnd-yStart));
250   - }
251   -};
252   -
253   -BR_REGISTER(Transform, CropBlackTransform)
254   -
255   -/*!
256   - * \ingroup transforms
257   - * \brief Divide the matrix into 4 smaller matricies of equal size.
258   - * \author Josh Klontz \cite jklontz
259   - */
260   -class SubdivideTransform : public UntrainableTransform
261   -{
262   - Q_OBJECT
263   -
264   - void project(const Template &src, Template &dst) const
265   - {
266   - const Mat &m = src;
267   - const int subrows = m.rows/2;
268   - const int subcolumns = m.cols/2;
269   - dst.append(Mat(m,Rect(0, 0, subcolumns, subrows)).clone());
270   - dst.append(Mat(m,Rect(subcolumns, 0, subcolumns, subrows)).clone());
271   - dst.append(Mat(m,Rect(0, subrows, subcolumns, subrows)).clone());
272   - dst.append(Mat(m,Rect(subcolumns, subrows, subcolumns, subrows)).clone());
273   - }
274   -};
275   -
276   -BR_REGISTER(Transform, SubdivideTransform)
277   -
278   -/*!
279   - * \ingroup transforms
280   - * \brief Trim the image so the width and the height are the same size.
281   - * \author Josh Klontz \cite jklontz
282   - */
283   -class CropSquareTransform : public UntrainableTransform
284   -{
285   - Q_OBJECT
286   -
287   - void project(const Template &src, Template &dst) const
288   - {
289   - const Mat &m = src;
290   - const int newSize = min(m.rows, m.cols);
291   - dst = Mat(m, Rect((m.cols-newSize)/2, (m.rows-newSize)/2, newSize, newSize));
292   - }
293   -};
294   -
295   -BR_REGISTER(Transform, CropSquareTransform)
296   -
297   -} // namespace br
298   -
299   -#include "crop.moc"
openbr/plugins/cvt.cpp deleted
1   -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2   - * Copyright 2012 The MITRE Corporation *
3   - * *
4   - * Licensed under the Apache License, Version 2.0 (the "License"); *
5   - * you may not use this file except in compliance with the License. *
6   - * You may obtain a copy of the License at *
7   - * *
8   - * http://www.apache.org/licenses/LICENSE-2.0 *
9   - * *
10   - * Unless required by applicable law or agreed to in writing, software *
11   - * distributed under the License is distributed on an "AS IS" BASIS, *
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13   - * See the License for the specific language governing permissions and *
14   - * limitations under the License. *
15   - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16   -
17   -#include <opencv2/imgproc/imgproc_c.h>
18   -#include <opencv2/imgproc/imgproc.hpp>
19   -#include "openbr_internal.h"
20   -#include "openbr/core/opencvutils.h"
21   -
22   -using namespace cv;
23   -
24   -namespace br
25   -{
26   -
27   -/*!
28   - * \ingroup transforms
29   - * \brief Colorspace conversion.
30   - * \author Josh Klontz \cite jklontz
31   - */
32   -class CvtTransform : public UntrainableTransform
33   -{
34   - Q_OBJECT
35   - Q_ENUMS(ColorSpace)
36   - Q_PROPERTY(ColorSpace colorSpace READ get_colorSpace WRITE set_colorSpace RESET reset_colorSpace STORED false)
37   - Q_PROPERTY(int channel READ get_channel WRITE set_channel RESET reset_channel STORED false)
38   -
39   -public:
40   - enum ColorSpace { Gray = CV_BGR2GRAY,
41   - RGBGray = CV_RGB2GRAY,
42   - HLS = CV_BGR2HLS,
43   - HSV = CV_BGR2HSV,
44   - Lab = CV_BGR2Lab,
45   - Luv = CV_BGR2Luv,
46   - RGB = CV_BGR2RGB,
47   - XYZ = CV_BGR2XYZ,
48   - YCrCb = CV_BGR2YCrCb,
49   - Color = CV_GRAY2BGR };
50   -
51   -private:
52   - BR_PROPERTY(ColorSpace, colorSpace, Gray)
53   - BR_PROPERTY(int, channel, -1)
54   -
55   - void project(const Template &src, Template &dst) const
56   - {
57   - if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace);
58   - else dst = src;
59   -
60   - if (channel != -1) {
61   - std::vector<Mat> mv;
62   - split(dst, mv);
63   - dst = mv[channel % (int)mv.size()];
64   - }
65   - }
66   -};
67   -
68   -BR_REGISTER(Transform, CvtTransform)
69   -
70   -/*!
71   - * \ingroup transforms
72   - * \brief Convert to floating point format.
73   - * \author Josh Klontz \cite jklontz
74   - */
75   -class CvtFloatTransform : public UntrainableTransform
76   -{
77   - Q_OBJECT
78   -
79   - void project(const Template &src, Template &dst) const
80   - {
81   - src.m().convertTo(dst, CV_32F);
82   - }
83   -};
84   -
85   -BR_REGISTER(Transform, CvtFloatTransform)
86   -
87   -/*!
88   - * \ingroup transforms
89   - * \brief Convert to uchar format
90   - * \author Josh Klontz \cite jklontz
91   - */
92   -class CvtUCharTransform : public UntrainableTransform
93   -{
94   - Q_OBJECT
95   -
96   - void project(const Template &src, Template &dst) const
97   - {
98   - OpenCVUtils::cvtUChar(src, dst);
99   - }
100   -};
101   -
102   -BR_REGISTER(Transform, CvtUCharTransform)
103   -
104   -/*!
105   - * \ingroup transforms
106   - * \brief Scales using the given factor
107   - * \author Scott Klum \cite sklum
108   - */
109   -class ScaleTransform : public UntrainableTransform
110   -{
111   - Q_OBJECT
112   -
113   - Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
114   - BR_PROPERTY(float, scaleFactor, 1.)
115   -
116   - void project(const Template &src, Template &dst) const
117   - {
118   - resize(src, dst, Size(src.m().cols*scaleFactor,src.m().rows*scaleFactor));
119   -
120   - QList<QRectF> rects = src.file.rects();
121   - for (int i=0; i<rects.size(); i++)
122   - rects[i] = QRectF(rects[i].topLeft()*scaleFactor,rects[i].bottomRight()*scaleFactor);
123   - dst.file.setRects(rects);
124   -
125   - QList<QPointF> points = src.file.points();
126   - for (int i=0; i<points.size(); i++)
127   - points[i] = points[i] * scaleFactor;
128   - dst.file.setPoints(points);
129   -
130   - }
131   -};
132   -
133   -BR_REGISTER(Transform, ScaleTransform)
134   -
135   -/*!
136   - * \ingroup transforms
137   - * \brief Split a multi-channel matrix into several single-channel matrices.
138   - * \author Josh Klontz \cite jklontz
139   - */
140   -class SplitChannelsTransform : public UntrainableTransform
141   -{
142   - Q_OBJECT
143   -
144   - void project(const Template &src, Template &dst) const
145   - {
146   - std::vector<Mat> mv;
147   - split(src, mv);
148   - foreach (const Mat &m, mv)
149   - dst += m;
150   - }
151   -};
152   -
153   -BR_REGISTER(Transform, SplitChannelsTransform)
154   -
155   -/*!
156   - * \ingroup transforms
157   - * \brief Enforce the matrix has a certain number of channels by adding or removing channels.
158   - * \author Josh Klontz \cite jklontz
159   - */
160   -class EnsureChannelsTransform : public UntrainableTransform
161   -{
162   - Q_OBJECT
163   - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false)
164   - BR_PROPERTY(int, n, 1)
165   -
166   - void project(const Template &src, Template &dst) const
167   - {
168   - if (src.m().channels() == n) {
169   - dst = src;
170   - } else {
171   - std::vector<Mat> mv;
172   - split(src, mv);
173   -
174   - // Add extra channels
175   - while ((int)mv.size() < n) {
176   - for (int i=0; i<src.m().channels(); i++) {
177   - mv.push_back(mv[i]);
178   - if ((int)mv.size() == n)
179   - break;
180   - }
181   - }
182   -
183   - // Remove extra channels
184   - while ((int)mv.size() > n)
185   - mv.pop_back();
186   -
187   - merge(mv, dst);
188   - }
189   - }
190   -};
191   -
192   -BR_REGISTER(Transform, EnsureChannelsTransform)
193   -
194   -/*!
195   - * \ingroup transforms
196   - * \brief Drop the alpha channel (if exists).
197   - * \author Austin Blanton \cite imaus10
198   - */
199   -class DiscardAlphaTransform : public UntrainableTransform
200   -{
201   - Q_OBJECT
202   -
203   - void project(const Template &src, Template &dst) const
204   - {
205   - if (src.m().channels() > 4 || src.m().channels() == 2) {
206   - dst.file.fte = true;
207   - return;
208   - }
209   -
210   - dst = src;
211   - if (src.m().channels() == 4) {
212   - std::vector<Mat> mv;
213   - split(src, mv);
214   - mv.pop_back();
215   - merge(mv, dst);
216   - }
217   - }
218   -};
219   -
220   -BR_REGISTER(Transform, DiscardAlphaTransform)
221   -
222   -/*!
223   - * \ingroup transforms
224   - * \brief Normalized RG color space.
225   - * \author Josh Klontz \cite jklontz
226   - */
227   -class RGTransform : public UntrainableTransform
228   -{
229   - Q_OBJECT
230   -
231   - void project(const Template &src, Template &dst) const
232   - {
233   - if (src.m().type() != CV_8UC3)
234   - qFatal("Expected CV_8UC3 images.");
235   -
236   - const Mat &m = src.m();
237   - Mat R(m.size(), CV_8UC1); // R / (R+G+B)
238   - Mat G(m.size(), CV_8UC1); // G / (R+G+B)
239   -
240   - for (int i=0; i<m.rows; i++)
241   - for (int j=0; j<m.cols; j++) {
242   - Vec3b v = m.at<Vec3b>(i,j);
243   - const int b = v[0];
244   - const int g = v[1];
245   - const int r = v[2];
246   - const int sum = b + g + r;
247   - if (sum > 0) {
248   - R.at<uchar>(i, j) = saturate_cast<uchar>(255.0*r/(r+g+b));
249   - G.at<uchar>(i, j) = saturate_cast<uchar>(255.0*g/(r+g+b));
250   - } else {
251   - R.at<uchar>(i, j) = 0;
252   - G.at<uchar>(i, j) = 0;
253   - }
254   - }
255   -
256   - dst.append(R);
257   - dst.append(G);
258   - }
259   -};
260   -
261   -BR_REGISTER(Transform, RGTransform)
262   -
263   -/*!
264   - * \ingroup transforms
265   - * \brief dst = a*src+b
266   - * \author Josh Klontz \cite jklontz
267   - */
268   -class MAddTransform : public UntrainableTransform
269   -{
270   - Q_OBJECT
271   - Q_PROPERTY(double a READ get_a WRITE set_a RESET reset_a STORED false)
272   - Q_PROPERTY(double b READ get_b WRITE set_b RESET reset_b STORED false)
273   - BR_PROPERTY(double, a, 1)
274   - BR_PROPERTY(double, b, 0)
275   -
276   - void project(const Template &src, Template &dst) const
277   - {
278   - src.m().convertTo(dst.m(), src.m().depth(), a, b);
279   - }
280   -};
281   -
282   -BR_REGISTER(Transform, MAddTransform)
283   -
284   -/*!
285   - * \ingroup transforms
286   - * \brief Computes the absolute value of each element.
287   - * \author Josh Klontz \cite jklontz
288   - */
289   -class AbsTransform : public UntrainableTransform
290   -{
291   - Q_OBJECT
292   -
293   - void project(const Template &src, Template &dst) const
294   - {
295   - dst = abs(src);
296   - }
297   -};
298   -
299   -BR_REGISTER(Transform, AbsTransform)
300   -
301   -} // namespace br
302   -
303   -#include "cvt.moc"
openbr/plugins/distance.cpp deleted
1   -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2   - * Copyright 2012 The MITRE Corporation *
3   - * *
4   - * Licensed under the Apache License, Version 2.0 (the "License"); *
5   - * you may not use this file except in compliance with the License. *
6   - * You may obtain a copy of the License at *
7   - * *
8   - * http://www.apache.org/licenses/LICENSE-2.0 *
9   - * *
10   - * Unless required by applicable law or agreed to in writing, software *
11   - * distributed under the License is distributed on an "AS IS" BASIS, *
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13   - * See the License for the specific language governing permissions and *
14   - * limitations under the License. *
15   - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16   -
17   -#include <QFutureSynchronizer>
18   -#include <QtConcurrentRun>
19   -#include <numeric>
20   -#include <opencv2/imgproc/imgproc.hpp>
21   -#include <opencv2/imgproc/imgproc_c.h>
22   -#include "openbr_internal.h"
23   -
24   -#include "openbr/core/distance_sse.h"
25   -#include "openbr/core/qtutils.h"
26   -#include "openbr/core/opencvutils.h"
27   -
28   -using namespace cv;
29   -
30   -namespace br
31   -{
32   -
33   -/*!
34   - * \ingroup distances
35   - * \brief Standard distance metrics
36   - * \author Josh Klontz \cite jklontz
37   - */
38   -class DistDistance : public UntrainableDistance
39   -{
40   - Q_OBJECT
41   - Q_ENUMS(Metric)
42   - Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false)
43   - Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false)
44   -
45   -public:
46   - /*!< */
47   - enum Metric { Correlation,
48   - ChiSquared,
49   - Intersection,
50   - Bhattacharyya,
51   - INF,
52   - L1,
53   - L2,
54   - Cosine,
55   - Dot};
56   -
57   -private:
58   - BR_PROPERTY(Metric, metric, L2)
59   - BR_PROPERTY(bool, negLogPlusOne, true)
60   -
61   - float compare(const Mat &a, const Mat &b) const
62   - {
63   - if ((a.size != b.size) ||
64   - (a.type() != b.type()))
65   - return -std::numeric_limits<float>::max();
66   -
67   -// TODO: this max value is never returned based on the switch / default
68   - float result = std::numeric_limits<float>::max();
69   - switch (metric) {
70   - case Correlation:
71   - return compareHist(a, b, CV_COMP_CORREL);
72   - case ChiSquared:
73   - result = compareHist(a, b, CV_COMP_CHISQR);
74   - break;
75   - case Intersection:
76   - result = compareHist(a, b, CV_COMP_INTERSECT);
77   - break;
78   - case Bhattacharyya:
79   - result = compareHist(a, b, CV_COMP_BHATTACHARYYA);
80   - break;
81   - case INF:
82   - result = norm(a, b, NORM_INF);
83   - break;
84   - case L1:
85   - result = norm(a, b, NORM_L1);
86   - break;
87   - case L2:
88   - result = norm(a, b, NORM_L2);
89   - break;
90   - case Cosine:
91   - return cosine(a, b);
92   - case Dot:
93   - return a.dot(b);
94   - default:
95   - qFatal("Invalid metric");
96   - }
97   -
98   - if (result != result)
99   - qFatal("NaN result.");
100   -
101   - return negLogPlusOne ? -log(result+1) : result;
102   - }
103   -
104   - static float cosine(const Mat &a, const Mat &b)
105   - {
106   - float dot = 0;
107   - float magA = 0;
108   - float magB = 0;
109   -
110   - for (int row=0; row<a.rows; row++) {
111   - for (int col=0; col<a.cols; col++) {
112   - const float target = a.at<float>(row,col);
113   - const float query = b.at<float>(row,col);
114   - dot += target * query;
115   - magA += target * target;
116   - magB += query * query;
117   - }
118   - }
119   -
120   - return dot / (sqrt(magA)*sqrt(magB));
121   - }
122   -};
123   -
124   -BR_REGISTER(Distance, DistDistance)
125   -
126   -/*!
127   - * \ingroup distances
128   - * \brief DistDistance wrapper.
129   - * \author Josh Klontz \cite jklontz
130   - */
131   -class DefaultDistance : public UntrainableDistance
132   -{
133   - Q_OBJECT
134   - Distance *distance;
135   -
136   - void init()
137   - {
138   - distance = Distance::make("Dist("+file.suffix()+")");
139   - }
140   -
141   - float compare(const cv::Mat &a, const cv::Mat &b) const
142   - {
143   - return distance->compare(a, b);
144   - }
145   -};
146   -
147   -BR_REGISTER(Distance, DefaultDistance)
148   -
149   -/*!
150   - * \ingroup distances
151   - * \brief Distances in series.
152   - * \author Josh Klontz \cite jklontz
153   - *
154   - * The templates are compared using each br::Distance in order.
155   - * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early.
156   - * Otherwise the returned result is the value of comparing the templates using the last br::Distance.
157   - */
158   -class PipeDistance : public Distance
159   -{
160   - Q_OBJECT
161   - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances)
162   - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>())
163   -
164   - void train(const TemplateList &data)
165   - {
166   - QFutureSynchronizer<void> futures;
167   - foreach (br::Distance *distance, distances)
168   - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data));
169   - futures.waitForFinished();
170   - }
171   -
172   - float compare(const Template &a, const Template &b) const
173   - {
174   - float result = -std::numeric_limits<float>::max();
175   - foreach (br::Distance *distance, distances) {
176   - result = distance->compare(a, b);
177   - if (result == -std::numeric_limits<float>::max())
178   - return result;
179   - }
180   - return result;
181   - }
182   -};
183   -
184   -BR_REGISTER(Distance, PipeDistance)
185   -
186   -/*!
187   - * \ingroup distances
188   - * \brief Fuses similarity scores across multiple matrices of compared templates
189   - * \author Scott Klum \cite sklum
190   - * \note Operation: Mean, sum, min, max are supported.
191   - */
192   -class FuseDistance : public Distance
193   -{
194   - Q_OBJECT
195   - Q_ENUMS(Operation)
196   - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
197   - Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false)
198   - Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false)
199   -
200   - QList<br::Distance*> distances;
201   -
202   -public:
203   - /*!< */
204   - enum Operation {Mean, Sum, Max, Min};
205   -
206   -private:
207   - BR_PROPERTY(QString, description, "L2")
208   - BR_PROPERTY(Operation, operation, Mean)
209   - BR_PROPERTY(QList<float>, weights, QList<float>())
210   -
211   - void train(const TemplateList &src)
212   - {
213   - // Partition the templates by matrix
214   - QList<int> split;
215   - for (int i=0; i<src.at(0).size(); i++) split.append(1);
216   -
217   - QList<TemplateList> partitionedSrc = src.partition(split);
218   -
219   - while (distances.size() < partitionedSrc.size())
220   - distances.append(make(description));
221   -
222   - // Train on each of the partitions
223   - for (int i=0; i<distances.size(); i++)
224   - distances[i]->train(partitionedSrc[i]);
225   - }
226   -
227   - float compare(const Template &a, const Template &b) const
228   - {
229   - if (a.size() != b.size()) qFatal("Comparison size mismatch");
230   -
231   - QList<float> scores;
232   - for (int i=0; i<distances.size(); i++) {
233   - float weight;
234   - weights.isEmpty() ? weight = 1. : weight = weights[i];
235   - scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i])));
236   - }
237   -
238   - switch (operation) {
239   - case Mean:
240   - return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size();
241   - break;
242   - case Sum:
243   - return std::accumulate(scores.begin(),scores.end(),0.0);
244   - break;
245   - case Min:
246   - return *std::min_element(scores.begin(),scores.end());
247   - break;
248   - case Max:
249   - return *std::max_element(scores.begin(),scores.end());
250   - break;
251   - default:
252   - qFatal("Invalid operation.");
253   - }
254   - return 0;
255   - }
256   -
257   - void store(QDataStream &stream) const
258   - {
259   - stream << distances.size();
260   - foreach (Distance *distance, distances)
261   - distance->store(stream);
262   - }
263   -
264   - void load(QDataStream &stream)
265   - {
266   - int numDistances;
267   - stream >> numDistances;
268   - while (distances.size() < numDistances)
269   - distances.append(make(description));
270   - foreach (Distance *distance, distances)
271   - distance->load(stream);
272   - }
273   -};
274   -
275   -BR_REGISTER(Distance, FuseDistance)
276   -
277   -/*!
278   - * \ingroup distances
279   - * \brief Fast 8-bit L1 distance
280   - * \author Josh Klontz \cite jklontz
281   - */
282   -class ByteL1Distance : public UntrainableDistance
283   -{
284   - Q_OBJECT
285   -
286   - float compare(const unsigned char *a, const unsigned char *b, size_t size) const
287   - {
288   - return l1(a, b, size);
289   - }
290   -};
291   -
292   -BR_REGISTER(Distance, ByteL1Distance)
293   -
294   -/*!
295   - * \ingroup distances
296   - * \brief Fast 4-bit L1 distance
297   - * \author Josh Klontz \cite jklontz
298   - */
299   -class HalfByteL1Distance : public UntrainableDistance
300   -{
301   - Q_OBJECT
302   -
303   - float compare(const Mat &a, const Mat &b) const
304   - {
305   - return packed_l1(a.data, b.data, a.total());
306   - }
307   -};
308   -
309   -BR_REGISTER(Distance, HalfByteL1Distance)
310   -
311   -/*!
312   - * \ingroup distances
313   - * \brief Returns -log(distance(a,b)+1)
314   - * \author Josh Klontz \cite jklontz
315   - */
316   -class NegativeLogPlusOneDistance : public UntrainableDistance
317   -{
318   - Q_OBJECT
319   - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
320   - BR_PROPERTY(br::Distance*, distance, NULL)
321   -
322   - void train(const TemplateList &src)
323   - {
324   - distance->train(src);
325   - }
326   -
327   - float compare(const Template &a, const Template &b) const
328   - {
329   - return -log(distance->compare(a,b)+1);
330   - }
331   -
332   - void store(QDataStream &stream) const
333   - {
334   - distance->store(stream);
335   - }
336   -
337   - void load(QDataStream &stream)
338   - {
339   - distance->load(stream);
340   - }
341   -};
342   -
343   -BR_REGISTER(Distance, NegativeLogPlusOneDistance)
344   -
345   -/*!
346   - * \ingroup distances
347   - * \brief Returns \c true if the templates are identical, \c false otherwise.
348   - * \author Josh Klontz \cite jklontz
349   - */
350   -class IdenticalDistance : public UntrainableDistance
351   -{
352   - Q_OBJECT
353   -
354   - float compare(const Mat &a, const Mat &b) const
355   - {
356   - const size_t size = a.total() * a.elemSize();
357   - if (size != b.total() * b.elemSize()) return 0;
358   - for (size_t i=0; i<size; i++)
359   - if (a.data[i] != b.data[i]) return 0;
360   - return 1;
361   - }
362   -};
363   -
364   -BR_REGISTER(Distance, IdenticalDistance)
365   -
366   -/*!
367   - * \ingroup distances
368   - * \brief Online distance metric to attenuate match scores across multiple frames
369   - * \author Brendan klare \cite bklare
370   - */
371   -class OnlineDistance : public UntrainableDistance
372   -{
373   - Q_OBJECT
374   - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
375   - Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false)
376   - BR_PROPERTY(br::Distance*, distance, NULL)
377   - BR_PROPERTY(float, alpha, 0.1f)
378   -
379   - mutable QHash<QString,float> scoreHash;
380   - mutable QMutex mutex;
381   -
382   - float compare(const Template &target, const Template &query) const
383   - {
384   - float currentScore = distance->compare(target, query);
385   -
386   - QMutexLocker mutexLocker(&mutex);
387   - return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore;
388   - }
389   -};
390   -
391   -BR_REGISTER(Distance, OnlineDistance)
392   -
393   -/*!
394   - * \ingroup distances
395   - * \brief Attenuation function based distance from attributes
396   - * \author Scott Klum \cite sklum
397   - */
398   -class AttributeDistance : public UntrainableDistance
399   -{
400   - Q_OBJECT
401   - Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false)
402   - BR_PROPERTY(QString, attribute, QString())
403   -
404   - float compare(const Template &target, const Template &query) const
405   - {
406   - float queryValue = query.file.get<float>(attribute);
407   - float targetValue = target.file.get<float>(attribute);
408   -
409   - // TODO: Set this magic number to something meaningful
410   - float stddev = 1;
411   -
412   - if (queryValue == targetValue) return 1;
413   - else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2));
414   - }
415   -};
416   -
417   -BR_REGISTER(Distance, AttributeDistance)
418   -
419   -/*!
420   - * \ingroup distances
421   - * \brief Sum match scores across multiple distances
422   - * \author Scott Klum \cite sklum
423   - */
424   -class SumDistance : public UntrainableDistance
425   -{
426   - Q_OBJECT
427   - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances)
428   - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>())
429   -
430   - void train(const TemplateList &data)
431   - {
432   - QFutureSynchronizer<void> futures;
433   - foreach (br::Distance *distance, distances)
434   - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data));
435   - futures.waitForFinished();
436   - }
437   -
438   - float compare(const Template &target, const Template &query) const
439   - {
440   - float result = 0;
441   -
442   - foreach (br::Distance *distance, distances) {
443   - result += distance->compare(target, query);
444   -
445   - if (result == -std::numeric_limits<float>::max())
446   - return result;
447   - }
448   -
449   - return result;
450   - }
451   -};
452   -
453   -BR_REGISTER(Distance, SumDistance)
454   -
455   -/*!
456   - * \ingroup transforms
457   - * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance.
458   - * dst will contain a 1 by n vector of scores.
459   - * \author Charles Otto \cite caotto
460   - */
461   -class GalleryCompareTransform : public Transform
462   -{
463   - Q_OBJECT
464   - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true)
465   - Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
466   - BR_PROPERTY(br::Distance*, distance, NULL)
467   - BR_PROPERTY(QString, galleryName, "")
468   -
469   - TemplateList gallery;
470   -
471   - void project(const Template &src, Template &dst) const
472   - {
473   - dst = src;
474   - if (gallery.isEmpty())
475   - return;
476   -
477   - QList<float> line = distance->compare(gallery, src);
478   - dst.m() = OpenCVUtils::toMat(line, 1);
479   - }
480   -
481   - void init()
482   - {
483   - if (!galleryName.isEmpty())
484   - gallery = TemplateList::fromGallery(galleryName);
485   - }
486   -
487   - void train(const TemplateList &data)
488   - {
489   - gallery = data;
490   - }
491   -
492   - void store(QDataStream &stream) const
493   - {
494   - br::Object::store(stream);
495   - stream << gallery;
496   - }
497   -
498   - void load(QDataStream &stream)
499   - {
500   - br::Object::load(stream);
501   - stream >> gallery;
502   - }
503   -
504   -public:
505   - GalleryCompareTransform() : Transform(false, true) {}
506   -};
507   -
508   -BR_REGISTER(Transform, GalleryCompareTransform)
509   -
510   -
511   -} // namespace br
512   -#include "distance.moc"
openbr/plugins/distance/L1.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <Eigen/Dense>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief L1 distance computed using eigen.
  27 + * \author Josh Klontz \cite jklontz
  28 + */
  29 +class L1Distance : public UntrainableDistance
  30 +{
  31 + Q_OBJECT
  32 +
  33 + float compare(const cv::Mat &a, const cv::Mat &b) const
  34 + {
  35 + const int size = a.rows * a.cols;
  36 + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size);
  37 + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size);
  38 + return (aMap-bMap).cwiseAbs().sum();
  39 + }
  40 +};
  41 +
  42 +BR_REGISTER(Distance, L1Distance)
  43 +
  44 +} // namespace br
  45 +
  46 +#include "distance/L1.moc"
... ...
openbr/plugins/distance/L2.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <Eigen/Dense>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief L2 distance computed using eigen.
  27 + * \author Josh Klontz \cite jklontz
  28 + */
  29 +class L2Distance : public UntrainableDistance
  30 +{
  31 + Q_OBJECT
  32 +
  33 + float compare(const cv::Mat &a, const cv::Mat &b) const
  34 + {
  35 + const int size = a.rows * a.cols;
  36 + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size);
  37 + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size);
  38 + return (aMap-bMap).squaredNorm();
  39 + }
  40 +};
  41 +
  42 +BR_REGISTER(Distance, L2Distance)
  43 +
  44 +} // namespace br
  45 +
  46 +#include "distance/L2.moc"
... ...
openbr/plugins/distance/attribute.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Attenuation function based distance from attributes
  25 + * \author Scott Klum \cite sklum
  26 + */
  27 +class AttributeDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false)
  31 + BR_PROPERTY(QString, attribute, QString())
  32 +
  33 + float compare(const Template &target, const Template &query) const
  34 + {
  35 + float queryValue = query.file.get<float>(attribute);
  36 + float targetValue = target.file.get<float>(attribute);
  37 +
  38 + // TODO: Set this magic number to something meaningful
  39 + float stddev = 1;
  40 +
  41 + if (queryValue == targetValue) return 1;
  42 + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2));
  43 + }
  44 +};
  45 +
  46 +BR_REGISTER(Distance, AttributeDistance)
  47 +
  48 +} // namespace br
  49 +
  50 +#include "distance/attribute.moc"
... ...
openbr/plugins/distance/bayesianquantization.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/opencvutils.h>
  21 +
  22 +using namespace cv;
  23 +
  24 +namespace br
  25 +{
  26 +
  27 +/*!
  28 + * \ingroup distances
  29 + * \brief Bayesian quantization distance
  30 + * \author Josh Klontz \cite jklontz
  31 + */
  32 +class BayesianQuantizationDistance : public Distance
  33 +{
  34 + Q_OBJECT
  35 +
  36 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  37 + BR_PROPERTY(QString, inputVariable, "Label")
  38 +
  39 + QVector<float> loglikelihoods;
  40 +
  41 + static void computeLogLikelihood(const Mat &data, const QList<int> &labels, float *loglikelihood)
  42 + {
  43 + const QList<uchar> vals = OpenCVUtils::matrixToVector<uchar>(data);
  44 + if (vals.size() != labels.size())
  45 + qFatal("Logic error.");
  46 +
  47 + QVector<quint64> genuines(256, 0), impostors(256,0);
  48 + for (int i=0; i<vals.size(); i++)
  49 + for (int j=i+1; j<vals.size(); j++)
  50 + if (labels[i] == labels[j]) genuines[abs(vals[i]-vals[j])]++;
  51 + else impostors[abs(vals[i]-vals[j])]++;
  52 +
  53 + quint64 totalGenuines(0), totalImpostors(0);
  54 + for (int i=0; i<256; i++) {
  55 + totalGenuines += genuines[i];
  56 + totalImpostors += impostors[i];
  57 + }
  58 +
  59 + for (int i=0; i<256; i++)
  60 + loglikelihood[i] = log((float(genuines[i]+1)/totalGenuines)/(float(impostors[i]+1)/totalImpostors));
  61 + }
  62 +
  63 + void train(const TemplateList &src)
  64 + {
  65 + if ((src.first().size() > 1) || (src.first().m().type() != CV_8UC1))
  66 + qFatal("Expected sigle matrix templates of type CV_8UC1!");
  67 +
  68 + const Mat data = OpenCVUtils::toMat(src.data());
  69 + const QList<int> templateLabels = src.indexProperty(inputVariable);
  70 + loglikelihoods = QVector<float>(data.cols*256, 0);
  71 +
  72 + QFutureSynchronizer<void> futures;
  73 + for (int i=0; i<data.cols; i++)
  74 + futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256]));
  75 + futures.waitForFinished();
  76 + }
  77 +
  78 + float compare(const cv::Mat &a, const cv::Mat &b) const
  79 + {
  80 + const uchar *aData = a.data;
  81 + const uchar *bData = b.data;
  82 + const int size = a.rows * a.cols;
  83 + float likelihood = 0;
  84 + for (int i=0; i<size; i++)
  85 + likelihood += loglikelihoods[i*256+abs(aData[i]-bData[i])];
  86 + return likelihood;
  87 + }
  88 +
  89 + void store(QDataStream &stream) const
  90 + {
  91 + stream << loglikelihoods;
  92 + }
  93 +
  94 + void load(QDataStream &stream)
  95 + {
  96 + stream >> loglikelihoods;
  97 + }
  98 +};
  99 +
  100 +BR_REGISTER(Distance, BayesianQuantizationDistance)
  101 +
  102 +} // namespace br
  103 +
  104 +#include "distance/bayesianquantization.moc"
... ...
openbr/plugins/distance/byteL1.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/distance_sse.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup distances
  25 + * \brief Fast 8-bit L1 distance
  26 + * \author Josh Klontz \cite jklontz
  27 + */
  28 +class ByteL1Distance : public UntrainableDistance
  29 +{
  30 + Q_OBJECT
  31 +
  32 + float compare(const unsigned char *a, const unsigned char *b, size_t size) const
  33 + {
  34 + return l1(a, b, size);
  35 + }
  36 +};
  37 +
  38 +BR_REGISTER(Distance, ByteL1Distance)
  39 +
  40 +} // namespace br
  41 +
  42 +#include "distance/byteL1.moc"
... ...
openbr/plugins/distance/crossvalidate.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Cross validate a distance metric.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class CrossValidateDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 +
  31 + float compare(const Template &a, const Template &b) const
  32 + {
  33 + static const QString key("Partition"); // More efficient to preallocate this
  34 + const int partitionA = a.file.get<int>(key, 0);
  35 + const int partitionB = b.file.get<int>(key, 0);
  36 + return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0;
  37 + }
  38 +};
  39 +
  40 +BR_REGISTER(Distance, CrossValidateDistance)
  41 +
  42 +} // namespace br
  43 +
  44 +#include "distance/crossvalidate.moc"
... ...
openbr/plugins/distance/default.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief DistDistance wrapper.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class DefaultDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 + Distance *distance;
  31 +
  32 + void init()
  33 + {
  34 + distance = Distance::make("Dist("+file.suffix()+")");
  35 + }
  36 +
  37 + float compare(const cv::Mat &a, const cv::Mat &b) const
  38 + {
  39 + return distance->compare(a, b);
  40 + }
  41 +};
  42 +
  43 +BR_REGISTER(Distance, DefaultDistance)
  44 +
  45 +} // namespace br
  46 +
  47 +#include "distance/default.moc"
... ...
openbr/plugins/distance/dist.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <opencv2/imgproc/imgproc.hpp>
  18 +#include <openbr/plugins/openbr_internal.h>
  19 +
  20 +using namespace cv;
  21 +
  22 +namespace br
  23 +{
  24 +
  25 +/*!
  26 + * \ingroup distances
  27 + * \brief Standard distance metrics
  28 + * \author Josh Klontz \cite jklontz
  29 + */
  30 +class DistDistance : public UntrainableDistance
  31 +{
  32 + Q_OBJECT
  33 + Q_ENUMS(Metric)
  34 + Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false)
  35 + Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false)
  36 +
  37 +public:
  38 + /*!< */
  39 + enum Metric { Correlation,
  40 + ChiSquared,
  41 + Intersection,
  42 + Bhattacharyya,
  43 + INF,
  44 + L1,
  45 + L2,
  46 + Cosine,
  47 + Dot};
  48 +
  49 +private:
  50 + BR_PROPERTY(Metric, metric, L2)
  51 + BR_PROPERTY(bool, negLogPlusOne, true)
  52 +
  53 + float compare(const Mat &a, const Mat &b) const
  54 + {
  55 + if ((a.size != b.size) ||
  56 + (a.type() != b.type()))
  57 + return -std::numeric_limits<float>::max();
  58 +
  59 +// TODO: this max value is never returned based on the switch / default
  60 + float result = std::numeric_limits<float>::max();
  61 + switch (metric) {
  62 + case Correlation:
  63 + return compareHist(a, b, CV_COMP_CORREL);
  64 + case ChiSquared:
  65 + result = compareHist(a, b, CV_COMP_CHISQR);
  66 + break;
  67 + case Intersection:
  68 + result = compareHist(a, b, CV_COMP_INTERSECT);
  69 + break;
  70 + case Bhattacharyya:
  71 + result = compareHist(a, b, CV_COMP_BHATTACHARYYA);
  72 + break;
  73 + case INF:
  74 + result = norm(a, b, NORM_INF);
  75 + break;
  76 + case L1:
  77 + result = norm(a, b, NORM_L1);
  78 + break;
  79 + case L2:
  80 + result = norm(a, b, NORM_L2);
  81 + break;
  82 + case Cosine:
  83 + return cosine(a, b);
  84 + case Dot:
  85 + return a.dot(b);
  86 + default:
  87 + qFatal("Invalid metric");
  88 + }
  89 +
  90 + if (result != result)
  91 + qFatal("NaN result.");
  92 +
  93 + return negLogPlusOne ? -log(result+1) : result;
  94 + }
  95 +
  96 + static float cosine(const Mat &a, const Mat &b)
  97 + {
  98 + float dot = 0;
  99 + float magA = 0;
  100 + float magB = 0;
  101 +
  102 + for (int row=0; row<a.rows; row++) {
  103 + for (int col=0; col<a.cols; col++) {
  104 + const float target = a.at<float>(row,col);
  105 + const float query = b.at<float>(row,col);
  106 + dot += target * query;
  107 + magA += target * target;
  108 + magB += query * query;
  109 + }
  110 + }
  111 +
  112 + return dot / (sqrt(magA)*sqrt(magB));
  113 + }
  114 +};
  115 +
  116 +BR_REGISTER(Distance, DistDistance)
  117 +
  118 +} // namespace br
  119 +
  120 +#include "distance/dist.moc"
... ...
openbr/plugins/distance/filter.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Checks target metadata against filters.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class FilterDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 +
  31 + float compare(const Template &a, const Template &b) const
  32 + {
  33 + (void) b; // Query template isn't checked
  34 + foreach (const QString &key, Globals->filters.keys()) {
  35 + bool keep = false;
  36 + const QString metadata = a.file.get<QString>(key, "");
  37 + if (Globals->filters[key].isEmpty()) continue;
  38 + if (metadata.isEmpty()) return -std::numeric_limits<float>::max();
  39 + foreach (const QString &value, Globals->filters[key]) {
  40 + if (metadata == value) {
  41 + keep = true;
  42 + break;
  43 + }
  44 + }
  45 + if (!keep) return -std::numeric_limits<float>::max();
  46 + }
  47 + return 0;
  48 + }
  49 +};
  50 +
  51 +BR_REGISTER(Distance, FilterDistance)
  52 +
  53 +} // namespace br
  54 +
  55 +#include "distance/filter.moc"
... ...
openbr/plugins/distance/fuse.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <numeric>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief Fuses similarity scores across multiple matrices of compared templates
  27 + * \author Scott Klum \cite sklum
  28 + * \note Operation: Mean, sum, min, max are supported.
  29 + */
  30 +class FuseDistance : public Distance
  31 +{
  32 + Q_OBJECT
  33 + Q_ENUMS(Operation)
  34 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
  35 + Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false)
  36 + Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false)
  37 +
  38 + QList<br::Distance*> distances;
  39 +
  40 +public:
  41 + /*!< */
  42 + enum Operation {Mean, Sum, Max, Min};
  43 +
  44 +private:
  45 + BR_PROPERTY(QString, description, "L2")
  46 + BR_PROPERTY(Operation, operation, Mean)
  47 + BR_PROPERTY(QList<float>, weights, QList<float>())
  48 +
  49 + void train(const TemplateList &src)
  50 + {
  51 + // Partition the templates by matrix
  52 + QList<int> split;
  53 + for (int i=0; i<src.at(0).size(); i++) split.append(1);
  54 +
  55 + QList<TemplateList> partitionedSrc = src.partition(split);
  56 +
  57 + while (distances.size() < partitionedSrc.size())
  58 + distances.append(make(description));
  59 +
  60 + // Train on each of the partitions
  61 + for (int i=0; i<distances.size(); i++)
  62 + distances[i]->train(partitionedSrc[i]);
  63 + }
  64 +
  65 + float compare(const Template &a, const Template &b) const
  66 + {
  67 + if (a.size() != b.size()) qFatal("Comparison size mismatch");
  68 +
  69 + QList<float> scores;
  70 + for (int i=0; i<distances.size(); i++) {
  71 + float weight;
  72 + weights.isEmpty() ? weight = 1. : weight = weights[i];
  73 + scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i])));
  74 + }
  75 +
  76 + switch (operation) {
  77 + case Mean:
  78 + return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size();
  79 + break;
  80 + case Sum:
  81 + return std::accumulate(scores.begin(),scores.end(),0.0);
  82 + break;
  83 + case Min:
  84 + return *std::min_element(scores.begin(),scores.end());
  85 + break;
  86 + case Max:
  87 + return *std::max_element(scores.begin(),scores.end());
  88 + break;
  89 + default:
  90 + qFatal("Invalid operation.");
  91 + }
  92 + return 0;
  93 + }
  94 +
  95 + void store(QDataStream &stream) const
  96 + {
  97 + stream << distances.size();
  98 + foreach (Distance *distance, distances)
  99 + distance->store(stream);
  100 + }
  101 +
  102 + void load(QDataStream &stream)
  103 + {
  104 + int numDistances;
  105 + stream >> numDistances;
  106 + while (distances.size() < numDistances)
  107 + distances.append(make(description));
  108 + foreach (Distance *distance, distances)
  109 + distance->load(stream);
  110 + }
  111 +};
  112 +
  113 +BR_REGISTER(Distance, FuseDistance)
  114 +
  115 +} // namespace br
  116 +
  117 +#include "distance/fuse.moc"
... ...
openbr/plugins/distance/halfbyteL1.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/distance_sse.h>
  19 +
  20 +using namespace cv;
  21 +
  22 +namespace br
  23 +{
  24 +
  25 +/*!
  26 + * \ingroup distances
  27 + * \brief Fast 4-bit L1 distance
  28 + * \author Josh Klontz \cite jklontz
  29 + */
  30 +class HalfByteL1Distance : public UntrainableDistance
  31 +{
  32 + Q_OBJECT
  33 +
  34 + float compare(const Mat &a, const Mat &b) const
  35 + {
  36 + return packed_l1(a.data, b.data, a.total());
  37 + }
  38 +};
  39 +
  40 +BR_REGISTER(Distance, HalfByteL1Distance)
  41 +
  42 +
  43 +} // namespace br
  44 +
  45 +#include "distance/halfbyteL1.moc"
... ...
openbr/plugins/distance/heatmap.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief 1v1 heat map comparison
  25 + * \author Scott Klum \cite sklum
  26 + */
  27 +class HeatMapDistance : public Distance
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
  31 + Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false)
  32 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  33 + BR_PROPERTY(QString, description, "IdenticalDistance")
  34 + BR_PROPERTY(int, step, 1)
  35 + BR_PROPERTY(QString, inputVariable, "Label")
  36 +
  37 + QList<br::Distance*> distances;
  38 +
  39 + void train(const TemplateList &src)
  40 + {
  41 + QList<TemplateList> patches;
  42 +
  43 + // Split src into list of TemplateLists of corresponding patches across all Templates
  44 + for (int i=0; i<step; i++) {
  45 + TemplateList patchBuffer;
  46 + for (int j=0; j<src.size(); j++)
  47 + patchBuffer.append(Template(src[j].file, src[j][i]));
  48 + patches.append(patchBuffer);
  49 + patchBuffer.clear();
  50 + }
  51 +
  52 + while (distances.size() < patches.size())
  53 + distances.append(make(description));
  54 +
  55 + // Train on a distance for each patch
  56 + for (int i=0; i<distances.size(); i++)
  57 + distances[i]->train(patches[i]);
  58 + }
  59 +
  60 + float compare(const cv::Mat &target, const cv::Mat &query) const
  61 + {
  62 + (void) target;
  63 + (void) query;
  64 + qFatal("Heatmap Distance not compatible with Template to Template comparison.");
  65 +
  66 + return 0;
  67 + }
  68 +
  69 + void compare(const TemplateList &target, const TemplateList &query, Output *output) const
  70 + {
  71 + for (int i=0; i<target.size(); i++) {
  72 + if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches.");
  73 + for (int j=0; j<step; j++)
  74 + output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0);
  75 + }
  76 + }
  77 +
  78 + void store(QDataStream &stream) const
  79 + {
  80 + stream << distances.size();
  81 + foreach (Distance *distance, distances)
  82 + distance->store(stream);
  83 + }
  84 +
  85 + void load(QDataStream &stream)
  86 + {
  87 + int numDistances;
  88 + stream >> numDistances;
  89 + while (distances.size() < numDistances)
  90 + distances.append(make(description));
  91 + foreach (Distance *distance, distances)
  92 + distance->load(stream);
  93 + }
  94 +};
  95 +
  96 +BR_REGISTER(Distance, HeatMapDistance)
  97 +
  98 +} // namespace br
  99 +
  100 +#include "distance/heatmap.moc"
... ...
openbr/plugins/distance/identical.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +using namespace cv;
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief Returns \c true if the templates are identical, \c false otherwise.
  27 + * \author Josh Klontz \cite jklontz
  28 + */
  29 +class IdenticalDistance : public UntrainableDistance
  30 +{
  31 + Q_OBJECT
  32 +
  33 + float compare(const Mat &a, const Mat &b) const
  34 + {
  35 + const size_t size = a.total() * a.elemSize();
  36 + if (size != b.total() * b.elemSize()) return 0;
  37 + for (size_t i=0; i<size; i++)
  38 + if (a.data[i] != b.data[i]) return 0;
  39 + return 1;
  40 + }
  41 +};
  42 +
  43 +BR_REGISTER(Distance, IdenticalDistance)
  44 +
  45 +} // namespace br
  46 +
  47 +#include "distance/identical.moc"
... ...
openbr/plugins/distance/keypointmatcher.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <opencv2/features2d/features2d.hpp>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +using namespace cv;
  22 +
  23 +namespace br
  24 +{
  25 +
  26 +/*!
  27 + * \ingroup transforms
  28 + * \brief Wraps OpenCV Key Point Matcher
  29 + * \author Josh Klontz \cite jklontz
  30 + */
  31 +class KeyPointMatcherDistance : public UntrainableDistance
  32 +{
  33 + Q_OBJECT
  34 + Q_PROPERTY(QString matcher READ get_matcher WRITE set_matcher RESET reset_matcher STORED false)
  35 + Q_PROPERTY(float maxRatio READ get_maxRatio WRITE set_maxRatio RESET reset_maxRatio STORED false)
  36 + BR_PROPERTY(QString, matcher, "BruteForce")
  37 + BR_PROPERTY(float, maxRatio, 0.8)
  38 +
  39 + Ptr<DescriptorMatcher> descriptorMatcher;
  40 +
  41 + void init()
  42 + {
  43 + descriptorMatcher = DescriptorMatcher::create(matcher.toStdString());
  44 + if (descriptorMatcher.empty())
  45 + qFatal("Failed to create DescriptorMatcher: %s", qPrintable(matcher));
  46 + }
  47 +
  48 + float compare(const Mat &a, const Mat &b) const
  49 + {
  50 + if ((a.rows < 2) || (b.rows < 2)) return 0;
  51 +
  52 + std::vector< std::vector<DMatch> > matches;
  53 + if (a.rows < b.rows) descriptorMatcher->knnMatch(a, b, matches, 2);
  54 + else descriptorMatcher->knnMatch(b, a, matches, 2);
  55 +
  56 + QList<float> distances;
  57 + foreach (const std::vector<DMatch> &match, matches) {
  58 + if (match[0].distance / match[1].distance > maxRatio) continue;
  59 + distances.append(match[0].distance);
  60 + }
  61 + qSort(distances);
  62 +
  63 + float similarity = 0;
  64 + for (int i=0; i<distances.size(); i++)
  65 + similarity += 1.f/(1+distances[i])/(i+1);
  66 + return similarity;
  67 + }
  68 +};
  69 +
  70 +BR_REGISTER(Distance, KeyPointMatcherDistance)
  71 +
  72 +} // namespace br
  73 +
  74 +#include "distance/keypointmatcher.moc"
... ...
openbr/plugins/distance/matchprobability.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +#include <openbr/core/common.h>
  21 +
  22 +namespace br
  23 +{
  24 +
  25 +float KDEPointer(const QList<float> *scores, double x, double h)
  26 +{
  27 + return Common::KernelDensityEstimation(*scores, x, h);
  28 +}
  29 +
  30 +/* Kernel Density Estimator */
  31 +struct KDE
  32 +{
  33 + float min, max;
  34 + double mean, stddev;
  35 + QList<float> bins;
  36 +
  37 + KDE() : min(0), max(1), mean(0), stddev(1) {}
  38 +
  39 + KDE(const QList<float> &scores, bool trainKDE)
  40 + {
  41 + Common::MinMax(scores, &min, &max);
  42 + Common::MeanStdDev(scores, &mean, &stddev);
  43 +
  44 + if (!trainKDE)
  45 + return;
  46 +
  47 + double h = Common::KernelDensityBandwidth(scores);
  48 + const int size = 255;
  49 + bins.reserve(size);
  50 +
  51 + QFutureSynchronizer<float> futures;
  52 +
  53 + for (int i=0; i < size; i++)
  54 + futures.addFuture(QtConcurrent::run(KDEPointer, &scores, min + (max-min)*i/(size-1), h));
  55 + futures.waitForFinished();
  56 +
  57 + foreach(const QFuture<float> & future, futures.futures())
  58 + bins.append(future.result());
  59 + }
  60 +
  61 + float operator()(float score, bool gaussian = true) const
  62 + {
  63 + if (gaussian) return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((score-mean)/stddev, 2));
  64 + if (bins.empty())
  65 + return -std::numeric_limits<float>::max();
  66 +
  67 + if (score <= min) return bins.first();
  68 + if (score >= max) return bins.last();
  69 + const float x = (score-min)/(max-min)*bins.size();
  70 + const float y1 = bins[floor(x)];
  71 + const float y2 = bins[ceil(x)];
  72 + return y1 + (y2-y1)*(x-floor(x));
  73 + }
  74 +};
  75 +
  76 +QDataStream &operator<<(QDataStream &stream, const KDE &kde)
  77 +{
  78 + return stream << kde.min << kde.max << kde.mean << kde.stddev << kde.bins;
  79 +}
  80 +
  81 +QDataStream &operator>>(QDataStream &stream, KDE &kde)
  82 +{
  83 + return stream >> kde.min >> kde.max >> kde.mean >> kde.stddev >> kde.bins;
  84 +}
  85 +
  86 +/* Match Probability */
  87 +struct MP
  88 +{
  89 + KDE genuine, impostor;
  90 + MP() {}
  91 + MP(const QList<float> &genuineScores, const QList<float> &impostorScores, bool trainKDE)
  92 + : genuine(genuineScores, trainKDE), impostor(impostorScores, trainKDE) {}
  93 + float operator()(float score, bool gaussian = true) const
  94 + {
  95 + const float g = genuine(score, gaussian);
  96 + const float s = g / (impostor(score, gaussian) + g);
  97 + return s;
  98 + }
  99 +};
  100 +
  101 +QDataStream &operator<<(QDataStream &stream, const MP &nmp)
  102 +{
  103 + return stream << nmp.genuine << nmp.impostor;
  104 +}
  105 +
  106 +QDataStream &operator>>(QDataStream &stream, MP &nmp)
  107 +{
  108 + return stream >> nmp.genuine >> nmp.impostor;
  109 +}
  110 +
  111 +/*!
  112 + * \ingroup distances
  113 + * \brief Match Probability \cite klare12
  114 + * \author Josh Klontz \cite jklontz
  115 + */
  116 +class MatchProbabilityDistance : public Distance
  117 +{
  118 + Q_OBJECT
  119 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  120 + Q_PROPERTY(bool gaussian READ get_gaussian WRITE set_gaussian RESET reset_gaussian STORED false)
  121 + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false)
  122 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  123 +
  124 + MP mp;
  125 +
  126 + void train(const TemplateList &src)
  127 + {
  128 + distance->train(src);
  129 +
  130 + const QList<int> labels = src.indexProperty(inputVariable);
  131 + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size())));
  132 + distance->compare(src, src, matrixOutput.data());
  133 +
  134 + QList<float> genuineScores, impostorScores;
  135 + genuineScores.reserve(labels.size());
  136 + impostorScores.reserve(labels.size()*labels.size());
  137 + for (int i=0; i<src.size(); i++) {
  138 + for (int j=0; j<i; j++) {
  139 + const float score = matrixOutput.data()->data.at<float>(i, j);
  140 + if (score == -std::numeric_limits<float>::max()) continue;
  141 + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue;
  142 + if (labels[i] == labels[j]) genuineScores.append(score);
  143 + else impostorScores.append(score);
  144 + }
  145 + }
  146 +
  147 + mp = MP(genuineScores, impostorScores, !gaussian);
  148 + }
  149 +
  150 + float compare(const Template &target, const Template &query) const
  151 + {
  152 + return normalize(distance->compare(target, query));
  153 + }
  154 +
  155 + float compare(const cv::Mat &target, const cv::Mat &query) const
  156 + {
  157 + return normalize(distance->compare(target, query));
  158 + }
  159 +
  160 + float compare(const uchar *a, const uchar *b, size_t size) const
  161 + {
  162 + return normalize(distance->compare(a, b, size));
  163 + }
  164 +
  165 + float normalize(float score) const
  166 + {
  167 + if (score == -std::numeric_limits<float>::max()) return score;
  168 + if (!Globals->scoreNormalization) return -log(score+1);
  169 + return mp(score, gaussian);
  170 + }
  171 +
  172 + void store(QDataStream &stream) const
  173 + {
  174 + distance->store(stream);
  175 + stream << mp;
  176 + }
  177 +
  178 + void load(QDataStream &stream)
  179 + {
  180 + distance->load(stream);
  181 + stream >> mp;
  182 + }
  183 +
  184 +protected:
  185 + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  186 + BR_PROPERTY(bool, gaussian, true)
  187 + BR_PROPERTY(bool, crossModality, false)
  188 + BR_PROPERTY(QString, inputVariable, "Label")
  189 +};
  190 +
  191 +BR_REGISTER(Distance, MatchProbabilityDistance)
  192 +
  193 +} // namespace br
  194 +
  195 +#include "distance/matchprobability.moc"
... ...
openbr/plugins/distance/metadata.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/qtutils.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup distances
  25 + * \brief Checks target metadata against query metadata.
  26 + * \author Scott Klum \cite sklum
  27 + */
  28 +class MetadataDistance : public UntrainableDistance
  29 +{
  30 + Q_OBJECT
  31 +
  32 + Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false)
  33 + BR_PROPERTY(QStringList, filters, QStringList())
  34 +
  35 + float compare(const Template &a, const Template &b) const
  36 + {
  37 + foreach (const QString &key, filters) {
  38 + QString aValue = a.file.get<QString>(key, QString());
  39 + QString bValue = b.file.get<QString>(key, QString());
  40 +
  41 + // The query value may be a range. Let's check.
  42 + if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF()));
  43 +
  44 + if (aValue.isEmpty() || bValue.isEmpty()) continue;
  45 +
  46 + bool keep = false;
  47 + bool ok;
  48 +
  49 + QPointF range = QtUtils::toPoint(bValue,&ok);
  50 +
  51 + if (ok) /* Range */ {
  52 + int value = range.x();
  53 + int upperBound = range.y();
  54 +
  55 + while (value <= upperBound) {
  56 + if (aValue == QString::number(value)) {
  57 + keep = true;
  58 + break;
  59 + }
  60 + value++;
  61 + }
  62 + }
  63 + else if (aValue == bValue) keep = true;
  64 +
  65 + if (!keep) return -std::numeric_limits<float>::max();
  66 + }
  67 + return 0;
  68 + }
  69 +};
  70 +
  71 +
  72 +BR_REGISTER(Distance, MetadataDistance)
  73 +
  74 +} // namespace br
  75 +
  76 +#include "distance/metadata.moc"
... ...
openbr/plugins/distance/neglogplusone.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Returns -log(distance(a,b)+1)
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class NegativeLogPlusOneDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  31 + BR_PROPERTY(br::Distance*, distance, NULL)
  32 +
  33 + void train(const TemplateList &src)
  34 + {
  35 + distance->train(src);
  36 + }
  37 +
  38 + float compare(const Template &a, const Template &b) const
  39 + {
  40 + return -log(distance->compare(a,b)+1);
  41 + }
  42 +
  43 + void store(QDataStream &stream) const
  44 + {
  45 + distance->store(stream);
  46 + }
  47 +
  48 + void load(QDataStream &stream)
  49 + {
  50 + distance->load(stream);
  51 + }
  52 +};
  53 +
  54 +BR_REGISTER(Distance, NegativeLogPlusOneDistance)
  55 +
  56 +} // namespace br
  57 +
  58 +#include "distance/neglogplusone.moc"
... ...
openbr/plugins/distance/online.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Online distance metric to attenuate match scores across multiple frames
  25 + * \author Brendan klare \cite bklare
  26 + */
  27 +class OnlineDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  31 + Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false)
  32 + BR_PROPERTY(br::Distance*, distance, NULL)
  33 + BR_PROPERTY(float, alpha, 0.1f)
  34 +
  35 + mutable QHash<QString,float> scoreHash;
  36 + mutable QMutex mutex;
  37 +
  38 + float compare(const Template &target, const Template &query) const
  39 + {
  40 + float currentScore = distance->compare(target, query);
  41 +
  42 + QMutexLocker mutexLocker(&mutex);
  43 + return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore;
  44 + }
  45 +};
  46 +
  47 +BR_REGISTER(Distance, OnlineDistance)
  48 +
  49 +} // namespace br
  50 +
  51 +#include "distance/online.moc"
... ...
openbr/plugins/distance/pipe.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief Distances in series.
  27 + * \author Josh Klontz \cite jklontz
  28 + *
  29 + * The templates are compared using each br::Distance in order.
  30 + * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early.
  31 + * Otherwise the returned result is the value of comparing the templates using the last br::Distance.
  32 + */
  33 +class PipeDistance : public Distance
  34 +{
  35 + Q_OBJECT
  36 + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances)
  37 + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>())
  38 +
  39 + void train(const TemplateList &data)
  40 + {
  41 + QFutureSynchronizer<void> futures;
  42 + foreach (br::Distance *distance, distances)
  43 + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data));
  44 + futures.waitForFinished();
  45 + }
  46 +
  47 + float compare(const Template &a, const Template &b) const
  48 + {
  49 + float result = -std::numeric_limits<float>::max();
  50 + foreach (br::Distance *distance, distances) {
  51 + result = distance->compare(a, b);
  52 + if (result == -std::numeric_limits<float>::max())
  53 + return result;
  54 + }
  55 + return result;
  56 + }
  57 +};
  58 +
  59 +BR_REGISTER(Distance, PipeDistance)
  60 +
  61 +} // namespace br
  62 +
  63 +#include "distance/pipe.moc"
... ...
openbr/plugins/distance/reject.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key.
  25 + * \author Scott Klum \cite sklum
  26 + */
  27 +class RejectDistance : public UntrainableDistance
  28 +{
  29 + Q_OBJECT
  30 +
  31 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  32 + BR_PROPERTY(QStringList, keys, QStringList())
  33 + Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false)
  34 + BR_PROPERTY(bool, rejectIfContains, false)
  35 +
  36 + float compare(const Template &a, const Template &b) const
  37 + {
  38 + // We don't look at the query
  39 + (void) b;
  40 +
  41 + foreach (const QString &key, keys)
  42 + if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
  43 + return -std::numeric_limits<float>::max();
  44 +
  45 + return 0;
  46 + }
  47 +};
  48 +
  49 +
  50 +BR_REGISTER(Distance, RejectDistance)
  51 +
  52 +} // namespace br
  53 +
  54 +#include "distance/reject.moc"
... ...
openbr/plugins/distance/sum.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtConcurrent>
  18 +
  19 +#include <openbr/plugins/openbr_internal.h>
  20 +
  21 +namespace br
  22 +{
  23 +
  24 +/*!
  25 + * \ingroup distances
  26 + * \brief Sum match scores across multiple distances
  27 + * \author Scott Klum \cite sklum
  28 + */
  29 +class SumDistance : public UntrainableDistance
  30 +{
  31 + Q_OBJECT
  32 + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances)
  33 + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>())
  34 +
  35 + void train(const TemplateList &data)
  36 + {
  37 + QFutureSynchronizer<void> futures;
  38 + foreach (br::Distance *distance, distances)
  39 + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data));
  40 + futures.waitForFinished();
  41 + }
  42 +
  43 + float compare(const Template &target, const Template &query) const
  44 + {
  45 + float result = 0;
  46 +
  47 + foreach (br::Distance *distance, distances) {
  48 + result += distance->compare(target, query);
  49 +
  50 + if (result == -std::numeric_limits<float>::max())
  51 + return result;
  52 + }
  53 +
  54 + return result;
  55 + }
  56 +};
  57 +
  58 +BR_REGISTER(Distance, SumDistance)
  59 +
  60 +} // namespace br
  61 +
  62 +#include "distance/sum.moc"
... ...
openbr/plugins/distance/turk.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/opencvutils.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +/*!
  24 + * \ingroup distances
  25 + * \brief Unmaps Turk HITs to be compared against query mats
  26 + * \author Scott Klum \cite sklum
  27 + */
  28 +class TurkDistance : public UntrainableDistance
  29 +{
  30 + Q_OBJECT
  31 + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key)
  32 + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
  33 + BR_PROPERTY(QString, key, QString())
  34 + BR_PROPERTY(QStringList, values, QStringList())
  35 +
  36 + bool targetHuman;
  37 + bool queryMachine;
  38 +
  39 + void init()
  40 + {
  41 + targetHuman = Globals->property("TurkTargetHuman").toBool();
  42 + queryMachine = Globals->property("TurkQueryMachine").toBool();
  43 + }
  44 +
  45 + cv::Mat getValues(const Template &t) const
  46 + {
  47 + QList<float> result;
  48 + foreach (const QString &value, values)
  49 + result.append(t.file.get<float>(key + "_" + value));
  50 + return OpenCVUtils::toMat(result, 1);
  51 + }
  52 +
  53 + float compare(const Template &target, const Template &query) const
  54 + {
  55 + const cv::Mat a = targetHuman ? getValues(target) : target.m();
  56 + const cv::Mat b = queryMachine ? query.m() : getValues(query);
  57 + return -norm(a, b, cv::NORM_L1);
  58 + }
  59 +};
  60 +
  61 +BR_REGISTER(Distance, TurkDistance)
  62 +
  63 +} // namespace br
  64 +
  65 +#include "distance/turk.moc"
... ...
openbr/plugins/distance/unit.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +
  19 +namespace br
  20 +{
  21 +
  22 +/*!
  23 + * \ingroup distances
  24 + * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1.
  25 + * \author Josh Klontz \cite jklontz
  26 + */
  27 +class UnitDistance : public Distance
  28 +{
  29 + Q_OBJECT
  30 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance)
  31 + Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a)
  32 + Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b)
  33 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  34 + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  35 + BR_PROPERTY(float, a, 1)
  36 + BR_PROPERTY(float, b, 0)
  37 + BR_PROPERTY(QString, inputVariable, "Label")
  38 +
  39 + void train(const TemplateList &templates)
  40 + {
  41 + const TemplateList samples = templates.mid(0, 2000);
  42 + const QList<int> sampleLabels = samples.indexProperty(inputVariable);
  43 + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(samples.size()), FileList(samples.size())));
  44 + Distance::compare(samples, samples, matrixOutput.data());
  45 +
  46 + double genuineAccumulator, impostorAccumulator;
  47 + int genuineCount, impostorCount;
  48 + genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0;
  49 +
  50 + for (int i=0; i<samples.size(); i++) {
  51 + for (int j=0; j<i; j++) {
  52 + const float val = matrixOutput.data()->data.at<float>(i, j);
  53 + if (sampleLabels[i] == sampleLabels[j]) {
  54 + genuineAccumulator += val;
  55 + genuineCount++;
  56 + } else {
  57 + impostorAccumulator += val;
  58 + impostorCount++;
  59 + }
  60 + }
  61 + }
  62 +
  63 + if (genuineCount == 0) { qWarning("No genuine matches."); return; }
  64 + if (impostorCount == 0) { qWarning("No impostor matches."); return; }
  65 +
  66 + double genuineMean = genuineAccumulator / genuineCount;
  67 + double impostorMean = impostorAccumulator / impostorCount;
  68 +
  69 + if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; }
  70 +
  71 + a = 1.0/(genuineMean-impostorMean);
  72 + b = impostorMean;
  73 +
  74 + qDebug("a = %f, b = %f", a, b);
  75 + }
  76 +
  77 + float compare(const Template &target, const Template &query) const
  78 + {
  79 + return a * (distance->compare(target, query) - b);
  80 + }
  81 +};
  82 +
  83 +BR_REGISTER(Distance, UnitDistance)
  84 +
  85 +} // namespace br
  86 +
  87 +#include "distance/unit.moc"
... ...
openbr/plugins/distance/zscore.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/common.h>
  19 +
  20 +namespace br
  21 +{
  22 +
  23 +class ZScoreDistance : public Distance
  24 +{
  25 + Q_OBJECT
  26 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  27 + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false)
  28 + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  29 + BR_PROPERTY(bool, crossModality, false)
  30 +
  31 + float min, max;
  32 + double mean, stddev;
  33 +
  34 + void train(const TemplateList &src)
  35 + {
  36 + distance->train(src);
  37 +
  38 + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size())));
  39 + distance->compare(src, src, matrixOutput.data());
  40 +
  41 + QList<float> scores;
  42 + scores.reserve(src.size()*src.size());
  43 + for (int i=0; i<src.size(); i++) {
  44 + for (int j=0; j<i; j++) {
  45 + const float score = matrixOutput.data()->data.at<float>(i, j);
  46 + if (score == -std::numeric_limits<float>::max()) continue;
  47 + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue;
  48 + scores.append(score);
  49 + }
  50 + }
  51 +
  52 + Common::MinMax(scores, &min, &max);
  53 + Common::MeanStdDev(scores, &mean, &stddev);
  54 +
  55 + if (stddev == 0) qFatal("Stddev is 0.");
  56 + }
  57 +
  58 + float compare(const Template &target, const Template &query) const
  59 + {
  60 + float score = distance->compare(target,query);
  61 + if (score == -std::numeric_limits<float>::max()) score = (min - mean) / stddev;
  62 + else if (score == std::numeric_limits<float>::max()) score = (max - mean) / stddev;
  63 + else score = (score - mean) / stddev;
  64 + return score;
  65 + }
  66 +
  67 + void store(QDataStream &stream) const
  68 + {
  69 + distance->store(stream);
  70 + stream << min << max << mean << stddev;
  71 + }
  72 +
  73 + void load(QDataStream &stream)
  74 + {
  75 + distance->load(stream);
  76 + stream >> min >> max >> mean >> stddev;
  77 + }
  78 +};
  79 +
  80 +BR_REGISTER(Distance, ZScoreDistance)
  81 +
  82 +} // namespace br
  83 +
  84 +#include "distance/zscore.moc"
... ...