Commit f5a08154bb700cfe6d1de4b997fcde0b661d210a

Authored by Charles Otto
2 parents c3d3dc86 5e20bc34

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

Showing 346 changed files with 22212 additions and 13802 deletions

Too many changes.

To preserve performance only 100 of 346 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,7 +13,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO
13 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/") 13 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/")
14 14
15 # Find Qt 5.0.2 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 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES}) 17 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES})
18 find_package(Qt5${QT_DEPENDENCY}) 18 find_package(Qt5${QT_DEPENDENCY})
19 endforeach() 19 endforeach()
CMakeLists.txt
@@ -80,7 +80,7 @@ endif() @@ -80,7 +80,7 @@ endif()
80 set(QT_DEPENDENCIES Concurrent Core) 80 set(QT_DEPENDENCIES Concurrent Core)
81 option(BR_EMBEDDED "Limit software dependencies") 81 option(BR_EMBEDDED "Limit software dependencies")
82 if(NOT ${BR_EMBEDDED}) 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 endif() 84 endif()
85 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES}) 85 foreach(QT_DEPENDENCY ${QT_DEPENDENCIES})
86 find_package(Qt5${QT_DEPENDENCY}) 86 find_package(Qt5${QT_DEPENDENCY})
@@ -89,7 +89,7 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Qt5Core_QTMAIN_LIBRARIES}) @@ -89,7 +89,7 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Qt5Core_QTMAIN_LIBRARIES})
89 89
90 # Find OpenCV 90 # Find OpenCV
91 find_package(OpenCV 2.4.5 REQUIRED) 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 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) 93 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS})
94 94
95 # Find Alphanum 95 # Find Alphanum
openbr/core/cluster.cpp
@@ -82,7 +82,7 @@ float normalizedROD(const Neighborhood &neighborhood, int a, int b) @@ -82,7 +82,7 @@ float normalizedROD(const Neighborhood &neighborhood, int a, int b)
82 return 1.f * (distanceA + distanceB) / std::min(indexA+1, indexB+1); 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 Neighborhood neighborhood; 87 Neighborhood neighborhood;
88 88
@@ -99,9 +99,7 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats) @@ -99,9 +99,7 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
99 int currentRows = -1; 99 int currentRows = -1;
100 int columnOffset = 0; 100 int columnOffset = 0;
101 for (int j=0; j<numGalleries; j++) { 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 if (j==0) { 103 if (j==0) {
106 currentRows = m.rows; 104 currentRows = m.rows;
107 allNeighbors.resize(currentRows); 105 allNeighbors.resize(currentRows);
@@ -132,37 +130,164 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats) @@ -132,37 +130,164 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
132 // Keep the top matches 130 // Keep the top matches
133 for (int j=0; j<allNeighbors.size(); j++) { 131 for (int j=0; j<allNeighbors.size(); j++) {
134 Neighbors &val = allNeighbors[j]; 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 int keep = std::min(cutoff, val.size()); 134 int keep = std::min(cutoff, val.size());
137 std::partial_sort(val.begin(), val.begin()+keep, val.end(), compareNeighbors); 135 std::partial_sort(val.begin(), val.begin()+keep, val.end(), compareNeighbors);
138 neighborhood.append((Neighbors)val.mid(0, keep)); 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 return neighborhood; 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 const int cutoff = neighborhood.first().size(); 291 const int cutoff = neighborhood.first().size();
167 const float threshold = 3*cutoff/4 * aggressiveness/5; 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,9 +364,39 @@ br::Clusters br::ClusterGallery(const QStringList &amp;simmats, float aggressiveness
239 neighborhood = newNeighborhood; 364 neighborhood = newNeighborhood;
240 } 365 }
241 366
242 - // Save clusters  
243 if (!csv.isEmpty()) 367 if (!csv.isEmpty())
244 WriteClusters(clusters, csv); 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 return clusters; 400 return clusters;
246 } 401 }
247 402
openbr/core/cluster.h
@@ -21,15 +21,46 @@ @@ -21,15 +21,46 @@
21 #include <QString> 21 #include <QString>
22 #include <QStringList> 22 #include <QStringList>
23 #include <QVector> 23 #include <QVector>
  24 +#include <openbr/openbr_plugin.h>
  25 +#include <openbr/plugins/openbr_internal.h>
24 26
25 namespace br 27 namespace br
26 { 28 {
27 typedef QList<int> Cluster; // List of indices into galleries 29 typedef QList<int> Cluster; // List of indices into galleries
28 typedef QVector<Cluster> Clusters; 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 void EvalClustering(const QString &csv, const QString &input, QString truth_property); 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 Clusters ReadClusters(const QString &csv); 64 Clusters ReadClusters(const QString &csv);
34 void WriteClusters(const Clusters &clusters, const QString &csv); 65 void WriteClusters(const Clusters &clusters, const QString &csv);
35 } 66 }
openbr/core/core.cpp
@@ -138,6 +138,13 @@ struct AlgorithmCore @@ -138,6 +138,13 @@ struct AlgorithmCore
138 138
139 void load(const QString &model) 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 QtUtils::BlockCompression compressedRead; 148 QtUtils::BlockCompression compressedRead;
142 QFile inFile(model); 149 QFile inFile(model);
143 compressedRead.setBasis(&inFile); 150 compressedRead.setBasis(&inFile);
@@ -762,5 +769,15 @@ QSharedPointer&lt;br::Distance&gt; br::Distance::fromAlgorithm(const QString &amp;algorith @@ -762,5 +769,15 @@ QSharedPointer&lt;br::Distance&gt; br::Distance::fromAlgorithm(const QString &amp;algorith
762 return AlgorithmManager::getAlgorithm(algorithm)->distance; 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 #include "core.moc" 783 #include "core.moc"
openbr/core/qtutils.cpp
@@ -500,14 +500,15 @@ QString getAbsolutePath(const QString &amp;filename) @@ -500,14 +500,15 @@ QString getAbsolutePath(const QString &amp;filename)
500 return QFileInfo(filename).absoluteFilePath(); 500 return QFileInfo(filename).absoluteFilePath();
501 } 501 }
502 502
  503 +const int base_block = 100000000;
  504 +
503 BlockCompression::BlockCompression(QIODevice *_basis) 505 BlockCompression::BlockCompression(QIODevice *_basis)
504 { 506 {
505 - blockSize = 100000000; 507 + blockSize = base_block;
506 setBasis(_basis); 508 setBasis(_basis);
507 } 509 }
508 510
509 -BlockCompression::BlockCompression() { blockSize = 100000000; };  
510 - 511 +BlockCompression::BlockCompression() { blockSize = base_block;};
511 512
512 bool BlockCompression::open(QIODevice::OpenMode mode) 513 bool BlockCompression::open(QIODevice::OpenMode mode)
513 { 514 {
@@ -521,14 +522,22 @@ bool BlockCompression::open(QIODevice::OpenMode mode) @@ -521,14 +522,22 @@ bool BlockCompression::open(QIODevice::OpenMode mode)
521 blockWriter.setDevice(basis); 522 blockWriter.setDevice(basis);
522 523
523 if (mode & QIODevice::WriteOnly) { 524 if (mode & QIODevice::WriteOnly) {
524 - precompressedBlockWriter = new QBuffer;  
525 - precompressedBlockWriter->open(QIODevice::ReadWrite); 525 + precompressedBlockWriter.open(QIODevice::WriteOnly);
526 } 526 }
527 else if (mode & QIODevice::ReadOnly) { 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 QByteArray compressedBlock; 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 decompressedBlock = qUncompress(compressedBlock); 539 decompressedBlock = qUncompress(compressedBlock);
  540 +
532 decompressedBlockReader.setBuffer(&decompressedBlock); 541 decompressedBlockReader.setBuffer(&decompressedBlock);
533 decompressedBlockReader.open(QIODevice::ReadOnly); 542 decompressedBlockReader.open(QIODevice::ReadOnly);
534 } 543 }
@@ -538,11 +547,17 @@ bool BlockCompression::open(QIODevice::OpenMode mode) @@ -538,11 +547,17 @@ bool BlockCompression::open(QIODevice::OpenMode mode)
538 547
539 void BlockCompression::close() 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 basis->close(); 561 basis->close();
547 } 562 }
548 563
@@ -557,8 +572,10 @@ void BlockCompression::setBasis(QIODevice *_basis) @@ -557,8 +572,10 @@ void BlockCompression::setBasis(QIODevice *_basis)
557 // block from basis 572 // block from basis
558 qint64 BlockCompression::readData(char *data, qint64 remaining) 573 qint64 BlockCompression::readData(char *data, qint64 remaining)
559 { 574 {
  575 + qint64 initial = remaining;
560 qint64 read = 0; 576 qint64 read = 0;
561 while (remaining > 0) { 577 while (remaining > 0) {
  578 + // attempt to read the target amount of data
562 qint64 single_read = decompressedBlockReader.read(data, remaining); 579 qint64 single_read = decompressedBlockReader.read(data, remaining);
563 if (single_read == -1) 580 if (single_read == -1)
564 qFatal("miss read"); 581 qFatal("miss read");
@@ -567,13 +584,21 @@ qint64 BlockCompression::readData(char *data, qint64 remaining) @@ -567,13 +584,21 @@ qint64 BlockCompression::readData(char *data, qint64 remaining)
567 read += single_read; 584 read += single_read;
568 data += single_read; 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 if (remaining > 0) { 588 if (remaining > 0) {
572 QByteArray compressedBlock; 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 decompressedBlock = qUncompress(compressedBlock); 602 decompressedBlock = qUncompress(compressedBlock);
578 603
579 decompressedBlockReader.close(); 604 decompressedBlockReader.close();
@@ -581,7 +606,12 @@ qint64 BlockCompression::readData(char *data, qint64 remaining) @@ -581,7 +606,12 @@ qint64 BlockCompression::readData(char *data, qint64 remaining)
581 decompressedBlockReader.open(QIODevice::ReadOnly); 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 bool BlockCompression::isSequential() const 617 bool BlockCompression::isSequential() const
@@ -591,36 +621,57 @@ bool BlockCompression::isSequential() const @@ -591,36 +621,57 @@ bool BlockCompression::isSequential() const
591 621
592 qint64 BlockCompression::writeData(const char *data, qint64 remaining) 622 qint64 BlockCompression::writeData(const char *data, qint64 remaining)
593 { 623 {
  624 + const char * endPoint = data + remaining;
  625 + qint64 initial = remaining;
  626 +
594 qint64 written = 0; 627 qint64 written = 0;
595 628
596 while (remaining > 0) { 629 while (remaining > 0) {
597 // how much more can be put in this buffer? 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 // don't try to write beyond capacity 635 // don't try to write beyond capacity
601 qint64 write_size = qMin(capacity, remaining); 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 if (singleWrite == -1) 640 if (singleWrite == -1)
607 - singleWrite = 0; 641 + qFatal("matrix write failure?");
608 642
609 remaining -= singleWrite; 643 remaining -= singleWrite;
610 data += singleWrite; 644 data += singleWrite;
611 written += singleWrite; 645 written += singleWrite;
  646 + if (data > endPoint)
  647 + qFatal("Wrote past the end");
612 648
613 if (remaining > 0) { 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 return basis->isWritable() ? written : -1; 675 return basis->isWritable() ? written : -1;
625 } 676 }
626 677
openbr/core/qtutils.h
@@ -122,7 +122,7 @@ namespace QtUtils @@ -122,7 +122,7 @@ namespace QtUtils
122 122
123 // write to a QByteArray, when max block sized is reached, compress and write 123 // write to a QByteArray, when max block sized is reached, compress and write
124 // it to basis 124 // it to basis
125 - QBuffer * precompressedBlockWriter; 125 + QBuffer precompressedBlockWriter;
126 QDataStream blockWriter; 126 QDataStream blockWriter;
127 qint64 writeData(const char *data, qint64 remaining); 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,7 +59,7 @@ void br_cat(int num_input_galleries, const char *input_galleries[], const char *
59 59
60 void br_cluster(int num_simmats, const char *simmats[], float aggressiveness, const char *csv) 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 void br_combine_masks(int num_input_masks, const char *input_masks[], const char *output_mask, const char *method) 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,6 +754,12 @@ public:
754 Q_PROPERTY(int crossValidate READ get_crossValidate WRITE set_crossValidate RESET reset_crossValidate) 754 Q_PROPERTY(int crossValidate READ get_crossValidate WRITE set_crossValidate RESET reset_crossValidate)
755 BR_PROPERTY(int, crossValidate, 0) 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 QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ 763 QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */
758 QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ 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/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 #include <opencv2/imgproc/imgproc.hpp> 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 using namespace cv; 23 using namespace cv;
8 24
@@ -128,4 +144,4 @@ BR_REGISTER(Transform, EBIFTransform) @@ -128,4 +144,4 @@ BR_REGISTER(Transform, EBIFTransform)
128 144
129 } // namespace br 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 using namespace cv; 20 using namespace cv;
6 21
7 namespace br 22 namespace br
@@ -250,113 +265,6 @@ class ForestInductionTransform : public ForestTransform @@ -250,113 +265,6 @@ class ForestInductionTransform : public ForestTransform
250 265
251 BR_REGISTER(Transform, ForestInductionTransform) 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 } // namespace br 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 #include <pxcaccelerator.h> 1 #include <pxcaccelerator.h>
3 #include <pxcface.h> 2 #include <pxcface.h>
4 #include <pxcimage.h> 3 #include <pxcimage.h>
5 #include <pxcsession.h> 4 #include <pxcsession.h>
6 5
  6 +#include <openbr/plugins/openbr_internal.h>
  7 +
7 using namespace br; 8 using namespace br;
8 9
9 static PXCSession *pxcSession = NULL; 10 static PXCSession *pxcSession = NULL;
openbr/plugins/eigen3.cpp renamed to openbr/plugins/classification/lda.cpp
@@ -15,12 +15,14 @@ @@ -15,12 +15,14 @@
15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16
17 #include <Eigen/Dense> 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 namespace br 27 namespace br
26 { 28 {
@@ -652,46 +654,609 @@ class SparseLDATransform : public Transform @@ -652,46 +654,609 @@ class SparseLDATransform : public Transform
652 654
653 BR_REGISTER(Transform, SparseLDATransform) 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 * \author Josh Klontz \cite jklontz 672 * \author Josh Klontz \cite jklontz
659 */ 673 */
660 -class L1Distance : public UntrainableDistance 674 +class WCDATransform : public Transform
661 { 675 {
662 Q_OBJECT 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 Q_OBJECT 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 } // namespace br 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,8 +2,8 @@
2 #include <opencv2/core/core.hpp> 2 #include <opencv2/core/core.hpp>
3 #include <opencv2/ml/ml.hpp> 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 #include <linear.h> 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 #include <opencv2/ml/ml.hpp> 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 using namespace cv; 22 using namespace cv;
12 23
13 namespace br 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 * \ingroup transforms 28 * \ingroup transforms
51 * \brief Wraps OpenCV's multi-layer perceptron framework 29 * \brief Wraps OpenCV's multi-layer perceptron framework
@@ -124,12 +102,12 @@ private: @@ -124,12 +102,12 @@ private:
124 102
125 void load(QDataStream &stream) 103 void load(QDataStream &stream)
126 { 104 {
127 - loadMLP(mlp,stream); 105 + OpenCVUtils::loadModel(mlp, stream);
128 } 106 }
129 107
130 void store(QDataStream &stream) const 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,4 +115,4 @@ BR_REGISTER(Transform, MLPTransform)
137 115
138 } // namespace br 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,8 +20,8 @@
20 #include <Bmp.h> 20 #include <Bmp.h>
21 #include <NGrayscaleImage.h> 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 using namespace cv; 26 using namespace cv;
27 using namespace br; 27 using namespace br;
@@ -457,4 +457,4 @@ class NT4Compare : public Distance @@ -457,4 +457,4 @@ class NT4Compare : public Distance
457 457
458 BR_REGISTER(Distance, NT4Compare) 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,7 +6,7 @@
6 #include <pittpatt_raw_image_io.h> 6 #include <pittpatt_raw_image_io.h>
7 #include <pittpatt_license.h> 7 #include <pittpatt_license.h>
8 #include <openbr/openbr_plugin.h> 8 #include <openbr/openbr_plugin.h>
9 -#include "openbr_internal.h" 9 +#include "openbr/plugins/openbr_internal.h"
10 #include "openbr/core/resource.h" 10 #include "openbr/core/resource.h"
11 11
12 #define TRY(CC) \ 12 #define TRY(CC) \
openbr/plugins/pp5.cpp renamed to openbr/plugins/classification/pp5.cpp
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 #include <pittpatt_raw_image_io.h> 11 #include <pittpatt_raw_image_io.h>
12 #include <pittpatt_sdk.h> 12 #include <pittpatt_sdk.h>
13 #include <pittpatt_license.h> 13 #include <pittpatt_license.h>
14 -#include "openbr_internal.h" 14 +#include "openbr/plugins/openbr_internal.h"
15 #include "openbr/core/resource.h" 15 #include "openbr/core/resource.h"
16 16
17 #define TRY(CC) \ 17 #define TRY(CC) \
@@ -593,4 +593,4 @@ class PP5GalleryTransform: public UntrainableMetaTransform @@ -593,4 +593,4 @@ class PP5GalleryTransform: public UntrainableMetaTransform
593 593
594 BR_REGISTER(Transform, PP5GalleryTransform) 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,8 +18,8 @@
18 #include <opencv2/core/core.hpp> 18 #include <opencv2/core/core.hpp>
19 #include <opencv2/ml/ml.hpp> 19 #include <opencv2/ml/ml.hpp>
20 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 using namespace cv; 24 using namespace cv;
25 25
@@ -261,4 +261,4 @@ BR_REGISTER(Distance, SVMDistance) @@ -261,4 +261,4 @@ BR_REGISTER(Distance, SVMDistance)
261 261
262 } // namespace br 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,12 +14,8 @@
14 * limitations under the License. * 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 using namespace cv; 20 using namespace cv;
25 21
@@ -28,58 +24,6 @@ namespace br @@ -28,58 +24,6 @@ namespace br
28 24
29 /*! 25 /*!
30 * \ingroup transforms 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 * \brief K nearest neighbors classifier. 27 * \brief K nearest neighbors classifier.
84 * \author Josh Klontz \cite jklontz 28 * \author Josh Klontz \cite jklontz
85 */ 29 */
@@ -151,148 +95,6 @@ class KNNTransform : public Transform @@ -151,148 +95,6 @@ class KNNTransform : public Transform
151 95
152 BR_REGISTER(Transform, KNNTransform) 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 } // namespace br 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/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,7 +2,8 @@ set(BR_WITH_IPC2013 OFF CACHE BOOL &quot;Build with Intel Perceptual Computing SDK 20
2 2
3 if(${BR_WITH_IPC2013}) 3 if(${BR_WITH_IPC2013})
4 find_package(IPC2013 REQUIRED) 4 find_package(IPC2013 REQUIRED)
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/ipc2013.cpp)  
6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${IPC2013_LIBS}) 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${IPC2013_LIBS})
7 install(DIRECTORY ${IPC2013_DIR}/bin/x64/ DESTINATION bin) 6 install(DIRECTORY ${IPC2013_DIR}/bin/x64/ DESTINATION bin)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/ipc2013.cpp)
8 endif() 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,10 +3,10 @@ set(BR_WITH_JAVA OFF CACHE BOOL &quot;Use Java Code&quot;)
3 if (${BR_WITH_JAVA}) 3 if (${BR_WITH_JAVA})
4 find_package(JNI REQUIRED) 4 find_package(JNI REQUIRED)
5 find_package(JAVA REQUIRED) 5 find_package(JAVA REQUIRED)
6 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/jni.cpp)  
7 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES}) 6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES})
8 7
9 include_directories(${JAVA_INCLUDE_PATH}) 8 include_directories(${JAVA_INCLUDE_PATH})
10 include_directories(${JAVA_INCLUDE_PATH2}) 9 include_directories(${JAVA_INCLUDE_PATH2})
11 - 10 +else()
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/jni.cpp)
12 endif() 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,5 +3,6 @@ set(BR_WITH_LIBLINEAR OFF CACHE BOOL &quot;Build with LibLinear&quot;)
3 if(${BR_WITH_LIBLINEAR}) 3 if(${BR_WITH_LIBLINEAR})
4 find_package(LibLinear REQUIRED) 4 find_package(LibLinear REQUIRED)
5 set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${LibLinear_SRC}) 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 endif() 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,6 +2,9 @@ set(BR_WITH_LIKELY OFF CACHE BOOL &quot;Build with Likely&quot;)
2 2
3 if(${BR_WITH_LIKELY}) 3 if(${BR_WITH_LIKELY})
4 find_package(Likely REQUIRED) 4 find_package(Likely REQUIRED)
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/likely.cpp)  
6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS}) 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 endif() 10 endif()
openbr/plugins/mongoose.cmake renamed to openbr/plugins/cmake/mongoose.cmake
1 set(BR_WITH_MONGOOSE OFF CACHE BOOL "Build with Mongoose") 1 set(BR_WITH_MONGOOSE OFF CACHE BOOL "Build with Mongoose")
2 if(${BR_WITH_MONGOOSE}) 2 if(${BR_WITH_MONGOOSE})
3 find_package(Mongoose) 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 install(FILES ${MONGOOSE_LICENSE} RENAME mongoose DESTINATION share/openbr/licenses) 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 endif() 8 endif()
openbr/plugins/qtnetwork.cmake renamed to openbr/plugins/cmake/network.cmake
@@ -3,6 +3,10 @@ if(${BR_WITH_QTNETWORK}) @@ -3,6 +3,10 @@ if(${BR_WITH_QTNETWORK})
3 find_package(Qt5Network) 3 find_package(Qt5Network)
4 find_package(HttpParser) 4 find_package(HttpParser)
5 set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Network) 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 install(FILES ${HTTPPARSER_LICENSE} RENAME http-parser DESTINATION share/openbr/licenses) 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 endif() 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,7 +2,8 @@ set(BR_WITH_NT4 OFF CACHE BOOL &quot;Build with Neurotec Biometric 4&quot;)
2 2
3 if(${BR_WITH_NT4}) 3 if(${BR_WITH_NT4})
4 find_package(NT4 REQUIRED) 4 find_package(NT4 REQUIRED)
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/nt4.cpp)  
6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${NT4_LIBS}) 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${NT4_LIBS})
7 install(DIRECTORY ${NT4_DIR_LIB}/ DESTINATION lib) 6 install(DIRECTORY ${NT4_DIR_LIB}/ DESTINATION lib)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/nt4.cpp)
8 endif() 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,8 +2,9 @@ set(BR_WITH_PP4 OFF CACHE BOOL &quot;Build with PittPatt 4&quot;)
2 2
3 if(${BR_WITH_PP4}) 3 if(${BR_WITH_PP4})
4 find_package(PP4 REQUIRED) 4 find_package(PP4 REQUIRED)
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp)  
6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS}) 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS})
7 install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib) 6 install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib)
8 install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4) 7 install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4)
  8 +else()
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp4.cpp)
9 endif() 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,7 +2,6 @@ set(BR_WITH_PP5 OFF CACHE BOOL &quot;Build with PittPatt 5&quot;)
2 2
3 if(${BR_WITH_PP5}) 3 if(${BR_WITH_PP5})
4 find_package(PP5 REQUIRED) 4 find_package(PP5 REQUIRED)
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp5.cpp)  
6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP5_LIBS}) 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP5_LIBS})
7 6
8 if(WIN32) 7 if(WIN32)
@@ -12,4 +11,6 @@ if(${BR_WITH_PP5}) @@ -12,4 +11,6 @@ if(${BR_WITH_PP5})
12 endif() 11 endif()
13 12
14 install(DIRECTORY ${PP5_DIR}/models/ DESTINATION share/openbr/models/pp5) 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 endif() 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,14 +2,9 @@ set(BR_WITH_STASM4 ON CACHE BOOL &quot;Build with Stasm&quot;)
2 2
3 if(${BR_WITH_STASM4}) 3 if(${BR_WITH_STASM4})
4 find_package(Stasm4 REQUIRED) 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 install(DIRECTORY ${Stasm_DIR}/data/ DESTINATION share/openbr/models/stasm) 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 endif() 10 endif()
openbr/plugins/algorithms.cpp renamed to openbr/plugins/core/algorithms.cpp
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 * limitations under the License. * 14 * limitations under the License. *
15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16
17 -#include "openbr_internal.h" 17 +#include <openbr/plugins/openbr_internal.h>
18 18
19 namespace br 19 namespace br
20 { 20 {
@@ -43,7 +43,7 @@ class AlgorithmsInitializer : public Initializer @@ -43,7 +43,7 @@ class AlgorithmsInitializer : public Initializer
43 Globals->abbreviations.insert("OpenBR", "FaceRecognition"); 43 Globals->abbreviations.insert("OpenBR", "FaceRecognition");
44 Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); 44 Globals->abbreviations.insert("GenderEstimation", "GenderClassification");
45 Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); 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 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)"); 47 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)");
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)"); 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,9 +55,9 @@ class AlgorithmsInitializer : public Initializer
55 Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard"); 55 Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard");
56 Globals->abbreviations.insert("ShowMotionSegmentation", "DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard"); 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 // Generic Image Processing 62 // Generic Image Processing
63 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); 63 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
@@ -66,7 +66,7 @@ class AlgorithmsInitializer : public Initializer @@ -66,7 +66,7 @@ class AlgorithmsInitializer : public Initializer
66 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); 66 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)");
67 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); 67 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2");
68 Globals->abbreviations.insert("ImageSimilarity", "Open+EnsureChannels(3)+Resize(256,256)+SplitChannels+RectRegions(64,64,64,64)+Hist(256,0,8)+Cat:NegativeLogPlusOne(L2)"); 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 Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)"); 70 Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)");
71 71
72 // Hash 72 // Hash
@@ -89,7 +89,7 @@ class AlgorithmsInitializer : public Initializer @@ -89,7 +89,7 @@ class AlgorithmsInitializer : public Initializer
89 // Transforms 89 // Transforms
90 Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); 90 Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)");
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))"); 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 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); 93 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)");
94 Globals->abbreviations.insert("DenseSIFT2", "(Grid(5,5)+SIFTDescriptor(12)+ByRow)"); 94 Globals->abbreviations.insert("DenseSIFT2", "(Grid(5,5)+SIFTDescriptor(12)+ByRow)");
95 Globals->abbreviations.insert("FaceRecognitionRegistration", "ASEFEyes+Affine(88,88,0.25,0.35)"); 95 Globals->abbreviations.insert("FaceRecognitionRegistration", "ASEFEyes+Affine(88,88,0.25,0.35)");
@@ -108,4 +108,4 @@ BR_REGISTER(Initializer, AlgorithmsInitializer) @@ -108,4 +108,4 @@ BR_REGISTER(Initializer, AlgorithmsInitializer)
108 108
109 } // namespace br 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 namespace br 22 namespace br
8 { 23 {
@@ -134,138 +149,6 @@ class CrossValidateTransform : public MetaTransform @@ -134,138 +149,6 @@ class CrossValidateTransform : public MetaTransform
134 149
135 BR_REGISTER(Transform, CrossValidateTransform) 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 } // namespace br 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 //Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables 1 //Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables
2 2
3 #include <limits> 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 #include <jni.h> 6 #include <jni.h>
7 7
8 namespace br 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 namespace br 3 namespace br
8 { 4 {
@@ -57,68 +53,6 @@ public: @@ -57,68 +53,6 @@ public:
57 53
58 BR_REGISTER(Transform, LikelyTransform) 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 } // namespace br 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 #include <QBuffer> 17 #include <QBuffer>
4 #include <QCoreApplication> 18 #include <QCoreApplication>
@@ -9,8 +23,8 @@ @@ -9,8 +23,8 @@
9 #include <QUuid> 23 #include <QUuid>
10 #include <QWaitCondition> 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 using namespace cv; 29 using namespace cv;
16 30
@@ -658,4 +672,4 @@ BR_REGISTER(Transform, ProcessWrapperTransform) @@ -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 #include <fstream> 17 #include <fstream>
2 #include <QReadWriteLock> 18 #include <QReadWriteLock>
3 #include <QWaitCondition> 19 #include <QWaitCondition>
@@ -8,10 +24,11 @@ @@ -8,10 +24,11 @@
8 #include <QtConcurrent> 24 #include <QtConcurrent>
9 #include <opencv/highgui.h> 25 #include <opencv/highgui.h>
10 #include <opencv2/highgui/highgui.hpp> 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 using namespace cv; 33 using namespace cv;
17 using namespace std; 34 using namespace std;
@@ -1360,5 +1377,5 @@ BR_REGISTER(Transform, StreamTransform) @@ -1360,5 +1377,5 @@ BR_REGISTER(Transform, StreamTransform)
1360 1377
1361 } // namespace br 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"
openbr/plugins/draw.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/highgui/highgui.hpp>  
18 -#include <opencv2/highgui/highgui_c.h>  
19 -#include <opencv2/imgproc/imgproc.hpp>  
20 -#include <vector>  
21 -#include "openbr_internal.h"  
22 -#include "openbr/core/opencvutils.h"  
23 -  
24 -using namespace cv;  
25 -  
26 -namespace br  
27 -{  
28 -  
29 -/*!  
30 - * \ingroup transforms  
31 - * \brief Renders metadata onto the image.  
32 - *  
33 - * The inPlace argument controls whether or not the image is cloned before the metadata is drawn.  
34 - *  
35 - * \author Josh Klontz \cite jklontz  
36 - */  
37 -class DrawTransform : public UntrainableTransform  
38 -{  
39 - Q_OBJECT  
40 - Q_PROPERTY(bool verbose READ get_verbose WRITE set_verbose RESET reset_verbose STORED false)  
41 - Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false)  
42 - Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false)  
43 - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)  
44 - Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false)  
45 - Q_PROPERTY(bool named READ get_named WRITE set_named RESET reset_named STORED false)  
46 - Q_PROPERTY(bool location READ get_location WRITE set_location RESET reset_location STORED false)  
47 - BR_PROPERTY(bool, verbose, false)  
48 - BR_PROPERTY(bool, points, true)  
49 - BR_PROPERTY(bool, rects, true)  
50 - BR_PROPERTY(bool, inPlace, false)  
51 - BR_PROPERTY(int, lineThickness, 1)  
52 - BR_PROPERTY(bool, named, true)  
53 - BR_PROPERTY(bool, location, true)  
54 -  
55 - void project(const Template &src, Template &dst) const  
56 - {  
57 - const Scalar color(0,255,0);  
58 - const Scalar verboseColor(255, 255, 0);  
59 - dst.m() = inPlace ? src.m() : src.m().clone();  
60 -  
61 - if (points) {  
62 - const QList<Point2f> pointsList = (named) ? OpenCVUtils::toPoints(src.file.points()+src.file.namedPoints()) : OpenCVUtils::toPoints(src.file.points());  
63 - for (int i=0; i<pointsList.size(); i++) {  
64 - const Point2f &point = pointsList[i];  
65 - circle(dst, point, 3, color, -1);  
66 - QString label = (location) ? QString("%1,(%2,%3)").arg(QString::number(i),QString::number(point.x),QString::number(point.y)) : QString("%1").arg(QString::number(i));  
67 - if (verbose) putText(dst, label.toStdString(), point, FONT_HERSHEY_SIMPLEX, 0.5, verboseColor, 1);  
68 - }  
69 - }  
70 - if (rects) {  
71 - foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects()))  
72 - rectangle(dst, rect, color, lineThickness);  
73 - }  
74 - }  
75 -};  
76 -  
77 -BR_REGISTER(Transform, DrawTransform)  
78 -  
79 -  
80 -/*!  
81 - * \ingroup transforms  
82 - * \brief Draw the value of the specified property at the specified point on the image  
83 - *  
84 - * The inPlace argument controls whether or not the image is cloned before it is drawn on.  
85 - *  
86 - * \author Charles Otto \cite caotto  
87 - */  
88 -class DrawPropertyPointTransform : public UntrainableTransform  
89 -{  
90 - Q_OBJECT  
91 - Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false)  
92 - Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false)  
93 - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)  
94 - BR_PROPERTY(QString, propName, "")  
95 - BR_PROPERTY(QString, pointName, "")  
96 - BR_PROPERTY(bool, inPlace, false)  
97 -  
98 -  
99 - void project(const Template &src, Template &dst) const  
100 - {  
101 - dst = src;  
102 - if (propName.isEmpty() || pointName.isEmpty())  
103 - return;  
104 -  
105 - dst.m() = inPlace ? src.m() : src.m().clone();  
106 -  
107 - const Scalar textColor(255, 255, 0);  
108 -  
109 - QVariant prop = dst.file.value(propName);  
110 -  
111 -  
112 - if (!prop.canConvert(QVariant::String))  
113 - return;  
114 - QString propString = prop.toString();  
115 -  
116 - QVariant point = dst.file.value(pointName);  
117 -  
118 - if (!point.canConvert(QVariant::PointF))  
119 - return;  
120 -  
121 - QPointF targetPoint = point.toPointF();  
122 -  
123 - Point2f cvPoint =OpenCVUtils::toPoint(targetPoint);  
124 -  
125 - std::string text = propName.toStdString() + ": " + propString.toStdString();  
126 - putText(dst, text, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1);  
127 - }  
128 -  
129 -};  
130 -BR_REGISTER(Transform, DrawPropertyPointTransform)  
131 -  
132 -/*!  
133 - * \ingroup transforms  
134 - * \brief Draw the values of a list of properties at the specified point on the image  
135 - *  
136 - * The inPlace argument controls whether or not the image is cloned before it is drawn on.  
137 - *  
138 - * \author Charles Otto \cite caotto  
139 - */  
140 -class DrawPropertiesPointTransform : public UntrainableTransform  
141 -{  
142 - Q_OBJECT  
143 - Q_PROPERTY(QStringList propNames READ get_propNames WRITE set_propNames RESET reset_propNames STORED false)  
144 - Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false)  
145 - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)  
146 - BR_PROPERTY(QStringList, propNames, QStringList())  
147 - BR_PROPERTY(QString, pointName, "")  
148 - BR_PROPERTY(bool, inPlace, false)  
149 -  
150 - void project(const Template &src, Template &dst) const  
151 - {  
152 - dst = src;  
153 - if (propNames.isEmpty() || pointName.isEmpty())  
154 - return;  
155 -  
156 - dst.m() = inPlace ? src.m() : src.m().clone();  
157 -  
158 - QVariant point = dst.file.value(pointName);  
159 -  
160 - if (!point.canConvert(QVariant::PointF))  
161 - return;  
162 -  
163 - QPointF targetPoint = point.toPointF();  
164 -  
165 - Point2f cvPoint =OpenCVUtils::toPoint(targetPoint);  
166 -  
167 -  
168 - const Scalar textColor(255, 255, 0);  
169 -  
170 - std::string outString = "";  
171 - foreach (const QString &propName, propNames)  
172 - {  
173 - QVariant prop = dst.file.value(propName);  
174 -  
175 - if (!prop.canConvert(QVariant::String))  
176 - continue;  
177 - QString propString = prop.toString();  
178 - outString += propName.toStdString() + ": " + propString.toStdString() + " ";  
179 -  
180 - }  
181 - if (outString.empty())  
182 - return;  
183 -  
184 - putText(dst, outString, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1);  
185 - }  
186 -  
187 -};  
188 -BR_REGISTER(Transform, DrawPropertiesPointTransform)  
189 -  
190 -  
191 -/*!  
192 - * \ingroup transforms  
193 - * \brief Draws a grid on the image  
194 - * \author Josh Klontz \cite jklontz  
195 - */  
196 -class DrawGridTransform : public UntrainableTransform  
197 -{  
198 - Q_OBJECT  
199 - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false)  
200 - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false)  
201 - Q_PROPERTY(int r READ get_r WRITE set_r RESET reset_r STORED false)  
202 - Q_PROPERTY(int g READ get_g WRITE set_g RESET reset_g STORED false)  
203 - Q_PROPERTY(int b READ get_b WRITE set_b RESET reset_b STORED false)  
204 - BR_PROPERTY(int, rows, 0)  
205 - BR_PROPERTY(int, columns, 0)  
206 - BR_PROPERTY(int, r, 196)  
207 - BR_PROPERTY(int, g, 196)  
208 - BR_PROPERTY(int, b, 196)  
209 -  
210 - void project(const Template &src, Template &dst) const  
211 - {  
212 - Mat m = src.m().clone();  
213 - float rowStep = 1.f * m.rows / (rows+1);  
214 - float columnStep = 1.f * m.cols / (columns+1);  
215 - int thickness = qMin(m.rows, m.cols) / 256;  
216 - for (float row = rowStep/2; row < m.rows; row += rowStep)  
217 - line(m, Point(0, row), Point(m.cols, row), Scalar(r, g, b), thickness, CV_AA);  
218 - for (float column = columnStep/2; column < m.cols; column += columnStep)  
219 - line(m, Point(column, 0), Point(column, m.rows), Scalar(r, g, b), thickness, CV_AA);  
220 - dst = m;  
221 - }  
222 -};  
223 -  
224 -BR_REGISTER(Transform, DrawGridTransform)  
225 -  
226 -/*!  
227 - * \ingroup transforms  
228 - * \brief Computes the mean of a set of templates.  
229 - * \note Suitable for visualization only as it sets every projected template to the mean template.  
230 - * \author Scott Klum \cite sklum  
231 - */  
232 -class MeanTransform : public Transform  
233 -{  
234 - Q_OBJECT  
235 -  
236 - Mat mean;  
237 -  
238 - void train(const TemplateList &data)  
239 - {  
240 - mean = Mat::zeros(data[0].m().rows,data[0].m().cols,CV_32F);  
241 -  
242 - for (int i = 0; i < data.size(); i++) {  
243 - Mat converted;  
244 - data[i].m().convertTo(converted, CV_32F);  
245 - mean += converted;  
246 - }  
247 -  
248 - mean /= data.size();  
249 - }  
250 -  
251 - void project(const Template &src, Template &dst) const  
252 - {  
253 - dst = src;  
254 - dst.m() = mean;  
255 - }  
256 -  
257 -};  
258 -  
259 -BR_REGISTER(Transform, MeanTransform)  
260 -  
261 -/*!  
262 - * \ingroup transforms  
263 - * \brief Load the image named in the specified property, draw it on the current matrix adjacent to the rect specified in the other property.  
264 - * \author Charles Otto \cite caotto  
265 - */  
266 -class AdjacentOverlayTransform : public Transform  
267 -{  
268 - Q_OBJECT  
269 -  
270 - Q_PROPERTY(QString imgName READ get_imgName WRITE set_imgName RESET reset_imgName STORED false)  
271 - Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false)  
272 - BR_PROPERTY(QString, imgName, "")  
273 - BR_PROPERTY(QString, targetName, "")  
274 -  
275 - QSharedPointer<Transform> opener;  
276 - void project(const Template &src, Template &dst) const  
277 - {  
278 - dst = src;  
279 -  
280 - if (imgName.isEmpty() || targetName.isEmpty() || !dst.file.contains(imgName) || !dst.file.contains(targetName))  
281 - return;  
282 -  
283 - QVariant temp = src.file.value(imgName);  
284 - cv::Mat im;  
285 - // is this a filename?  
286 - if (temp.canConvert<QString>()) {  
287 - QString im_name = temp.toString();  
288 - Template temp_im;  
289 - opener->project(File(im_name), temp_im);  
290 - im = temp_im.m();  
291 - }  
292 - // a cv::Mat ?  
293 - else if (temp.canConvert<cv::Mat>())  
294 - im = src.file.get<cv::Mat>(imgName);  
295 - else  
296 - qDebug() << "Unrecognized property type " << imgName << "for" << src.file.name;  
297 -  
298 - // Location of detected face in source image  
299 - QRectF target_location = src.file.get<QRectF>(targetName);  
300 -  
301 - // match width with target region  
302 - qreal target_width = target_location.width();  
303 - qreal current_width = im.cols;  
304 - qreal current_height = im.rows;  
305 -  
306 - qreal aspect_ratio = current_height / current_width;  
307 - qreal target_height = target_width * aspect_ratio;  
308 -  
309 - cv::resize(im, im, cv::Size(target_width, target_height));  
310 -  
311 - // ROI used to maybe crop the matched image  
312 - cv::Rect clip_roi;  
313 - clip_roi.x = 0;  
314 - clip_roi.y = 0;  
315 - clip_roi.width = im.cols;  
316 - clip_roi.height= im.rows <= dst.m().rows ? im.rows : dst.m().rows;  
317 -  
318 - int half_width = src.m().cols / 2;  
319 - int out_x = 0;  
320 -  
321 - // place in the source image we will copy the matched image to.  
322 - cv::Rect target_roi;  
323 - bool left_side = false;  
324 - int width_adjust = 0;  
325 - // Place left  
326 - if (target_location.center().rx() > half_width) {  
327 - out_x = target_location.left() - im.cols;  
328 - if (out_x < 0) {  
329 - width_adjust = abs(out_x);  
330 - out_x = 0;  
331 - }  
332 - left_side = true;  
333 - }  
334 - // place right  
335 - else {  
336 - out_x = target_location.right();  
337 - int high = out_x + im.cols;  
338 - if (high >= src.m().cols) {  
339 - width_adjust = abs(high - src.m().cols + 1);  
340 - }  
341 - }  
342 -  
343 - cv::Mat outIm;  
344 - if (width_adjust)  
345 - {  
346 - outIm.create(dst.m().rows, dst.m().cols + width_adjust, CV_8UC3);  
347 - memset(outIm.data, 127, outIm.rows * outIm.cols * outIm.channels());  
348 -  
349 - Rect temp;  
350 -  
351 - if (left_side)  
352 - temp = Rect(abs(width_adjust), 0, dst.m().cols, dst.m().rows);  
353 -  
354 - else  
355 - temp = Rect(0, 0, dst.m().cols, dst.m().rows);  
356 -  
357 - dst.m().copyTo(outIm(temp));  
358 -  
359 - }  
360 - else  
361 - outIm = dst.m();  
362 -  
363 - if (clip_roi.height + target_location.top() >= outIm.rows)  
364 - {  
365 - clip_roi.height -= abs(outIm.rows - (clip_roi.height + target_location.top() ));  
366 - }  
367 - if (clip_roi.x + clip_roi.width >= im.cols) {  
368 - clip_roi.width -= abs(im.cols - (clip_roi.x + clip_roi.width + 1));  
369 - if (clip_roi.width < 0)  
370 - clip_roi.width = 1;  
371 - }  
372 -  
373 - if (clip_roi.y + clip_roi.height >= im.rows) {  
374 - clip_roi.height -= abs(im.rows - (clip_roi.y + clip_roi.height + 1));  
375 - }  
376 - if (clip_roi.x < 0)  
377 - clip_roi.x = 0;  
378 - if (clip_roi.y < 0)  
379 - clip_roi.y = 0;  
380 -  
381 - if (clip_roi.height < 0)  
382 - clip_roi.height = 0;  
383 -  
384 - if (clip_roi.width < 0)  
385 - clip_roi.width = 0;  
386 -  
387 -  
388 - if (clip_roi.y + clip_roi.height >= im.rows)  
389 - {  
390 - qDebug() << "Bad clip y" << clip_roi.y + clip_roi.height << im.rows;  
391 - }  
392 - if (clip_roi.x + clip_roi.width >= im.cols)  
393 - {  
394 - qDebug() << "Bad clip x" << clip_roi.x + clip_roi.width << im.cols;  
395 - }  
396 -  
397 - if (clip_roi.y < 0 || clip_roi.height < 0)  
398 - {  
399 - qDebug() << "bad clip y, low" << clip_roi.y << clip_roi.height;  
400 - qFatal("die");  
401 - }  
402 - if (clip_roi.x < 0 || clip_roi.width < 0)  
403 - {  
404 - qDebug() << "bad clip x, low" << clip_roi.x << clip_roi.width;  
405 - qFatal("die");  
406 - }  
407 -  
408 - target_roi.x = out_x;  
409 - target_roi.width = clip_roi.width;  
410 - target_roi.y = target_location.top();  
411 - target_roi.height = clip_roi.height;  
412 -  
413 -  
414 - im = im(clip_roi);  
415 -  
416 - if (target_roi.x < 0 || target_roi.x >= outIm.cols)  
417 - {  
418 - qDebug() << "Bad xdim in targetROI!" << target_roi.x << " out im x: " << outIm.cols;  
419 - qFatal("die");  
420 - }  
421 -  
422 - if (target_roi.x + target_roi.width < 0 || (target_roi.x + target_roi.width) >= outIm.cols)  
423 - {  
424 - qDebug() << "Bad xdim in targetROI!" << target_roi.x + target_roi.width;  
425 - qFatal("die");  
426 - }  
427 -  
428 - if (target_roi.y < 0 || target_roi.y >= outIm.rows)  
429 - {  
430 - qDebug() << "Bad ydim in targetROI!" << target_roi.y;  
431 - qFatal("die");  
432 - }  
433 -  
434 - if ((target_roi.y + target_roi.height) < 0 || (target_roi.y + target_roi.height) > outIm.rows)  
435 - {  
436 - qDebug() << "Bad ydim in targetROI!" << target_roi.y + target_roi.height;  
437 - qDebug() << "target_roi.y: " << target_roi.y << " height: " << target_roi.height;  
438 - qFatal("die");  
439 - }  
440 -  
441 -  
442 - std::vector<cv::Mat> channels;  
443 - cv::split(outIm, channels);  
444 -  
445 - std::vector<cv::Mat> patch_channels;  
446 - cv::split(im, patch_channels);  
447 -  
448 - for (size_t i=0; i < channels.size(); i++)  
449 - {  
450 - cv::addWeighted(channels[i](target_roi), 0, patch_channels[i % patch_channels.size()], 1, 0,channels[i](target_roi));  
451 - }  
452 - cv::merge(channels, outIm);  
453 - dst.m() = outIm;  
454 -  
455 - }  
456 -  
457 - void init()  
458 - {  
459 - opener = QSharedPointer<br::Transform>(br::Transform::make("Cache(Open)", NULL));  
460 - }  
461 -  
462 -};  
463 -  
464 -BR_REGISTER(Transform, AdjacentOverlayTransform)  
465 -  
466 -/*!  
467 - * \ingroup transforms  
468 - * \brief Draw a line representing the direction and magnitude of optical flow at the specified points.  
469 - * \author Austin Blanton \cite imaus10  
470 - */  
471 -class DrawOpticalFlow : public UntrainableTransform  
472 -{  
473 - Q_OBJECT  
474 - Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false)  
475 - BR_PROPERTY(QString, original, "original")  
476 -  
477 - void project(const Template &src, Template &dst) const  
478 - {  
479 - const Scalar color(0,255,0);  
480 - Mat flow = src.m();  
481 - dst = src;  
482 - if (!dst.file.contains(original)) qFatal("The original img must be saved in the metadata with SaveMat.");  
483 - dst.m() = dst.file.get<Mat>(original);  
484 - dst.file.remove(original);  
485 - foreach (const Point2f &pt, OpenCVUtils::toPoints(dst.file.points())) {  
486 - Point2f dxy = flow.at<Point2f>(pt.y, pt.x);  
487 - Point2f newPt(pt.x+dxy.x, pt.y+dxy.y);  
488 - line(dst, pt, newPt, color);  
489 - }  
490 - }  
491 -};  
492 -BR_REGISTER(Transform, DrawOpticalFlow)  
493 -  
494 -/*!  
495 - * \ingroup transforms  
496 - * \brief Fill in the segmentations or draw a line between intersecting segments.  
497 - * \author Austin Blanton \cite imaus10  
498 - */  
499 -class DrawSegmentation : public UntrainableTransform  
500 -{  
501 - Q_OBJECT  
502 - Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false)  
503 - BR_PROPERTY(bool, fillSegment, true)  
504 -  
505 - void project(const Template &src, Template &dst) const  
506 - {  
507 - if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours.");  
508 - Mat segments = src.file.get<Mat>("SegmentsMask");  
509 - int numSegments = src.file.get<int>("NumSegments");  
510 -  
511 - dst.file = src.file;  
512 - Mat drawn = fillSegment ? Mat(segments.size(), CV_8UC3, Scalar::all(0)) : src.m();  
513 -  
514 - for (int i=1; i<numSegments+1; i++) {  
515 - Mat mask = segments == i;  
516 - if (fillSegment) { // color the whole segment  
517 - // set to a random color - get ready for a craaaazy acid trip  
518 - int b = theRNG().uniform(0, 255);  
519 - int g = theRNG().uniform(0, 255);  
520 - int r = theRNG().uniform(0, 255);  
521 - drawn.setTo(Scalar(r,g,b), mask);  
522 - } else { // draw lines where there's a color change  
523 - vector<vector<Point> > contours;  
524 - Scalar color(0,255,0);  
525 - findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);  
526 - drawContours(drawn, contours, -1, color);  
527 - }  
528 - }  
529 -  
530 - dst.m() = drawn;  
531 - }  
532 -};  
533 -BR_REGISTER(Transform, DrawSegmentation)  
534 -  
535 -/*!  
536 - * \ingroup transforms  
537 - * \brief Write all mats to disk as images.  
538 - * \author Brendan Klare \cite bklare  
539 - */  
540 -class WriteImageTransform : public TimeVaryingTransform  
541 -{  
542 - Q_OBJECT  
543 - Q_PROPERTY(QString outputDirectory READ get_outputDirectory WRITE set_outputDirectory RESET reset_outputDirectory STORED false)  
544 - Q_PROPERTY(QString imageName READ get_imageName WRITE set_imageName RESET reset_imageName STORED false)  
545 - Q_PROPERTY(QString imgExtension READ get_imgExtension WRITE set_imgExtension RESET reset_imgExtension STORED false)  
546 - BR_PROPERTY(QString, outputDirectory, "Temp")  
547 - BR_PROPERTY(QString, imageName, "image")  
548 - BR_PROPERTY(QString, imgExtension, "jpg")  
549 -  
550 - int cnt;  
551 -  
552 - void init() {  
553 - cnt = 0;  
554 - if (! QDir(outputDirectory).exists())  
555 - QDir().mkdir(outputDirectory);  
556 - }  
557 -  
558 - void projectUpdate(const Template &src, Template &dst)  
559 - {  
560 - dst = src;  
561 - OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, 10, QChar('0')).arg(imgExtension));  
562 - }  
563 -  
564 -};  
565 -BR_REGISTER(Transform, WriteImageTransform)  
566 -  
567 -  
568 -/**  
569 - * @brief The MeanImageTransform class computes the average template/image  
570 - * and save the result as an encoded image.  
571 - */  
572 -class MeanImageTransform : public TimeVaryingTransform  
573 -{  
574 - Q_OBJECT  
575 -  
576 - Q_PROPERTY(QString imgname READ get_imgname WRITE set_imgname RESET reset_imgname STORED false)  
577 - Q_PROPERTY(QString ext READ get_ext WRITE set_ext RESET reset_ext STORED false)  
578 -  
579 - BR_PROPERTY(QString, imgname, "average")  
580 - BR_PROPERTY(QString, ext, "jpg")  
581 -  
582 - Mat average;  
583 - int cnt;  
584 -  
585 - void init()  
586 - {  
587 - cnt = 0;  
588 - }  
589 -  
590 - void projectUpdate(const Template &src, Template &dst)  
591 - {  
592 - dst = src;  
593 - if (cnt == 0) {  
594 - if (src.m().channels() == 1)  
595 - average = Mat::zeros(dst.m().size(),CV_64FC1);  
596 - else if (src.m().channels() == 3)  
597 - average = Mat::zeros(dst.m().size(),CV_64FC3);  
598 - else  
599 - qFatal("Unsupported number of channels");  
600 - }  
601 -  
602 - Mat temp;  
603 - if (src.m().channels() == 1) {  
604 - src.m().convertTo(temp, CV_64FC1);  
605 - average += temp;  
606 - } else if (src.m().channels() == 3) {  
607 - src.m().convertTo(temp, CV_64FC3);  
608 - average += temp;  
609 - } else  
610 - qFatal("Unsupported number of channels");  
611 -  
612 - cnt++;  
613 - }  
614 -  
615 - virtual void finalize(TemplateList &output)  
616 - {  
617 - average /= float(cnt);  
618 - imwrite(QString("%1.%2").arg(imgname).arg(ext).toStdString(), average);  
619 - output = TemplateList();  
620 - }  
621 -  
622 -  
623 -public:  
624 - MeanImageTransform() : TimeVaryingTransform(false, false) {}  
625 -};  
626 -  
627 -BR_REGISTER(Transform, MeanImageTransform)  
628 -  
629 -  
630 -// TODO: re-implement EditTransform using Qt  
631 -#if 0  
632 -/*!  
633 - * \ingroup transforms  
634 - * \brief Remove landmarks.  
635 - * \author Josh Klontz \cite jklontz  
636 - */  
637 -class EditTransform : public UntrainableTransform  
638 -{  
639 - Q_OBJECT  
640 -  
641 - Transform *draw;  
642 - static Template currentTemplate;  
643 - static QMutex currentTemplateLock;  
644 -  
645 - void init()  
646 - {  
647 - draw = make("Draw");  
648 - Globals->setProperty("parallelism", "0"); // Can only work in single threaded mode  
649 - }  
650 -  
651 - void project(const Template &src, Template &dst) const  
652 - {  
653 - dst = src;  
654 -  
655 - if (Globals->parallelism) {  
656 - qWarning("Edit::project() only works in single threaded mode.");  
657 - return;  
658 - }  
659 -  
660 - currentTemplateLock.lock();  
661 - currentTemplate = src;  
662 - OpenCVUtils::showImage(src, "Edit", false);  
663 - setMouseCallback("Edit", mouseCallback, (void*)this);  
664 - mouseEvent(0, 0, 0, 0);  
665 - waitKey(-1);  
666 - dst = currentTemplate;  
667 - currentTemplateLock.unlock();  
668 - }  
669 -  
670 - static void mouseCallback(int event, int x, int y, int flags, void *userdata)  
671 - {  
672 - ((const EditTransform*)userdata)->mouseEvent(event, x, y, flags);  
673 - }  
674 -  
675 - void mouseEvent(int event, int x, int y, int flags) const  
676 - {  
677 - (void) event;  
678 - if (flags) {  
679 - QList<QRectF> rects = currentTemplate.file.rects();  
680 - for (int i=rects.size()-1; i>=0; i--)  
681 - if (rects[i].contains(x,y))  
682 - rects.removeAt(i);  
683 - currentTemplate.file.setRects(rects);  
684 - }  
685 -  
686 - Template temp;  
687 - draw->project(currentTemplate, temp);  
688 - OpenCVUtils::showImage(temp, "Edit", false);  
689 - }  
690 -};  
691 -  
692 -Template EditTransform::currentTemplate;  
693 -QMutex EditTransform::currentTemplateLock;  
694 -  
695 -BR_REGISTER(Transform, EditTransform)  
696 -#endif  
697 -  
698 -} // namespace br  
699 -  
700 -#include "draw.moc"  
openbr/plugins/eigen3.cmake deleted
1 -set(BR_WITH_EIGEN3 ON CACHE BOOL "Build Eigen3 plugins")  
2 -  
3 -if(${BR_WITH_EIGEN3})  
4 - find_package(Eigen3 REQUIRED)  
5 - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/eigen3.cpp)  
6 - install(FILES ${EIGEN3_LICENSE} RENAME Eigen3 DESTINATION share/openbr/licenses)  
7 -endif()