Commit 9e56c8699bff03b7101df5837ef56b8584b2f8ea
Merge branch 'dlib' of https://github.com/biometrics/openbr into dlib
Showing
348 changed files
with
22214 additions
and
13804 deletions
Too many changes.
To preserve performance only 100 of 348 files are displayed.
3rdparty/stasm4.0.0/CMakeLists.txt
| ... | ... | @@ -13,7 +13,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO |
| 13 | 13 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/") |
| 14 | 14 | |
| 15 | 15 | # Find Qt 5.0.2 |
| 16 | -set(QT_DEPENDENCIES Concurrent Core Gui Network Sql Svg Widgets Xml) | |
| 16 | +set(QT_DEPENDENCIES Concurrent Core Gui Network Sql Widgets Xml) | |
| 17 | 17 | foreach(QT_DEPENDENCY ${QT_DEPENDENCIES}) |
| 18 | 18 | find_package(Qt5${QT_DEPENDENCY}) |
| 19 | 19 | endforeach() | ... | ... |
CMakeLists.txt
| ... | ... | @@ -80,7 +80,7 @@ endif() |
| 80 | 80 | set(QT_DEPENDENCIES Concurrent Core) |
| 81 | 81 | option(BR_EMBEDDED "Limit software dependencies") |
| 82 | 82 | if(NOT ${BR_EMBEDDED}) |
| 83 | - set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Gui Network Sql Svg Widgets Xml) | |
| 83 | + set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Gui Network Sql Widgets Xml) | |
| 84 | 84 | endif() |
| 85 | 85 | foreach(QT_DEPENDENCY ${QT_DEPENDENCIES}) |
| 86 | 86 | find_package(Qt5${QT_DEPENDENCY}) |
| ... | ... | @@ -89,7 +89,7 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Qt5Core_QTMAIN_LIBRARIES}) |
| 89 | 89 | |
| 90 | 90 | # Find OpenCV |
| 91 | 91 | find_package(OpenCV 2.4.5 REQUIRED) |
| 92 | -set(OPENCV_DEPENDENCIES opencv_calib3d opencv_core opencv_features2d opencv_flann opencv_gpu opencv_highgui opencv_imgproc opencv_ml opencv_nonfree opencv_objdetect opencv_photo opencv_video) | |
| 92 | +set(OPENCV_DEPENDENCIES opencv_calib3d opencv_core opencv_features2d opencv_flann opencv_gpu opencv_highgui opencv_imgproc opencv_ml opencv_nonfree opencv_objdetect opencv_photo opencv_video opencv_videostab opencv_superres opencv_stitching opencv_ocl opencv_legacy opencv_contrib) | |
| 93 | 93 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) |
| 94 | 94 | |
| 95 | 95 | # Find Alphanum | ... | ... |
openbr/core/cluster.cpp
| ... | ... | @@ -82,7 +82,7 @@ float normalizedROD(const Neighborhood &neighborhood, int a, int b) |
| 82 | 82 | return 1.f * (distanceA + distanceB) / std::min(indexA+1, indexB+1); |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | -Neighborhood getNeighborhood(const QStringList &simmats) | |
| 85 | +Neighborhood br::knnFromSimmat(const QList<cv::Mat> &simmats, int k) | |
| 86 | 86 | { |
| 87 | 87 | Neighborhood neighborhood; |
| 88 | 88 | |
| ... | ... | @@ -99,9 +99,7 @@ Neighborhood getNeighborhood(const QStringList &simmats) |
| 99 | 99 | int currentRows = -1; |
| 100 | 100 | int columnOffset = 0; |
| 101 | 101 | for (int j=0; j<numGalleries; j++) { |
| 102 | - QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmats[i*numGalleries+j])); | |
| 103 | - br::Template t = format->read(); | |
| 104 | - cv::Mat m = t.m(); | |
| 102 | + cv::Mat m = simmats[i * numGalleries + j]; | |
| 105 | 103 | if (j==0) { |
| 106 | 104 | currentRows = m.rows; |
| 107 | 105 | allNeighbors.resize(currentRows); |
| ... | ... | @@ -132,37 +130,164 @@ Neighborhood getNeighborhood(const QStringList &simmats) |
| 132 | 130 | // Keep the top matches |
| 133 | 131 | for (int j=0; j<allNeighbors.size(); j++) { |
| 134 | 132 | Neighbors &val = allNeighbors[j]; |
| 135 | - const int cutoff = 20; // Somewhat arbitrary number of neighbors to keep | |
| 133 | + const int cutoff = k; // Number of neighbors to keep | |
| 136 | 134 | int keep = std::min(cutoff, val.size()); |
| 137 | 135 | std::partial_sort(val.begin(), val.begin()+keep, val.end(), compareNeighbors); |
| 138 | 136 | neighborhood.append((Neighbors)val.mid(0, keep)); |
| 139 | 137 | } |
| 140 | 138 | } |
| 141 | 139 | |
| 142 | - // Normalize scores | |
| 143 | - for (int i=0; i<neighborhood.size(); i++) { | |
| 144 | - Neighbors &neighbors = neighborhood[i]; | |
| 145 | - for (int j=0; j<neighbors.size(); j++) { | |
| 146 | - Neighbor &neighbor = neighbors[j]; | |
| 147 | - if (neighbor.second == -std::numeric_limits<float>::infinity()) | |
| 148 | - neighbor.second = 0; | |
| 149 | - else if (neighbor.second == std::numeric_limits<float>::infinity()) | |
| 150 | - neighbor.second = 1; | |
| 151 | - else | |
| 152 | - neighbor.second = (neighbor.second - globalMin) / (globalMax - globalMin); | |
| 153 | - } | |
| 140 | + return neighborhood; | |
| 141 | +} | |
| 142 | + | |
| 143 | +// generate k-NN graph from pre-computed similarity matrices | |
| 144 | +Neighborhood br::knnFromSimmat(const QStringList &simmats, int k) | |
| 145 | +{ | |
| 146 | + QList<cv::Mat> mats; | |
| 147 | + foreach (const QString &simmat, simmats) { | |
| 148 | + QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmat)); | |
| 149 | + br::Template t = format->read(); | |
| 150 | + mats.append(t); | |
| 151 | + } | |
| 152 | + return knnFromSimmat(mats, k); | |
| 153 | +} | |
| 154 | + | |
| 155 | +TemplateList knnFromGallery(const QString & galleryName, bool inMemory, const QString & outFile, int k) | |
| 156 | +{ | |
| 157 | + QSharedPointer<Transform> comparison = Transform::fromComparison(Globals->algorithm); | |
| 158 | + | |
| 159 | + Gallery *tempG = Gallery::make(galleryName); | |
| 160 | + qint64 total = tempG->totalSize(); | |
| 161 | + delete tempG; | |
| 162 | + comparison->setPropertyRecursive("galleryName", galleryName+"[dropMetadata=true]"); | |
| 163 | + | |
| 164 | + bool multiProcess = Globals->file.getBool("multiProcess", false); | |
| 165 | + if (multiProcess) | |
| 166 | + comparison = QSharedPointer<Transform> (br::wrapTransform(comparison.data(), "ProcessWrapper")); | |
| 167 | + | |
| 168 | + QScopedPointer<Transform> collect(Transform::make("CollectNN+ProgressCounter+Discard", NULL)); | |
| 169 | + collect->setPropertyRecursive("totalProgress", total); | |
| 170 | + collect->setPropertyRecursive("keep", k); | |
| 171 | + | |
| 172 | + QList<Transform *> tforms; | |
| 173 | + tforms.append(comparison.data()); | |
| 174 | + tforms.append(collect.data()); | |
| 175 | + | |
| 176 | + QScopedPointer<Transform> compareCollect(br::pipeTransforms(tforms)); | |
| 177 | + | |
| 178 | + QSharedPointer <Transform> projector; | |
| 179 | + if (inMemory) | |
| 180 | + projector = QSharedPointer<Transform> (br::wrapTransform(compareCollect.data(), "Stream(readMode=StreamGallery, endPoint=Discard")); | |
| 181 | + else | |
| 182 | + projector = QSharedPointer<Transform> (br::wrapTransform(compareCollect.data(), "Stream(readMode=StreamGallery, endPoint=LogNN("+outFile+")+DiscardTemplates)")); | |
| 183 | + | |
| 184 | + TemplateList input; | |
| 185 | + input.append(Template(galleryName)); | |
| 186 | + TemplateList output; | |
| 187 | + | |
| 188 | + projector->init(); | |
| 189 | + projector->projectUpdate(input, output); | |
| 190 | + | |
| 191 | + return output; | |
| 192 | +} | |
| 193 | + | |
| 194 | +// Generate k-NN graph from a gallery, using the current algorithm for comparison. | |
| 195 | +// Direct serialization to file system, k-NN graph is not retained in memory | |
| 196 | +void br::knnFromGallery(const QString &galleryName, const QString &outFile, int k) | |
| 197 | +{ | |
| 198 | + knnFromGallery(galleryName, false, outFile, k); | |
| 199 | +} | |
| 200 | + | |
| 201 | +// In-memory graph construction | |
| 202 | +Neighborhood br::knnFromGallery(const QString &gallery, int k) | |
| 203 | +{ | |
| 204 | + // Nearest neighbor data current stored as template metadata, so retrieve it | |
| 205 | + TemplateList res = knnFromGallery(gallery, true, "", k); | |
| 206 | + | |
| 207 | + Neighborhood neighborhood; | |
| 208 | + foreach (const Template &t, res) { | |
| 209 | + Neighbors neighbors = t.file.get<Neighbors>("neighbors"); | |
| 210 | + neighbors.append(neighbors); | |
| 154 | 211 | } |
| 155 | 212 | |
| 156 | 213 | return neighborhood; |
| 157 | 214 | } |
| 158 | 215 | |
| 159 | -// Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011 | |
| 160 | -br::Clusters br::ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv) | |
| 216 | +Neighborhood br::loadkNN(const QString &infile) | |
| 217 | +{ | |
| 218 | + Neighborhood neighborhood; | |
| 219 | + QFile file(infile); | |
| 220 | + bool success = file.open(QFile::ReadOnly); | |
| 221 | + if (!success) qFatal("Failed to open %s for reading.", qPrintable(infile)); | |
| 222 | + QStringList lines = QString(file.readAll()).split("\n"); | |
| 223 | + file.close(); | |
| 224 | + int min_idx = INT_MAX; | |
| 225 | + int max_idx = -1; | |
| 226 | + int count = 0; | |
| 227 | + | |
| 228 | + foreach (const QString &line, lines) { | |
| 229 | + Neighbors neighbors; | |
| 230 | + count++; | |
| 231 | + if (line.trimmed().isEmpty()) { | |
| 232 | + neighborhood.append(neighbors); | |
| 233 | + continue; | |
| 234 | + } | |
| 235 | + bool off = false; | |
| 236 | + QStringList list = line.trimmed().split(",", QString::SkipEmptyParts); | |
| 237 | + foreach (const QString &item, list) { | |
| 238 | + QStringList parts = item.trimmed().split(":", QString::SkipEmptyParts); | |
| 239 | + bool intOK = true; | |
| 240 | + bool floatOK = true; | |
| 241 | + int idx = parts[0].toInt(&intOK); | |
| 242 | + float score = parts[1].toFloat(&floatOK); | |
| 243 | + | |
| 244 | + if (idx > max_idx) | |
| 245 | + max_idx = idx; | |
| 246 | + if (idx <min_idx) | |
| 247 | + min_idx = idx; | |
| 248 | + | |
| 249 | + if (idx >= lines.size()) { | |
| 250 | + off = true; | |
| 251 | + continue; | |
| 252 | + } | |
| 253 | + neighbors.append(qMakePair(idx, score)); | |
| 254 | + | |
| 255 | + | |
| 256 | + if (!intOK && floatOK) | |
| 257 | + qFatal("Failed to parse word: %s", qPrintable(item)); | |
| 258 | + } | |
| 259 | + neighborhood.append(neighbors); | |
| 260 | + } | |
| 261 | + return neighborhood; | |
| 262 | +} | |
| 263 | + | |
| 264 | +bool br::savekNN(const Neighborhood &neighborhood, const QString &outfile) | |
| 265 | +{ | |
| 266 | + QFile file(outfile); | |
| 267 | + bool success = file.open(QFile::WriteOnly); | |
| 268 | + if (!success) qFatal("Failed to open %s for writing.", qPrintable(outfile)); | |
| 269 | + | |
| 270 | + foreach (Neighbors neighbors, neighborhood) { | |
| 271 | + QString aLine; | |
| 272 | + if (!neighbors.empty()) | |
| 273 | + { | |
| 274 | + aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second)); | |
| 275 | + for (int i=1; i < neighbors.size();i++) { | |
| 276 | + aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second)); | |
| 277 | + } | |
| 278 | + } | |
| 279 | + aLine += "\n"; | |
| 280 | + file.write(qPrintable(aLine)); | |
| 281 | + } | |
| 282 | + file.close(); | |
| 283 | + return true; | |
| 284 | +} | |
| 285 | + | |
| 286 | + | |
| 287 | +// Rank-order clustering on a pre-computed k-NN graph | |
| 288 | +Clusters br::ClusterGraph(Neighborhood neighborhood, float aggressiveness, const QString &csv) | |
| 161 | 289 | { |
| 162 | - qDebug("Clustering %d simmat(s), aggressiveness %f", simmats.size(), aggressiveness); | |
| 163 | 290 | |
| 164 | - // Read in gallery parts, keeping top neighbors of each template | |
| 165 | - Neighborhood neighborhood = getNeighborhood(simmats); | |
| 166 | 291 | const int cutoff = neighborhood.first().size(); |
| 167 | 292 | const float threshold = 3*cutoff/4 * aggressiveness/5; |
| 168 | 293 | |
| ... | ... | @@ -239,9 +364,39 @@ br::Clusters br::ClusterGallery(const QStringList &simmats, float aggressiveness |
| 239 | 364 | neighborhood = newNeighborhood; |
| 240 | 365 | } |
| 241 | 366 | |
| 242 | - // Save clusters | |
| 243 | 367 | if (!csv.isEmpty()) |
| 244 | 368 | WriteClusters(clusters, csv); |
| 369 | + | |
| 370 | + return clusters; | |
| 371 | +} | |
| 372 | + | |
| 373 | +Clusters br::ClusterGraph(const QString & knnName, float aggressiveness, const QString &csv) | |
| 374 | +{ | |
| 375 | + Neighborhood neighbors = loadkNN(knnName); | |
| 376 | + return ClusterGraph(neighbors, aggressiveness, csv); | |
| 377 | +} | |
| 378 | + | |
| 379 | +// Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011 | |
| 380 | +br::Clusters br::ClusterSimmat(const QList<cv::Mat> &simmats, float aggressiveness, const QString &csv) | |
| 381 | +{ | |
| 382 | + qDebug("Clustering %d simmat(s), aggressiveness %f", simmats.size(), aggressiveness); | |
| 383 | + | |
| 384 | + // Read in gallery parts, keeping top neighbors of each template | |
| 385 | + Neighborhood neighborhood = knnFromSimmat(simmats); | |
| 386 | + | |
| 387 | + return ClusterGraph(neighborhood, aggressiveness, csv); | |
| 388 | +} | |
| 389 | + | |
| 390 | +br::Clusters br::ClusterSimmat(const QStringList &simmats, float aggressiveness, const QString &csv) | |
| 391 | +{ | |
| 392 | + QList<cv::Mat> mats; | |
| 393 | + foreach (const QString &simmat, simmats) { | |
| 394 | + QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmat)); | |
| 395 | + br::Template t = format->read(); | |
| 396 | + mats.append(t); | |
| 397 | + } | |
| 398 | + | |
| 399 | + Clusters clusters = ClusterSimmat(mats, aggressiveness, csv); | |
| 245 | 400 | return clusters; |
| 246 | 401 | } |
| 247 | 402 | ... | ... |
openbr/core/cluster.h
| ... | ... | @@ -21,15 +21,46 @@ |
| 21 | 21 | #include <QString> |
| 22 | 22 | #include <QStringList> |
| 23 | 23 | #include <QVector> |
| 24 | +#include <openbr/openbr_plugin.h> | |
| 25 | +#include <openbr/plugins/openbr_internal.h> | |
| 24 | 26 | |
| 25 | 27 | namespace br |
| 26 | 28 | { |
| 27 | 29 | typedef QList<int> Cluster; // List of indices into galleries |
| 28 | 30 | typedef QVector<Cluster> Clusters; |
| 29 | 31 | |
| 30 | - Clusters ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv); | |
| 32 | + // generate k-NN graph from pre-computed similarity matrices | |
| 33 | + Neighborhood knnFromSimmat(const QStringList &simmats, int k = 20); | |
| 34 | + Neighborhood knnFromSimmat(const QList<cv::Mat> &simmats, int k = 20); | |
| 35 | + | |
| 36 | + // Generate k-NN graph from a gallery, using the current algorithm for comparison. | |
| 37 | + // direct serialization to file system. | |
| 38 | + void knnFromGallery(const QString &galleryName, const QString & outFile, int k = 20); | |
| 39 | + // in memory graph computation | |
| 40 | + Neighborhood knnFromGallery(const QString &gallery, int k = 20); | |
| 41 | + | |
| 42 | + // Load k-NN graph from a file with the following ascii format: | |
| 43 | + // One line per sample, each line lists the top k neighbors for the sample as follows: | |
| 44 | + // index1:score1,index2:score2,...,indexk:scorek | |
| 45 | + Neighborhood loadkNN(const QString &fname); | |
| 46 | + | |
| 47 | + // Save k-NN graph to file | |
| 48 | + bool savekNN(const Neighborhood &neighborhood, const QString &outfile); | |
| 49 | + | |
| 50 | + // Rank-order clustering on a pre-computed k-NN graph | |
| 51 | + Clusters ClusterGraph(Neighborhood neighbors, float aggresssiveness, const QString &csv = ""); | |
| 52 | + Clusters ClusterGraph(const QString & knnName, float aggressiveness, const QString &csv = ""); | |
| 53 | + | |
| 54 | + // Given a similarity matrix, compute the k-NN graph, then perform rank-order clustering. | |
| 55 | + Clusters ClusterSimmat(const QList<cv::Mat> &simmats, float aggressiveness, const QString &csv = ""); | |
| 56 | + Clusters ClusterSimmat(const QStringList &simmats, float aggressiveness, const QString &csv = ""); | |
| 57 | + | |
| 58 | + // evaluate clustering results in csv, reading ground truth data from gallery input, using truth_property | |
| 59 | + // as the key for ground truth labels. | |
| 31 | 60 | void EvalClustering(const QString &csv, const QString &input, QString truth_property); |
| 32 | 61 | |
| 62 | + // Read/write clusters from a text format, 1 line = 1 cluster, each line contains comma separated list | |
| 63 | + // of assigned indices. | |
| 33 | 64 | Clusters ReadClusters(const QString &csv); |
| 34 | 65 | void WriteClusters(const Clusters &clusters, const QString &csv); |
| 35 | 66 | } | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -138,6 +138,13 @@ struct AlgorithmCore |
| 138 | 138 | |
| 139 | 139 | void load(const QString &model) |
| 140 | 140 | { |
| 141 | + // since we are loading an existing model, add its path to the search list for submodels | |
| 142 | + // assuming it is not already present. | |
| 143 | + QFileInfo finfo(model); | |
| 144 | + QString path = finfo.absolutePath(); | |
| 145 | + if (!Globals->modelSearch.contains(path)) | |
| 146 | + Globals->modelSearch.append(path); | |
| 147 | + | |
| 141 | 148 | QtUtils::BlockCompression compressedRead; |
| 142 | 149 | QFile inFile(model); |
| 143 | 150 | compressedRead.setBasis(&inFile); |
| ... | ... | @@ -762,5 +769,15 @@ QSharedPointer<br::Distance> br::Distance::fromAlgorithm(const QString &algorith |
| 762 | 769 | return AlgorithmManager::getAlgorithm(algorithm)->distance; |
| 763 | 770 | } |
| 764 | 771 | |
| 772 | +class pathInitializer : public Initializer | |
| 773 | +{ | |
| 774 | + Q_OBJECT | |
| 775 | + void initialize() const | |
| 776 | + { | |
| 777 | + Globals->modelSearch.append(Globals->sdkPath + "/share/openbr/models/transforms/"); | |
| 778 | + } | |
| 779 | + | |
| 780 | +}; | |
| 781 | +BR_REGISTER(Initializer, pathInitializer) | |
| 765 | 782 | |
| 766 | 783 | #include "core.moc" | ... | ... |
openbr/core/qtutils.cpp
| ... | ... | @@ -500,14 +500,15 @@ QString getAbsolutePath(const QString &filename) |
| 500 | 500 | return QFileInfo(filename).absoluteFilePath(); |
| 501 | 501 | } |
| 502 | 502 | |
| 503 | +const int base_block = 100000000; | |
| 504 | + | |
| 503 | 505 | BlockCompression::BlockCompression(QIODevice *_basis) |
| 504 | 506 | { |
| 505 | - blockSize = 100000000; | |
| 507 | + blockSize = base_block; | |
| 506 | 508 | setBasis(_basis); |
| 507 | 509 | } |
| 508 | 510 | |
| 509 | -BlockCompression::BlockCompression() { blockSize = 100000000; }; | |
| 510 | - | |
| 511 | +BlockCompression::BlockCompression() { blockSize = base_block;}; | |
| 511 | 512 | |
| 512 | 513 | bool BlockCompression::open(QIODevice::OpenMode mode) |
| 513 | 514 | { |
| ... | ... | @@ -521,14 +522,22 @@ bool BlockCompression::open(QIODevice::OpenMode mode) |
| 521 | 522 | blockWriter.setDevice(basis); |
| 522 | 523 | |
| 523 | 524 | if (mode & QIODevice::WriteOnly) { |
| 524 | - precompressedBlockWriter = new QBuffer; | |
| 525 | - precompressedBlockWriter->open(QIODevice::ReadWrite); | |
| 525 | + precompressedBlockWriter.open(QIODevice::WriteOnly); | |
| 526 | 526 | } |
| 527 | 527 | else if (mode & QIODevice::ReadOnly) { |
| 528 | + | |
| 529 | + // Read an initial compressed block from the underlying QIODevice, | |
| 530 | + // decompress, and set up a reader on it | |
| 528 | 531 | QByteArray compressedBlock; |
| 529 | - blockReader >> compressedBlock; | |
| 532 | + quint32 block_size; | |
| 533 | + blockReader >> block_size; | |
| 534 | + compressedBlock.resize(block_size); | |
| 535 | + int read_count = blockReader.readRawData(compressedBlock.data(), block_size); | |
| 536 | + if (read_count != block_size) | |
| 537 | + qFatal("Failed to read initial block"); | |
| 530 | 538 | |
| 531 | 539 | decompressedBlock = qUncompress(compressedBlock); |
| 540 | + | |
| 532 | 541 | decompressedBlockReader.setBuffer(&decompressedBlock); |
| 533 | 542 | decompressedBlockReader.open(QIODevice::ReadOnly); |
| 534 | 543 | } |
| ... | ... | @@ -538,11 +547,17 @@ bool BlockCompression::open(QIODevice::OpenMode mode) |
| 538 | 547 | |
| 539 | 548 | void BlockCompression::close() |
| 540 | 549 | { |
| 541 | - // flush output buffer | |
| 542 | - if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter) { | |
| 543 | - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1); | |
| 544 | - blockWriter << compressedBlock; | |
| 550 | + // flush output buffer, since we may have a partial block which hasn't been | |
| 551 | + // written to disk yet. | |
| 552 | + if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter.isOpen()) { | |
| 553 | + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer()); | |
| 554 | + precompressedBlockWriter.close(); | |
| 555 | + | |
| 556 | + quint32 bsize= compressedBlock.size(); | |
| 557 | + blockWriter << bsize; | |
| 558 | + blockWriter.writeRawData(compressedBlock.data(), compressedBlock.size()); | |
| 545 | 559 | } |
| 560 | + // close the underlying device. | |
| 546 | 561 | basis->close(); |
| 547 | 562 | } |
| 548 | 563 | |
| ... | ... | @@ -557,8 +572,10 @@ void BlockCompression::setBasis(QIODevice *_basis) |
| 557 | 572 | // block from basis |
| 558 | 573 | qint64 BlockCompression::readData(char *data, qint64 remaining) |
| 559 | 574 | { |
| 575 | + qint64 initial = remaining; | |
| 560 | 576 | qint64 read = 0; |
| 561 | 577 | while (remaining > 0) { |
| 578 | + // attempt to read the target amount of data | |
| 562 | 579 | qint64 single_read = decompressedBlockReader.read(data, remaining); |
| 563 | 580 | if (single_read == -1) |
| 564 | 581 | qFatal("miss read"); |
| ... | ... | @@ -567,13 +584,21 @@ qint64 BlockCompression::readData(char *data, qint64 remaining) |
| 567 | 584 | read += single_read; |
| 568 | 585 | data += single_read; |
| 569 | 586 | |
| 570 | - // need a new block | |
| 587 | + // need a new block if we didn't get enough bytes from the previous read | |
| 571 | 588 | if (remaining > 0) { |
| 572 | 589 | QByteArray compressedBlock; |
| 573 | - blockReader >> compressedBlock; | |
| 574 | - if (compressedBlock.size() == 0) { | |
| 575 | - return read; | |
| 576 | - } | |
| 590 | + | |
| 591 | + // read the size of the next block | |
| 592 | + quint32 block_size; | |
| 593 | + blockReader >> block_size; | |
| 594 | + if (block_size == 0) | |
| 595 | + break; | |
| 596 | + | |
| 597 | + compressedBlock.resize(block_size); | |
| 598 | + int actualRead = blockReader.readRawData(compressedBlock.data(), block_size); | |
| 599 | + if (actualRead != block_size) | |
| 600 | + qFatal("Bad read on nominal block size: %d, only got %d", block_size, remaining); | |
| 601 | + | |
| 577 | 602 | decompressedBlock = qUncompress(compressedBlock); |
| 578 | 603 | |
| 579 | 604 | decompressedBlockReader.close(); |
| ... | ... | @@ -581,7 +606,12 @@ qint64 BlockCompression::readData(char *data, qint64 remaining) |
| 581 | 606 | decompressedBlockReader.open(QIODevice::ReadOnly); |
| 582 | 607 | } |
| 583 | 608 | } |
| 584 | - return blockReader.atEnd() && !basis->isReadable() ? -1 : read; | |
| 609 | + | |
| 610 | + bool condition = blockReader.atEnd() && !basis->isReadable() ; | |
| 611 | + if (condition) | |
| 612 | + qWarning("Returning -1 from read"); | |
| 613 | + | |
| 614 | + return condition ? -1 : read; | |
| 585 | 615 | } |
| 586 | 616 | |
| 587 | 617 | bool BlockCompression::isSequential() const |
| ... | ... | @@ -591,36 +621,57 @@ bool BlockCompression::isSequential() const |
| 591 | 621 | |
| 592 | 622 | qint64 BlockCompression::writeData(const char *data, qint64 remaining) |
| 593 | 623 | { |
| 624 | + const char * endPoint = data + remaining; | |
| 625 | + qint64 initial = remaining; | |
| 626 | + | |
| 594 | 627 | qint64 written = 0; |
| 595 | 628 | |
| 596 | 629 | while (remaining > 0) { |
| 597 | 630 | // how much more can be put in this buffer? |
| 598 | - qint64 capacity = blockSize - precompressedBlockWriter->pos(); | |
| 631 | + qint64 capacity = blockSize - precompressedBlockWriter.pos(); | |
| 632 | + if (capacity < 0) | |
| 633 | + qFatal("Negative capacity!!!"); | |
| 599 | 634 | |
| 600 | 635 | // don't try to write beyond capacity |
| 601 | 636 | qint64 write_size = qMin(capacity, remaining); |
| 602 | 637 | |
| 603 | - qint64 singleWrite = precompressedBlockWriter->write(data, write_size); | |
| 604 | - // ignore the error case here, we consdier basis's failure mode the real | |
| 605 | - // end case | |
| 638 | + qint64 singleWrite = precompressedBlockWriter.write(data, write_size); | |
| 639 | + | |
| 606 | 640 | if (singleWrite == -1) |
| 607 | - singleWrite = 0; | |
| 641 | + qFatal("matrix write failure?"); | |
| 608 | 642 | |
| 609 | 643 | remaining -= singleWrite; |
| 610 | 644 | data += singleWrite; |
| 611 | 645 | written += singleWrite; |
| 646 | + if (data > endPoint) | |
| 647 | + qFatal("Wrote past the end"); | |
| 612 | 648 | |
| 613 | 649 | if (remaining > 0) { |
| 614 | - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1); | |
| 650 | + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer(), -1); | |
| 615 | 651 | |
| 616 | - if (compressedBlock.size() != 0) | |
| 617 | - blockWriter << compressedBlock; | |
| 652 | + if (precompressedBlockWriter.buffer().size() != 0) { | |
| 653 | + quint32 block_size = compressedBlock.size(); | |
| 654 | + blockWriter << block_size; | |
| 618 | 655 | |
| 619 | - delete precompressedBlockWriter; | |
| 620 | - precompressedBlockWriter = new QBuffer; | |
| 621 | - precompressedBlockWriter->open(QIODevice::ReadWrite); | |
| 656 | + int write_count = blockWriter.writeRawData(compressedBlock.data(), block_size); | |
| 657 | + if (write_count != block_size) | |
| 658 | + qFatal("Didn't write enough data"); | |
| 659 | + } | |
| 660 | + else | |
| 661 | + qFatal("serialized empty compressed block (?)"); | |
| 662 | + | |
| 663 | + precompressedBlockWriter.close(); | |
| 664 | + precompressedBlockWriter.open(QIODevice::WriteOnly); | |
| 622 | 665 | } |
| 623 | 666 | } |
| 667 | + | |
| 668 | + if (written != initial) | |
| 669 | + qFatal("didn't write enough bytes"); | |
| 670 | + | |
| 671 | + bool condition = basis->isWritable(); | |
| 672 | + if (!condition) | |
| 673 | + qWarning("Returning -1 from write"); | |
| 674 | + | |
| 624 | 675 | return basis->isWritable() ? written : -1; |
| 625 | 676 | } |
| 626 | 677 | ... | ... |
openbr/core/qtutils.h
| ... | ... | @@ -122,7 +122,7 @@ namespace QtUtils |
| 122 | 122 | |
| 123 | 123 | // write to a QByteArray, when max block sized is reached, compress and write |
| 124 | 124 | // it to basis |
| 125 | - QBuffer * precompressedBlockWriter; | |
| 125 | + QBuffer precompressedBlockWriter; | |
| 126 | 126 | QDataStream blockWriter; |
| 127 | 127 | qint64 writeData(const char *data, qint64 remaining); |
| 128 | 128 | }; | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -59,7 +59,7 @@ void br_cat(int num_input_galleries, const char *input_galleries[], const char * |
| 59 | 59 | |
| 60 | 60 | void br_cluster(int num_simmats, const char *simmats[], float aggressiveness, const char *csv) |
| 61 | 61 | { |
| 62 | - ClusterGallery(QtUtils::toStringList(num_simmats, simmats), aggressiveness, csv); | |
| 62 | + ClusterSimmat(QtUtils::toStringList(num_simmats, simmats), aggressiveness, csv); | |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | void br_combine_masks(int num_input_masks, const char *input_masks[], const char *output_mask, const char *method) | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -754,6 +754,12 @@ public: |
| 754 | 754 | Q_PROPERTY(int crossValidate READ get_crossValidate WRITE set_crossValidate RESET reset_crossValidate) |
| 755 | 755 | BR_PROPERTY(int, crossValidate, 0) |
| 756 | 756 | |
| 757 | + /*! | |
| 758 | + * \brief List of paths sub-models will be searched for on | |
| 759 | + */ | |
| 760 | + Q_PROPERTY(QList<QString> modelSearch READ get_modelSearch WRITE set_modelSearch RESET reset_modelSearch) | |
| 761 | + BR_PROPERTY(QList<QString>, modelSearch, QList<QString>() ) | |
| 762 | + | |
| 757 | 763 | QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ |
| 758 | 764 | QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ |
| 759 | 765 | ... | ... |
openbr/plugins/classification/adaboost.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/opencvutils.h> | |
| 19 | + | |
| 20 | +using namespace cv; | |
| 21 | + | |
| 22 | +namespace br | |
| 23 | +{ | |
| 24 | + | |
| 25 | +/*! | |
| 26 | + * \ingroup transforms | |
| 27 | + * \brief Wraps OpenCV's Ada Boost framework | |
| 28 | + * \author Scott Klum \cite sklum | |
| 29 | + * \brief http://docs.opencv.org/modules/ml/doc/boosting.html | |
| 30 | + */ | |
| 31 | +class AdaBoostTransform : public Transform | |
| 32 | +{ | |
| 33 | + Q_OBJECT | |
| 34 | + Q_ENUMS(Type) | |
| 35 | + Q_ENUMS(SplitCriteria) | |
| 36 | + | |
| 37 | + Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false) | |
| 38 | + Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false) | |
| 39 | + Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false) | |
| 40 | + Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false) | |
| 41 | + Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false) | |
| 42 | + Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false) | |
| 43 | + Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false) | |
| 44 | + Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false) | |
| 45 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 46 | + Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false) | |
| 47 | + | |
| 48 | +public: | |
| 49 | + enum Type { Discrete = CvBoost::DISCRETE, | |
| 50 | + Real = CvBoost::REAL, | |
| 51 | + Logit = CvBoost::LOGIT, | |
| 52 | + Gentle = CvBoost::GENTLE}; | |
| 53 | + | |
| 54 | + enum SplitCriteria { Default = CvBoost::DEFAULT, | |
| 55 | + Gini = CvBoost::GINI, | |
| 56 | + Misclass = CvBoost::MISCLASS, | |
| 57 | + Sqerr = CvBoost::SQERR}; | |
| 58 | + | |
| 59 | +private: | |
| 60 | + BR_PROPERTY(Type, type, Real) | |
| 61 | + BR_PROPERTY(SplitCriteria, splitCriteria, Default) | |
| 62 | + BR_PROPERTY(int, weakCount, 100) | |
| 63 | + BR_PROPERTY(float, trimRate, .95) | |
| 64 | + BR_PROPERTY(int, folds, 0) | |
| 65 | + BR_PROPERTY(int, maxDepth, 1) | |
| 66 | + BR_PROPERTY(bool, returnConfidence, true) | |
| 67 | + BR_PROPERTY(bool, overwriteMat, true) | |
| 68 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 69 | + BR_PROPERTY(QString, outputVariable, "") | |
| 70 | + | |
| 71 | + CvBoost boost; | |
| 72 | + | |
| 73 | + void train(const TemplateList &data) | |
| 74 | + { | |
| 75 | + Mat samples = OpenCVUtils::toMat(data.data()); | |
| 76 | + Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable)); | |
| 77 | + | |
| 78 | + Mat types = Mat(samples.cols + 1, 1, CV_8U); | |
| 79 | + types.setTo(Scalar(CV_VAR_NUMERICAL)); | |
| 80 | + types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL; | |
| 81 | + | |
| 82 | + CvBoostParams params; | |
| 83 | + params.boost_type = type; | |
| 84 | + params.split_criteria = splitCriteria; | |
| 85 | + params.weak_count = weakCount; | |
| 86 | + params.weight_trim_rate = trimRate; | |
| 87 | + params.cv_folds = folds; | |
| 88 | + params.max_depth = maxDepth; | |
| 89 | + | |
| 90 | + boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(), | |
| 91 | + params); | |
| 92 | + } | |
| 93 | + | |
| 94 | + void project(const Template &src, Template &dst) const | |
| 95 | + { | |
| 96 | + dst = src; | |
| 97 | + float response; | |
| 98 | + if (returnConfidence) { | |
| 99 | + response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount; | |
| 100 | + } else { | |
| 101 | + response = boost.predict(src.m().reshape(1,1)); | |
| 102 | + } | |
| 103 | + | |
| 104 | + if (overwriteMat) { | |
| 105 | + dst.m() = Mat(1, 1, CV_32F); | |
| 106 | + dst.m().at<float>(0, 0) = response; | |
| 107 | + } else { | |
| 108 | + dst.file.set(outputVariable, response); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + void load(QDataStream &stream) | |
| 113 | + { | |
| 114 | + OpenCVUtils::loadModel(boost,stream); | |
| 115 | + } | |
| 116 | + | |
| 117 | + void store(QDataStream &stream) const | |
| 118 | + { | |
| 119 | + OpenCVUtils::storeModel(boost,stream); | |
| 120 | + } | |
| 121 | + | |
| 122 | + | |
| 123 | + void init() | |
| 124 | + { | |
| 125 | + if (outputVariable.isEmpty()) | |
| 126 | + outputVariable = inputVariable; | |
| 127 | + } | |
| 128 | +}; | |
| 129 | + | |
| 130 | +BR_REGISTER(Transform, AdaBoostTransform) | |
| 131 | + | |
| 132 | +} // namespace br | |
| 133 | + | |
| 134 | +#include "classification/adaboost.moc" | ... | ... |
openbr/plugins/dlib.cpp renamed to openbr/plugins/classification/dlib.cpp
openbr/plugins/ebif.cpp renamed to openbr/plugins/classification/ebif.cpp
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 1 | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 2 | 18 | |
| 3 | -#include "openbr_internal.h" | |
| 4 | -#include "openbr/core/common.h" | |
| 5 | -#include "openbr/core/opencvutils.h" | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/common.h> | |
| 21 | +#include <openbr/core/opencvutils.h> | |
| 6 | 22 | |
| 7 | 23 | using namespace cv; |
| 8 | 24 | |
| ... | ... | @@ -128,4 +144,4 @@ BR_REGISTER(Transform, EBIFTransform) |
| 128 | 144 | |
| 129 | 145 | } // namespace br |
| 130 | 146 | |
| 131 | -#include "ebif.moc" | |
| 147 | +#include "classification/ebif.moc" | ... | ... |
openbr/plugins/tree.cpp renamed to openbr/plugins/classification/forest.cpp
| 1 | -#include "openbr_internal.h" | |
| 2 | -#include "openbr/core/opencvutils.h" | |
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/opencvutils.h> | |
| 3 | 19 | |
| 4 | -using namespace std; | |
| 5 | 20 | using namespace cv; |
| 6 | 21 | |
| 7 | 22 | namespace br |
| ... | ... | @@ -250,113 +265,6 @@ class ForestInductionTransform : public ForestTransform |
| 250 | 265 | |
| 251 | 266 | BR_REGISTER(Transform, ForestInductionTransform) |
| 252 | 267 | |
| 253 | -/*! | |
| 254 | - * \ingroup transforms | |
| 255 | - * \brief Wraps OpenCV's Ada Boost framework | |
| 256 | - * \author Scott Klum \cite sklum | |
| 257 | - * \brief http://docs.opencv.org/modules/ml/doc/boosting.html | |
| 258 | - */ | |
| 259 | -class AdaBoostTransform : public Transform | |
| 260 | -{ | |
| 261 | - Q_OBJECT | |
| 262 | - Q_ENUMS(Type) | |
| 263 | - Q_ENUMS(SplitCriteria) | |
| 264 | - | |
| 265 | - Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false) | |
| 266 | - Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false) | |
| 267 | - Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false) | |
| 268 | - Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false) | |
| 269 | - Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false) | |
| 270 | - Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false) | |
| 271 | - Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false) | |
| 272 | - Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false) | |
| 273 | - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 274 | - Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false) | |
| 275 | - | |
| 276 | -public: | |
| 277 | - enum Type { Discrete = CvBoost::DISCRETE, | |
| 278 | - Real = CvBoost::REAL, | |
| 279 | - Logit = CvBoost::LOGIT, | |
| 280 | - Gentle = CvBoost::GENTLE}; | |
| 281 | - | |
| 282 | - enum SplitCriteria { Default = CvBoost::DEFAULT, | |
| 283 | - Gini = CvBoost::GINI, | |
| 284 | - Misclass = CvBoost::MISCLASS, | |
| 285 | - Sqerr = CvBoost::SQERR}; | |
| 286 | - | |
| 287 | -private: | |
| 288 | - BR_PROPERTY(Type, type, Real) | |
| 289 | - BR_PROPERTY(SplitCriteria, splitCriteria, Default) | |
| 290 | - BR_PROPERTY(int, weakCount, 100) | |
| 291 | - BR_PROPERTY(float, trimRate, .95) | |
| 292 | - BR_PROPERTY(int, folds, 0) | |
| 293 | - BR_PROPERTY(int, maxDepth, 1) | |
| 294 | - BR_PROPERTY(bool, returnConfidence, true) | |
| 295 | - BR_PROPERTY(bool, overwriteMat, true) | |
| 296 | - BR_PROPERTY(QString, inputVariable, "Label") | |
| 297 | - BR_PROPERTY(QString, outputVariable, "") | |
| 298 | - | |
| 299 | - CvBoost boost; | |
| 300 | - | |
| 301 | - void train(const TemplateList &data) | |
| 302 | - { | |
| 303 | - Mat samples = OpenCVUtils::toMat(data.data()); | |
| 304 | - Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable)); | |
| 305 | - | |
| 306 | - Mat types = Mat(samples.cols + 1, 1, CV_8U); | |
| 307 | - types.setTo(Scalar(CV_VAR_NUMERICAL)); | |
| 308 | - types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL; | |
| 309 | - | |
| 310 | - CvBoostParams params; | |
| 311 | - params.boost_type = type; | |
| 312 | - params.split_criteria = splitCriteria; | |
| 313 | - params.weak_count = weakCount; | |
| 314 | - params.weight_trim_rate = trimRate; | |
| 315 | - params.cv_folds = folds; | |
| 316 | - params.max_depth = maxDepth; | |
| 317 | - | |
| 318 | - boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(), | |
| 319 | - params); | |
| 320 | - } | |
| 321 | - | |
| 322 | - void project(const Template &src, Template &dst) const | |
| 323 | - { | |
| 324 | - dst = src; | |
| 325 | - float response; | |
| 326 | - if (returnConfidence) { | |
| 327 | - response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount; | |
| 328 | - } else { | |
| 329 | - response = boost.predict(src.m().reshape(1,1)); | |
| 330 | - } | |
| 331 | - | |
| 332 | - if (overwriteMat) { | |
| 333 | - dst.m() = Mat(1, 1, CV_32F); | |
| 334 | - dst.m().at<float>(0, 0) = response; | |
| 335 | - } else { | |
| 336 | - dst.file.set(outputVariable, response); | |
| 337 | - } | |
| 338 | - } | |
| 339 | - | |
| 340 | - void load(QDataStream &stream) | |
| 341 | - { | |
| 342 | - OpenCVUtils::loadModel(boost,stream); | |
| 343 | - } | |
| 344 | - | |
| 345 | - void store(QDataStream &stream) const | |
| 346 | - { | |
| 347 | - OpenCVUtils::storeModel(boost,stream); | |
| 348 | - } | |
| 349 | - | |
| 350 | - | |
| 351 | - void init() | |
| 352 | - { | |
| 353 | - if (outputVariable.isEmpty()) | |
| 354 | - outputVariable = inputVariable; | |
| 355 | - } | |
| 356 | -}; | |
| 357 | - | |
| 358 | -BR_REGISTER(Transform, AdaBoostTransform) | |
| 359 | - | |
| 360 | 268 | } // namespace br |
| 361 | 269 | |
| 362 | -#include "tree.moc" | |
| 270 | +#include "classification/forest.moc" | ... | ... |
openbr/plugins/ipc2013.cpp renamed to openbr/plugins/classification/ipc2013.cpp
openbr/plugins/eigen3.cpp renamed to openbr/plugins/classification/lda.cpp
| ... | ... | @@ -15,12 +15,14 @@ |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <Eigen/Dense> |
| 18 | +#include <opencv2/imgproc/imgproc.hpp> | |
| 19 | +#include <opencv2/highgui/highgui.hpp> | |
| 18 | 20 | |
| 19 | -#include "openbr_internal.h" | |
| 21 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | 22 | |
| 21 | -#include "openbr/core/common.h" | |
| 22 | -#include "openbr/core/eigenutils.h" | |
| 23 | -#include "openbr/core/opencvutils.h" | |
| 23 | +#include <openbr/core/common.h> | |
| 24 | +#include <openbr/core/eigenutils.h> | |
| 25 | +#include <openbr/core/opencvutils.h> | |
| 24 | 26 | |
| 25 | 27 | namespace br |
| 26 | 28 | { |
| ... | ... | @@ -652,46 +654,609 @@ class SparseLDATransform : public Transform |
| 652 | 654 | |
| 653 | 655 | BR_REGISTER(Transform, SparseLDATransform) |
| 654 | 656 | |
| 657 | +using namespace Eigen; | |
| 658 | +using namespace cv; | |
| 659 | + | |
| 655 | 660 | /*! |
| 656 | - * \ingroup distances | |
| 657 | - * \brief L1 distance computed using eigen. | |
| 661 | + * \ingroup transforms | |
| 662 | + * \brief Projects input into a within-class minimizing subspace. | |
| 663 | + * | |
| 664 | + * Like LDA but without the explicit between-class consideration. | |
| 665 | + * | |
| 666 | + * \par Compression | |
| 667 | + * Projection matricies can become quite large, resulting in proportionally large model files. | |
| 668 | + * WCDA automatically alleviates this issue with lossy compression of the projection matrix. | |
| 669 | + * Each element is stored as an 8-bit integer instead of a 32-bit float, resulting in a 75% reduction in the size of the projection matrix. | |
| 670 | + * A non-linear (sqrt) scaling is used because element values are distributed around 0, in affect allowing for higher precision storage of the more frequently occuring values. | |
| 671 | + * | |
| 658 | 672 | * \author Josh Klontz \cite jklontz |
| 659 | 673 | */ |
| 660 | -class L1Distance : public UntrainableDistance | |
| 674 | +class WCDATransform : public Transform | |
| 661 | 675 | { |
| 662 | 676 | Q_OBJECT |
| 677 | + Q_PROPERTY(float keep READ get_keep WRITE set_keep RESET reset_keep STORED false) | |
| 678 | + BR_PROPERTY(float, keep, 0.98) | |
| 679 | + | |
| 680 | + VectorXf mean; | |
| 681 | + MatrixXf projection; | |
| 682 | + | |
| 683 | + typedef Matrix<quint8, Dynamic, Dynamic> CompressedMatrix; | |
| 684 | + CompressedMatrix compressed; | |
| 685 | + float a, b; | |
| 663 | 686 | |
| 664 | - float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 687 | + static CompressedMatrix compress(MatrixXf src, float &a, float &b) | |
| 665 | 688 | { |
| 666 | - const int size = a.rows * a.cols; | |
| 667 | - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | |
| 668 | - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | |
| 669 | - return (aMap-bMap).cwiseAbs().sum(); | |
| 689 | + for (int i=0; i<src.rows(); i++) | |
| 690 | + for (int j=0; j<src.cols(); j++) { | |
| 691 | + float &element = src(i, j); | |
| 692 | + element = sqrtf(fabsf(element)) * ((element >= 0) ? 1 : -1); | |
| 693 | + } | |
| 694 | + b = src.minCoeff(); | |
| 695 | + a = (src.maxCoeff() - b) / 255; | |
| 696 | + return ((src.array() - b) / a).cast<quint8>(); | |
| 670 | 697 | } |
| 698 | + | |
| 699 | + static MatrixXf decompress(const CompressedMatrix &src, float a, float b) | |
| 700 | + { | |
| 701 | + MatrixXf dst = src.cast<float>().array() * a + b; | |
| 702 | + for (int i=0; i<dst.rows(); i++) | |
| 703 | + for (int j=0; j<dst.cols(); j++) { | |
| 704 | + float &element = dst(i, j); | |
| 705 | + element = (element * element) * ((element >= 0) ? 1 : -1); | |
| 706 | + } | |
| 707 | + return dst; | |
| 708 | + } | |
| 709 | + | |
| 710 | + void train(const TemplateList &_templates) | |
| 711 | + { | |
| 712 | + // Relabel ensures that class values range from 0 to numClasses-1. | |
| 713 | + const TemplateList templates = TemplateList::relabel(_templates, "Label", false); | |
| 714 | + const int instances = templates.size(); | |
| 715 | + const int dimsIn = templates.first().m().rows * templates.first().m().cols; | |
| 716 | + | |
| 717 | + // Map data into Eigen | |
| 718 | + MatrixXf data(dimsIn, instances); | |
| 719 | + for (int i=0; i<instances; i++) | |
| 720 | + data.col(i) = Map<const VectorXf>(templates[i].m().ptr<float>(), dimsIn); | |
| 721 | + | |
| 722 | + // Perform PCA dimensionality reduction | |
| 723 | + VectorXf pcaEvals; | |
| 724 | + MatrixXf pcaEvecs; | |
| 725 | + trainCore(data, keep, mean, pcaEvals, pcaEvecs); | |
| 726 | + data = pcaEvecs.transpose() * (data.colwise() - mean); | |
| 727 | + | |
| 728 | + // Get ground truth | |
| 729 | + const QList<int> classes = File::get<int>(templates, "Label"); | |
| 730 | + const QMap<int, int> classCounts = templates.countValues<int>("Label"); | |
| 731 | + const int numClasses = classCounts.size(); | |
| 732 | + | |
| 733 | + // Compute and remove the class means | |
| 734 | + MatrixXf classMeans = MatrixXf::Zero(data.rows(), numClasses); | |
| 735 | + for (int i=0; i<instances; i++) classMeans.col(classes[i]) += data.col(i); | |
| 736 | + for (int i=0; i<numClasses; i++) classMeans.col(i) /= classCounts[i]; | |
| 737 | + for (int i=0; i<instances; i++) data.col(i) -= classMeans.col(classes[i]); | |
| 738 | + | |
| 739 | + // Compute the within-class projection | |
| 740 | + VectorXf wcMean, wcEvals; | |
| 741 | + MatrixXf wcEvecs; | |
| 742 | + trainCore(data, keep, wcMean, wcEvals, wcEvecs); | |
| 743 | + | |
| 744 | + // This has the effect of whitening the within-class scatter. | |
| 745 | + // In effect, this minimizes the within-class variation energy. | |
| 746 | + for (int i=0; i<keep; i++) | |
| 747 | + wcEvecs.col(i) /= sqrt(wcEvals(i)); | |
| 748 | + | |
| 749 | + projection = wcEvecs.transpose() * pcaEvecs.transpose(); | |
| 750 | + | |
| 751 | + // Compress and restore the projection matrix | |
| 752 | + compressed = compress(projection, a, b); | |
| 753 | + projection = decompress(compressed, a, b); | |
| 754 | + } | |
| 755 | + | |
| 756 | + static void trainCore(MatrixXf data, float keep, VectorXf &mean, VectorXf &eVals, MatrixXf &eVecs) | |
| 757 | + { | |
| 758 | + const int dimsIn = data.rows(); | |
| 759 | + const int instances = data.cols(); | |
| 760 | + const bool dominantEigenEstimation = (dimsIn > instances); | |
| 761 | + | |
| 762 | + // Compute and remove mean | |
| 763 | + mean = data.rowwise().sum() / instances; | |
| 764 | + data.colwise() -= mean; | |
| 765 | + | |
| 766 | + // Calculate and normalize covariance matrix | |
| 767 | + MatrixXf cov; | |
| 768 | + if (dominantEigenEstimation) cov = data.transpose() * data; | |
| 769 | + else cov = data * data.transpose(); | |
| 770 | + cov /= (instances-1); | |
| 771 | + | |
| 772 | + // Compute eigendecomposition, returning eigenvectors/eigenvalues in increasing order by eigenvalue. | |
| 773 | + SelfAdjointEigenSolver<MatrixXf> eSolver(cov); | |
| 774 | + VectorXf allEVals = eSolver.eigenvalues(); | |
| 775 | + MatrixXf allEVecs = eSolver.eigenvectors(); | |
| 776 | + if (dominantEigenEstimation) | |
| 777 | + allEVecs = data * allEVecs; | |
| 778 | + | |
| 779 | + if (keep < 1) { | |
| 780 | + // Keep eigenvectors that retain a certain energy percentage. | |
| 781 | + const float desiredEnergy = keep * allEVals.sum(); | |
| 782 | + float currentEnergy = 0; | |
| 783 | + int i = 0; | |
| 784 | + while ((currentEnergy < desiredEnergy) && (i < allEVals.rows())) { | |
| 785 | + currentEnergy += allEVals(allEVals.rows()-(i+1)); | |
| 786 | + i++; | |
| 787 | + } | |
| 788 | + keep = i; | |
| 789 | + } else { | |
| 790 | + if (keep > allEVals.rows()) { | |
| 791 | + qWarning("Insufficient samples, needed at least %d but only got %d.", (int)keep, (int)allEVals.rows()); | |
| 792 | + keep = allEVals.rows(); | |
| 793 | + } | |
| 794 | + } | |
| 795 | + | |
| 796 | + // Keep highest energy vectors | |
| 797 | + eVals = VectorXf((int)keep); | |
| 798 | + eVecs = MatrixXf(allEVecs.rows(), (int)keep); | |
| 799 | + for (int i=0; i<keep; i++) { | |
| 800 | + const int index = allEVals.rows()-(i+1); | |
| 801 | + eVals(i) = allEVals(index); | |
| 802 | + eVecs.col(i) = allEVecs.col(index) / allEVecs.col(index).norm(); | |
| 803 | + } | |
| 804 | + } | |
| 805 | + | |
| 806 | + void project(const Template &src, Template &dst) const | |
| 807 | + { | |
| 808 | + dst = Mat(1, projection.rows(), CV_32FC1); | |
| 809 | + Map<const VectorXf> inMap(src.m().ptr<float>(), src.m().rows * src.m().cols); | |
| 810 | + Map<VectorXf> outMap(dst.m().ptr<float>(), projection.rows()); | |
| 811 | + outMap = projection * (inMap - mean); | |
| 812 | + } | |
| 813 | + | |
| 814 | + void store(QDataStream &stream) const | |
| 815 | + { | |
| 816 | + stream << mean << compressed << a << b; | |
| 817 | + } | |
| 818 | + | |
| 819 | + void load(QDataStream &stream) | |
| 820 | + { | |
| 821 | + stream >> mean >> compressed >> a >> b; | |
| 822 | + projection = decompress(compressed, a, b); | |
| 823 | + } | |
| 824 | +}; | |
| 825 | + | |
| 826 | +BR_REGISTER(Transform, WCDATransform) | |
| 827 | + | |
| 828 | +// For use in BBLDAAlignmentTransform | |
| 829 | +// A single decision boundary with gaussian distributed responses | |
| 830 | +struct DecisionBoundary | |
| 831 | +{ | |
| 832 | + VectorXf function; | |
| 833 | + float positiveMean, negativeMean, positiveSD, negativeSD; | |
| 671 | 834 | }; |
| 672 | 835 | |
| 673 | -BR_REGISTER(Distance, L1Distance) | |
| 836 | +QDataStream &operator<<(QDataStream &stream, const DecisionBoundary &db) | |
| 837 | +{ | |
| 838 | + return stream << db.function << db.positiveMean << db.negativeMean << db.positiveSD << db.negativeSD; | |
| 839 | +} | |
| 840 | + | |
| 841 | +QDataStream &operator>>(QDataStream &stream, DecisionBoundary &db) | |
| 842 | +{ | |
| 843 | + return stream >> db.function >> db.positiveMean >> db.negativeMean >> db.positiveSD >> db.negativeSD; | |
| 844 | +} | |
| 674 | 845 | |
| 675 | 846 | /*! |
| 676 | - * \ingroup distances | |
| 677 | - * \brief L2 distance computed using eigen. | |
| 678 | - * \author Josh Klontz \cite jklontz | |
| 847 | + * \ingroup transforms | |
| 848 | + * \brief Boosted Binary LDA classifier for local alignment. | |
| 679 | 849 | */ |
| 680 | -class L2Distance : public UntrainableDistance | |
| 850 | +class BBLDAAlignmentTransform : public MetaTransform | |
| 681 | 851 | { |
| 682 | 852 | Q_OBJECT |
| 853 | + Q_PROPERTY(QList<int> anchors READ get_anchors WRITE set_anchors RESET reset_anchors STORED false) // A list of two indicies to provide initial rotation and scaling of training data | |
| 854 | + Q_PROPERTY(QString detectionKey READ get_detectionKey WRITE set_detectionKey RESET reset_detectionKey STORED false) // Metadata key containing the detection bounding box | |
| 855 | + Q_PROPERTY(int iad READ get_iad WRITE set_iad RESET reset_iad STORED false) // Inter-anchor distance in pixels | |
| 856 | + Q_PROPERTY(float radius READ get_radius WRITE set_radius RESET reset_radius STORED false) // Kernel size as a fraction of IAD | |
| 857 | + Q_PROPERTY(int resolution READ get_resolution WRITE set_resolution RESET reset_resolution STORED false) // Project resolution for sampling rotation and scale | |
| 858 | + BR_PROPERTY(QList<int>, anchors, QList<int>()) | |
| 859 | + BR_PROPERTY(QString, detectionKey, "FrontalFace") | |
| 860 | + BR_PROPERTY(int, iad, 16) | |
| 861 | + BR_PROPERTY(float, radius, 2) | |
| 862 | + BR_PROPERTY(int, resolution, 20) | |
| 863 | + | |
| 864 | + typedef Matrix<quint8, Dynamic, Dynamic> MatrixX8U; | |
| 865 | + | |
| 866 | + struct RegistrationMatrix | |
| 867 | + { | |
| 868 | + Mat src; | |
| 869 | + Point2f center; | |
| 870 | + double angle, scale; | |
| 871 | + | |
| 872 | + RegistrationMatrix(const Mat &src = Mat(), const Point2f ¢er = 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 ®istered, 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> ®istered, 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> ®istered, 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 ¢eredSampleMatrix = 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 ®istrationMatrix, registrationMatricies) | |
| 1161 | + registered.append(registrationMatrix.warp(regionSize).cast<float>()); | |
| 1162 | + | |
| 1163 | + // Boosted LDA | |
| 1164 | + const int numImages = registered.size(); | |
| 1165 | + const int kernelSize = iad * radius; | |
| 1166 | + const int responseSize = regionSize - kernelSize + 1; | |
| 1167 | + const MatrixXf prior = MatrixXf::Ones(numImages, responseSize*responseSize); | |
| 1168 | + const MatrixXf responses = computeBoundaryRecursive(registered, kernelSize, prior, decisionBoundaries); | |
| 1169 | + | |
| 1170 | +// for (int i=0; i<numImages; i++) { | |
| 1171 | +// float maxResponse = -std::numeric_limits<float>::max(); | |
| 1172 | +// int maxX = -1; | |
| 1173 | +// int maxY = -1; | |
| 1174 | +// for (int j=0; j<responseSize; j++) | |
| 1175 | +// for (int k=0; k<responseSize; k++) { | |
| 1176 | +// const float response = responses(i, j*responseSize+k); | |
| 1177 | +// if (response > maxResponse) { | |
| 1178 | +// maxResponse = response; | |
| 1179 | +// maxY = j; | |
| 1180 | +// maxX = k; | |
| 1181 | +// } | |
| 1182 | +// } | |
| 1183 | + | |
| 1184 | +// MatrixXf draw = registered[i]; | |
| 1185 | +// const int r = 3; | |
| 1186 | +// maxX += kernelSize / 2; | |
| 1187 | +// maxY += kernelSize / 2; | |
| 1188 | +// for (int i=-r; i<=r; i++) | |
| 1189 | +// draw(regionSize/2 + i, regionSize/2) *= 2; | |
| 1190 | +// for (int i=-r; i<=r; i++) | |
| 1191 | +// draw(regionSize/2, regionSize/2 + i) *= 2; | |
| 1192 | +// for (int i=-r; i<=r; i++) | |
| 1193 | +// draw(maxX + i, maxY) /= 2; | |
| 1194 | +// for (int i=-r; i<=r; i++) | |
| 1195 | +// draw(maxX, maxY + i) /= 2; | |
| 1196 | +// show("draw", draw); | |
| 1197 | +// show("responses", VectorXf(responses.row(i))); | |
| 1198 | +// } | |
| 1199 | + | |
| 1200 | + if (Globals->verbose) | |
| 1201 | + qDebug("Learned %d function(s) with error %g", decisionBoundaries.size(), IADError(responses, prior)); | |
| 1202 | + } | |
| 1203 | + | |
| 1204 | + void project(const Template &src, Template &dst) const | |
| 1205 | + { | |
| 1206 | + dst = src; | |
| 1207 | + const QRectF detection = src.file.get<QRectF>(detectionKey); | |
| 1208 | + RegistrationMatrix registrationMatrix(src, OpenCVUtils::toPoint(detection.center())); | |
| 1209 | + | |
| 1210 | + const int regionSize = iad * (1 + radius); | |
| 1211 | + const int kernelSize = iad * radius; | |
| 1212 | + const int responseSize = regionSize - kernelSize + 1; | |
| 1213 | + const float rotationStep = (2 * rotationMax) / (resolution - 1); | |
| 1214 | + const float scaleStep = (scaleMax - scaleMin) / (resolution - 1); | |
| 1215 | + | |
| 1216 | + float bestResponse = -std::numeric_limits<float>::max(), bestRotation = 0, bestScale = 0; | |
| 1217 | + int bestX = 0, bestY =0; | |
| 1218 | + | |
| 1219 | + for (float rotation = -rotationMax; rotation <= rotationMax; rotation += rotationStep) { | |
| 1220 | + registrationMatrix.angle = rotation; | |
| 1221 | + for (float scale = scaleMin; scale <= scaleMax; scale += scaleStep) { | |
| 1222 | + registrationMatrix.scale = iad / (scale * detection.width()); | |
| 1223 | + const MatrixXf registered = registrationMatrix.warp(regionSize).cast<float>(); | |
| 1224 | + | |
| 1225 | + for (int j=0; j<responseSize; j++) | |
| 1226 | + for (int k=0; k<responseSize; k++) { | |
| 1227 | + const MatrixXf sample = getSample(registered, j, k, kernelSize); | |
| 1228 | + float posterior = 1; | |
| 1229 | + foreach (const DecisionBoundary &db, decisionBoundaries) { | |
| 1230 | + const float response = db.function.transpose() * Map<const VectorXf>(sample.data(), kernelSize*kernelSize); | |
| 1231 | + const float positiveDensity = 1 / (sqrtf(2 * CV_PI) * db.positiveSD) * expf(-0.5 * powf((response - db.positiveMean) / db.positiveSD, 2.f)); | |
| 1232 | + const float negativeDensity = 1 / (sqrtf(2 * CV_PI) * db.negativeSD) * expf(-0.5 * powf((response - db.negativeMean) / db.negativeSD, 2.f)); | |
| 1233 | + posterior *= positiveDensity / (positiveDensity + negativeDensity); | |
| 1234 | + } | |
| 1235 | + if (posterior > bestResponse) { | |
| 1236 | + bestResponse = posterior; | |
| 1237 | + bestX = k + kernelSize/2; | |
| 1238 | + bestY = j + kernelSize/2; | |
| 1239 | + bestRotation = rotation; | |
| 1240 | + bestScale = scale; | |
| 1241 | + } | |
| 1242 | + } | |
| 1243 | + } | |
| 1244 | + } | |
| 1245 | + } | |
| 1246 | + | |
| 1247 | + void store(QDataStream &stream) const | |
| 1248 | + { | |
| 1249 | + stream << rotationMax << scaleMin << scaleMax << xTranslationMax << yTranslationMin << yTranslationMax << decisionBoundaries; | |
| 1250 | + } | |
| 1251 | + | |
| 1252 | + void load(QDataStream &stream) | |
| 685 | 1253 | { |
| 686 | - const int size = a.rows * a.cols; | |
| 687 | - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | |
| 688 | - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | |
| 689 | - return (aMap-bMap).squaredNorm(); | |
| 1254 | + stream >> rotationMax >> scaleMin >> scaleMax >> xTranslationMax >> yTranslationMin >> yTranslationMax >> decisionBoundaries; | |
| 690 | 1255 | } |
| 691 | 1256 | }; |
| 692 | 1257 | |
| 693 | -BR_REGISTER(Distance, L2Distance) | |
| 1258 | +BR_REGISTER(Transform, BBLDAAlignmentTransform) | |
| 694 | 1259 | |
| 695 | 1260 | } // namespace br |
| 696 | 1261 | |
| 697 | -#include "eigen3.moc" | |
| 1262 | +#include "classification/lda.moc" | ... | ... |
openbr/plugins/liblinear.cpp renamed to openbr/plugins/classification/liblinear.cpp
openbr/plugins/nn.cpp renamed to openbr/plugins/classification/mlp.cpp
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 1 | 17 | #include <opencv2/ml/ml.hpp> |
| 2 | 18 | |
| 3 | -#include "openbr_internal.h" | |
| 4 | -#include "openbr/core/qtutils.h" | |
| 5 | -#include "openbr/core/opencvutils.h" | |
| 6 | -#include "openbr/core/eigenutils.h" | |
| 7 | -#include <QString> | |
| 8 | -#include <QTemporaryFile> | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/opencvutils.h> | |
| 9 | 21 | |
| 10 | -using namespace std; | |
| 11 | 22 | using namespace cv; |
| 12 | 23 | |
| 13 | 24 | namespace br |
| 14 | 25 | { |
| 15 | 26 | |
| 16 | -static void storeMLP(const CvANN_MLP &mlp, QDataStream &stream) | |
| 17 | -{ | |
| 18 | - // Create local file | |
| 19 | - QTemporaryFile tempFile; | |
| 20 | - tempFile.open(); | |
| 21 | - tempFile.close(); | |
| 22 | - | |
| 23 | - // Save MLP to local file | |
| 24 | - mlp.save(qPrintable(tempFile.fileName())); | |
| 25 | - | |
| 26 | - // Copy local file contents to stream | |
| 27 | - tempFile.open(); | |
| 28 | - QByteArray data = tempFile.readAll(); | |
| 29 | - tempFile.close(); | |
| 30 | - stream << data; | |
| 31 | -} | |
| 32 | - | |
| 33 | -static void loadMLP(CvANN_MLP &mlp, QDataStream &stream) | |
| 34 | -{ | |
| 35 | - // Copy local file contents from stream | |
| 36 | - QByteArray data; | |
| 37 | - stream >> data; | |
| 38 | - | |
| 39 | - // Create local file | |
| 40 | - QTemporaryFile tempFile(QDir::tempPath()+"/MLP"); | |
| 41 | - tempFile.open(); | |
| 42 | - tempFile.write(data); | |
| 43 | - tempFile.close(); | |
| 44 | - | |
| 45 | - // Load MLP from local file | |
| 46 | - mlp.load(qPrintable(tempFile.fileName())); | |
| 47 | -} | |
| 48 | - | |
| 49 | 27 | /*! |
| 50 | 28 | * \ingroup transforms |
| 51 | 29 | * \brief Wraps OpenCV's multi-layer perceptron framework |
| ... | ... | @@ -124,12 +102,12 @@ private: |
| 124 | 102 | |
| 125 | 103 | void load(QDataStream &stream) |
| 126 | 104 | { |
| 127 | - loadMLP(mlp,stream); | |
| 105 | + OpenCVUtils::loadModel(mlp, stream); | |
| 128 | 106 | } |
| 129 | 107 | |
| 130 | 108 | void store(QDataStream &stream) const |
| 131 | 109 | { |
| 132 | - storeMLP(mlp,stream); | |
| 110 | + OpenCVUtils::storeModel(mlp, stream); | |
| 133 | 111 | } |
| 134 | 112 | }; |
| 135 | 113 | |
| ... | ... | @@ -137,4 +115,4 @@ BR_REGISTER(Transform, MLPTransform) |
| 137 | 115 | |
| 138 | 116 | } // namespace br |
| 139 | 117 | |
| 140 | -#include "nn.moc" | |
| 118 | +#include "classification/mlp.moc" | ... | ... |
openbr/plugins/nt4.cpp renamed to openbr/plugins/classification/nt4.cpp
| ... | ... | @@ -20,8 +20,8 @@ |
| 20 | 20 | #include <Bmp.h> |
| 21 | 21 | #include <NGrayscaleImage.h> |
| 22 | 22 | |
| 23 | -#include "core/resource.h" | |
| 24 | -#include "core/opencvutils.h" | |
| 23 | +#include <openbr/core/resource.h> | |
| 24 | +#include <openbr/core/opencvutils.h> | |
| 25 | 25 | |
| 26 | 26 | using namespace cv; |
| 27 | 27 | using namespace br; |
| ... | ... | @@ -457,4 +457,4 @@ class NT4Compare : public Distance |
| 457 | 457 | |
| 458 | 458 | BR_REGISTER(Distance, NT4Compare) |
| 459 | 459 | |
| 460 | -#include "nt4.moc" | |
| 460 | +#include "classification/nt4.moc" | ... | ... |
openbr/plugins/pp4.cpp renamed to openbr/plugins/classification/pp4.cpp
openbr/plugins/pp5.cpp renamed to openbr/plugins/classification/pp5.cpp
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | #include <pittpatt_raw_image_io.h> |
| 12 | 12 | #include <pittpatt_sdk.h> |
| 13 | 13 | #include <pittpatt_license.h> |
| 14 | -#include "openbr_internal.h" | |
| 14 | +#include "openbr/plugins/openbr_internal.h" | |
| 15 | 15 | #include "openbr/core/resource.h" |
| 16 | 16 | |
| 17 | 17 | #define TRY(CC) \ |
| ... | ... | @@ -593,4 +593,4 @@ class PP5GalleryTransform: public UntrainableMetaTransform |
| 593 | 593 | |
| 594 | 594 | BR_REGISTER(Transform, PP5GalleryTransform) |
| 595 | 595 | |
| 596 | -#include "plugins/pp5.moc" | |
| 596 | +#include "classification/pp5.moc" | ... | ... |
openbr/plugins/svm.cpp renamed to openbr/plugins/classification/svm.cpp
| ... | ... | @@ -18,8 +18,8 @@ |
| 18 | 18 | #include <opencv2/core/core.hpp> |
| 19 | 19 | #include <opencv2/ml/ml.hpp> |
| 20 | 20 | |
| 21 | -#include "openbr_internal.h" | |
| 22 | -#include "openbr/core/opencvutils.h" | |
| 21 | +#include <openbr/plugins/openbr_internal.h> | |
| 22 | +#include <openbr/core/opencvutils.h> | |
| 23 | 23 | |
| 24 | 24 | using namespace cv; |
| 25 | 25 | |
| ... | ... | @@ -261,4 +261,4 @@ BR_REGISTER(Distance, SVMDistance) |
| 261 | 261 | |
| 262 | 262 | } // namespace br |
| 263 | 263 | |
| 264 | -#include "svm.moc" | |
| 264 | +#include "classification/svm.moc" | ... | ... |
openbr/plugins/classification/turk.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Convenience class for training turk attribute regressors | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class TurkClassifierTransform : public Transform | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false) | |
| 31 | + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false) | |
| 32 | + Q_PROPERTY(bool isMeta READ get_isMeta WRITE set_isMeta RESET reset_isMeta STORED false) | |
| 33 | + BR_PROPERTY(QString, key, QString()) | |
| 34 | + BR_PROPERTY(QStringList, values, QStringList()) | |
| 35 | + BR_PROPERTY(bool, isMeta, false) | |
| 36 | + | |
| 37 | + Transform *child; | |
| 38 | + | |
| 39 | + void init() | |
| 40 | + { | |
| 41 | + QStringList classifiers; | |
| 42 | + foreach (const QString &value, values) | |
| 43 | + classifiers.append(QString("(SVM(RBF,EPS_SVR,returnDFVal=true,inputVariable=%1,outputVariable=predicted_%1)%2)").arg(key + "_" + value, isMeta ? QString("+Average+SaveMat(predicted_%1)").arg(value) : QString())); | |
| 44 | + child = Transform::make(classifiers.join("/") + (classifiers.size() > 1 ? "+Cat" : "")); | |
| 45 | + } | |
| 46 | + | |
| 47 | + void train(const QList<TemplateList> &data) | |
| 48 | + { | |
| 49 | + child->train(data); | |
| 50 | + } | |
| 51 | + | |
| 52 | + void project(const Template &src, Template &dst) const | |
| 53 | + { | |
| 54 | + child->project(src, dst); | |
| 55 | + } | |
| 56 | + | |
| 57 | + void store(QDataStream &stream) const | |
| 58 | + { | |
| 59 | + child->store(stream); | |
| 60 | + } | |
| 61 | + | |
| 62 | + void load(QDataStream &stream) | |
| 63 | + { | |
| 64 | + child->load(stream); | |
| 65 | + } | |
| 66 | +}; | |
| 67 | + | |
| 68 | +BR_REGISTER(Transform, TurkClassifierTransform) | |
| 69 | + | |
| 70 | +} // namespace br | |
| 71 | + | |
| 72 | +#include "classification/turk.moc" | ... | ... |
openbr/plugins/cluster/collectnn.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Collect nearest neighbors and append them to metadata. | |
| 25 | + * \author Charles Otto \cite caotto | |
| 26 | + */ | |
| 27 | +class CollectNNTransform : public UntrainableMetaTransform | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false) | |
| 32 | + BR_PROPERTY(int, keep, 20) | |
| 33 | + | |
| 34 | + void project(const Template &src, Template &dst) const | |
| 35 | + { | |
| 36 | + dst.file = src.file; | |
| 37 | + dst.clear(); | |
| 38 | + dst.m() = cv::Mat(); | |
| 39 | + Neighbors neighbors; | |
| 40 | + for (int i=0; i < src.m().cols;i++) { | |
| 41 | + // skip self compares | |
| 42 | + if (i == src.file.get<int>("FrameNumber")) | |
| 43 | + continue; | |
| 44 | + neighbors.append(Neighbor(i, src.m().at<float>(0,i))); | |
| 45 | + } | |
| 46 | + int actuallyKeep = std::min(keep, neighbors.size()); | |
| 47 | + std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors); | |
| 48 | + | |
| 49 | + Neighbors selected = neighbors.mid(0, actuallyKeep); | |
| 50 | + dst.file.set("neighbors", QVariant::fromValue(selected)); | |
| 51 | + } | |
| 52 | +}; | |
| 53 | + | |
| 54 | +BR_REGISTER(Transform, CollectNNTransform) | |
| 55 | + | |
| 56 | +} // namespace br | |
| 57 | + | |
| 58 | +#include "cluster/collectnn.moc" | ... | ... |
openbr/plugins/cluster/kmeans.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <opencv2/flann/flann.hpp> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/opencvutils.h> | |
| 21 | + | |
| 22 | +using namespace cv; | |
| 23 | + | |
| 24 | +namespace br | |
| 25 | +{ | |
| 26 | + | |
| 27 | +/*! | |
| 28 | + * \ingroup transforms | |
| 29 | + * \brief Wraps OpenCV kmeans and flann. | |
| 30 | + * \author Josh Klontz \cite jklontz | |
| 31 | + */ | |
| 32 | +class KMeansTransform : public Transform | |
| 33 | +{ | |
| 34 | + Q_OBJECT | |
| 35 | + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | |
| 36 | + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | |
| 37 | + BR_PROPERTY(int, kTrain, 256) | |
| 38 | + BR_PROPERTY(int, kSearch, 1) | |
| 39 | + | |
| 40 | + Mat centers; | |
| 41 | + mutable QScopedPointer<flann::Index> index; | |
| 42 | + mutable QMutex mutex; | |
| 43 | + | |
| 44 | + void reindex() | |
| 45 | + { | |
| 46 | + index.reset(new flann::Index(centers, flann::LinearIndexParams())); | |
| 47 | + } | |
| 48 | + | |
| 49 | + void train(const TemplateList &data) | |
| 50 | + { | |
| 51 | + Mat bestLabels; | |
| 52 | + const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers); | |
| 53 | + qDebug("KMeans compactness = %f", compactness); | |
| 54 | + reindex(); | |
| 55 | + } | |
| 56 | + | |
| 57 | + void project(const Template &src, Template &dst) const | |
| 58 | + { | |
| 59 | + QMutexLocker locker(&mutex); | |
| 60 | + Mat dists, indicies; | |
| 61 | + index->knnSearch(src, indicies, dists, kSearch); | |
| 62 | + dst = indicies.reshape(1, 1); | |
| 63 | + } | |
| 64 | + | |
| 65 | + void load(QDataStream &stream) | |
| 66 | + { | |
| 67 | + stream >> centers; | |
| 68 | + reindex(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + void store(QDataStream &stream) const | |
| 72 | + { | |
| 73 | + stream << centers; | |
| 74 | + } | |
| 75 | +}; | |
| 76 | + | |
| 77 | +BR_REGISTER(Transform, KMeansTransform) | |
| 78 | + | |
| 79 | +} // namespace br | |
| 80 | + | |
| 81 | +#include "cluster/kmeans.moc" | ... | ... |
openbr/plugins/cluster.cpp renamed to openbr/plugins/cluster/knn.cpp
| ... | ... | @@ -14,12 +14,8 @@ |
| 14 | 14 | * limitations under the License. * |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | -#include <opencv2/flann/flann.hpp> | |
| 18 | - | |
| 19 | -#include "openbr_internal.h" | |
| 20 | -#include "openbr/core/common.h" | |
| 21 | -#include "openbr/core/opencvutils.h" | |
| 22 | -#include <fstream> | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/common.h> | |
| 23 | 19 | |
| 24 | 20 | using namespace cv; |
| 25 | 21 | |
| ... | ... | @@ -28,58 +24,6 @@ namespace br |
| 28 | 24 | |
| 29 | 25 | /*! |
| 30 | 26 | * \ingroup transforms |
| 31 | - * \brief Wraps OpenCV kmeans and flann. | |
| 32 | - * \author Josh Klontz \cite jklontz | |
| 33 | - */ | |
| 34 | -class KMeansTransform : public Transform | |
| 35 | -{ | |
| 36 | - Q_OBJECT | |
| 37 | - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | |
| 38 | - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | |
| 39 | - BR_PROPERTY(int, kTrain, 256) | |
| 40 | - BR_PROPERTY(int, kSearch, 1) | |
| 41 | - | |
| 42 | - Mat centers; | |
| 43 | - mutable QScopedPointer<flann::Index> index; | |
| 44 | - mutable QMutex mutex; | |
| 45 | - | |
| 46 | - void reindex() | |
| 47 | - { | |
| 48 | - index.reset(new flann::Index(centers, flann::LinearIndexParams())); | |
| 49 | - } | |
| 50 | - | |
| 51 | - void train(const TemplateList &data) | |
| 52 | - { | |
| 53 | - Mat bestLabels; | |
| 54 | - const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers); | |
| 55 | - qDebug("KMeans compactness = %f", compactness); | |
| 56 | - reindex(); | |
| 57 | - } | |
| 58 | - | |
| 59 | - void project(const Template &src, Template &dst) const | |
| 60 | - { | |
| 61 | - QMutexLocker locker(&mutex); | |
| 62 | - Mat dists, indicies; | |
| 63 | - index->knnSearch(src, indicies, dists, kSearch); | |
| 64 | - dst = indicies.reshape(1, 1); | |
| 65 | - } | |
| 66 | - | |
| 67 | - void load(QDataStream &stream) | |
| 68 | - { | |
| 69 | - stream >> centers; | |
| 70 | - reindex(); | |
| 71 | - } | |
| 72 | - | |
| 73 | - void store(QDataStream &stream) const | |
| 74 | - { | |
| 75 | - stream << centers; | |
| 76 | - } | |
| 77 | -}; | |
| 78 | - | |
| 79 | -BR_REGISTER(Transform, KMeansTransform) | |
| 80 | - | |
| 81 | -/*! | |
| 82 | - * \ingroup transforms | |
| 83 | 27 | * \brief K nearest neighbors classifier. |
| 84 | 28 | * \author Josh Klontz \cite jklontz |
| 85 | 29 | */ |
| ... | ... | @@ -151,148 +95,6 @@ class KNNTransform : public Transform |
| 151 | 95 | |
| 152 | 96 | BR_REGISTER(Transform, KNNTransform) |
| 153 | 97 | |
| 154 | -/*! | |
| 155 | - * \ingroup transforms | |
| 156 | - * \brief Chooses k random points to be centroids. | |
| 157 | - * \author Austin Blanton \cite imaus10 | |
| 158 | - * \see KMeansTransform | |
| 159 | - */ | |
| 160 | -class RandomCentroidsTransform : public Transform | |
| 161 | -{ | |
| 162 | - Q_OBJECT | |
| 163 | - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | |
| 164 | - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | |
| 165 | - BR_PROPERTY(int, kTrain, 256) | |
| 166 | - BR_PROPERTY(int, kSearch, 1) | |
| 167 | - | |
| 168 | - Mat centers; | |
| 169 | - mutable QScopedPointer<flann::Index> index; | |
| 170 | - mutable QMutex mutex; | |
| 171 | - | |
| 172 | - void reindex() | |
| 173 | - { | |
| 174 | - index.reset(new flann::Index(centers, flann::LinearIndexParams())); | |
| 175 | - } | |
| 176 | - | |
| 177 | - void train(const TemplateList &data) | |
| 178 | - { | |
| 179 | - Mat flat = OpenCVUtils::toMatByRow(data.data()); | |
| 180 | - QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true); | |
| 181 | - foreach (const int &idx, sample) | |
| 182 | - centers.push_back(flat.row(idx)); | |
| 183 | - reindex(); | |
| 184 | - } | |
| 185 | - | |
| 186 | - void project(const Template &src, Template &dst) const | |
| 187 | - { | |
| 188 | - QMutexLocker locker(&mutex); | |
| 189 | - Mat dists, indicies; | |
| 190 | - index->knnSearch(src, indicies, dists, kSearch); | |
| 191 | - dst = indicies.reshape(1, 1); | |
| 192 | - } | |
| 193 | - | |
| 194 | - void load(QDataStream &stream) | |
| 195 | - { | |
| 196 | - stream >> centers; | |
| 197 | - reindex(); | |
| 198 | - } | |
| 199 | - | |
| 200 | - void store(QDataStream &stream) const | |
| 201 | - { | |
| 202 | - stream << centers; | |
| 203 | - } | |
| 204 | -}; | |
| 205 | - | |
| 206 | -BR_REGISTER(Transform, RandomCentroidsTransform) | |
| 207 | - | |
| 208 | -class RegInitializer : public Initializer | |
| 209 | -{ | |
| 210 | - Q_OBJECT | |
| 211 | - | |
| 212 | - void initialize() const | |
| 213 | - { | |
| 214 | - qRegisterMetaType<br::Neighbors>(); | |
| 215 | - } | |
| 216 | -}; | |
| 217 | -BR_REGISTER(Initializer, RegInitializer) | |
| 218 | - | |
| 219 | -class CollectNNTransform : public UntrainableMetaTransform | |
| 220 | -{ | |
| 221 | - Q_OBJECT | |
| 222 | - | |
| 223 | - Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false) | |
| 224 | - BR_PROPERTY(int, keep, 20) | |
| 225 | - | |
| 226 | - void project(const Template &src, Template &dst) const | |
| 227 | - { | |
| 228 | - dst.file = src.file; | |
| 229 | - dst.clear(); | |
| 230 | - dst.m() = cv::Mat(); | |
| 231 | - Neighbors neighbors; | |
| 232 | - for (int i=0; i < src.m().cols;i++) { | |
| 233 | - // skip self compares | |
| 234 | - if (i == src.file.get<int>("FrameNumber")) | |
| 235 | - continue; | |
| 236 | - neighbors.append(Neighbor(i, src.m().at<float>(0,i))); | |
| 237 | - } | |
| 238 | - int actuallyKeep = std::min(keep, neighbors.size()); | |
| 239 | - std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors); | |
| 240 | - | |
| 241 | - Neighbors selected = neighbors.mid(0, actuallyKeep); | |
| 242 | - dst.file.set("neighbors", QVariant::fromValue(selected)); | |
| 243 | - } | |
| 244 | -}; | |
| 245 | -BR_REGISTER(Transform, CollectNNTransform) | |
| 246 | - | |
| 247 | -class LogNNTransform : public TimeVaryingTransform | |
| 248 | -{ | |
| 249 | - Q_OBJECT | |
| 250 | - | |
| 251 | - Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) | |
| 252 | - BR_PROPERTY(QString, fileName, "") | |
| 253 | - | |
| 254 | - std::fstream fout; | |
| 255 | - | |
| 256 | - void projectUpdate(const Template &src, Template &dst) | |
| 257 | - { | |
| 258 | - dst = src; | |
| 259 | - | |
| 260 | - if (!dst.file.contains("neighbors")) { | |
| 261 | - fout << std::endl; | |
| 262 | - return; | |
| 263 | - } | |
| 264 | - | |
| 265 | - Neighbors neighbors = dst.file.get<Neighbors>("neighbors"); | |
| 266 | - if (neighbors.isEmpty() ) { | |
| 267 | - fout << std::endl; | |
| 268 | - return; | |
| 269 | - } | |
| 270 | - | |
| 271 | - QString aLine; | |
| 272 | - aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second)); | |
| 273 | - for (int i=1; i < neighbors.size();i++) | |
| 274 | - aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second)); | |
| 275 | - | |
| 276 | - fout << qPrintable(aLine) << std::endl; | |
| 277 | - } | |
| 278 | - | |
| 279 | - void init() | |
| 280 | - { | |
| 281 | - if (!fileName.isEmpty()) | |
| 282 | - fout.open(qPrintable(fileName), std::ios_base::out); | |
| 283 | - } | |
| 284 | - | |
| 285 | - void finalize(TemplateList &output) | |
| 286 | - { | |
| 287 | - (void) output; | |
| 288 | - fout.close(); | |
| 289 | - } | |
| 290 | - | |
| 291 | -public: | |
| 292 | - LogNNTransform() : TimeVaryingTransform(false, false) {} | |
| 293 | -}; | |
| 294 | -BR_REGISTER(Transform, LogNNTransform) | |
| 295 | - | |
| 296 | 98 | } // namespace br |
| 297 | 99 | |
| 298 | -#include "cluster.moc" | |
| 100 | +#include "cluster/knn.moc" | ... | ... |
openbr/plugins/cluster/lognn.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <fstream> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup transforms | |
| 26 | + * \brief Log nearest neighbors to specified file. | |
| 27 | + * \author Charles Otto \cite caotto | |
| 28 | + */ | |
| 29 | +class LogNNTransform : public TimeVaryingTransform | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + | |
| 33 | + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) | |
| 34 | + BR_PROPERTY(QString, fileName, "") | |
| 35 | + | |
| 36 | + std::fstream fout; | |
| 37 | + | |
| 38 | + void projectUpdate(const Template &src, Template &dst) | |
| 39 | + { | |
| 40 | + dst = src; | |
| 41 | + | |
| 42 | + if (!dst.file.contains("neighbors")) { | |
| 43 | + fout << std::endl; | |
| 44 | + return; | |
| 45 | + } | |
| 46 | + | |
| 47 | + Neighbors neighbors = dst.file.get<Neighbors>("neighbors"); | |
| 48 | + if (neighbors.isEmpty() ) { | |
| 49 | + fout << std::endl; | |
| 50 | + return; | |
| 51 | + } | |
| 52 | + | |
| 53 | + QString aLine; | |
| 54 | + aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second)); | |
| 55 | + for (int i=1; i < neighbors.size();i++) | |
| 56 | + aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second)); | |
| 57 | + | |
| 58 | + fout << qPrintable(aLine) << std::endl; | |
| 59 | + } | |
| 60 | + | |
| 61 | + void init() | |
| 62 | + { | |
| 63 | + if (!fileName.isEmpty()) | |
| 64 | + fout.open(qPrintable(fileName), std::ios_base::out); | |
| 65 | + } | |
| 66 | + | |
| 67 | + void finalize(TemplateList &output) | |
| 68 | + { | |
| 69 | + (void) output; | |
| 70 | + fout.close(); | |
| 71 | + } | |
| 72 | + | |
| 73 | +public: | |
| 74 | + LogNNTransform() : TimeVaryingTransform(false, false) {} | |
| 75 | +}; | |
| 76 | + | |
| 77 | +BR_REGISTER(Transform, LogNNTransform) | |
| 78 | + | |
| 79 | +} // namespace br | |
| 80 | + | |
| 81 | +#include "cluster/lognn.moc" | ... | ... |
openbr/plugins/cluster/randomcentroids.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <opencv2/flann/flann.hpp> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/common.h> | |
| 21 | +#include <openbr/core/opencvutils.h> | |
| 22 | + | |
| 23 | +using namespace cv; | |
| 24 | + | |
| 25 | +namespace br | |
| 26 | +{ | |
| 27 | + | |
| 28 | +/*! | |
| 29 | + * \ingroup transforms | |
| 30 | + * \brief Chooses k random points to be centroids. | |
| 31 | + * \author Austin Blanton \cite imaus10 | |
| 32 | + * \see KMeansTransform | |
| 33 | + */ | |
| 34 | +class RandomCentroidsTransform : public Transform | |
| 35 | +{ | |
| 36 | + Q_OBJECT | |
| 37 | + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | |
| 38 | + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | |
| 39 | + BR_PROPERTY(int, kTrain, 256) | |
| 40 | + BR_PROPERTY(int, kSearch, 1) | |
| 41 | + | |
| 42 | + Mat centers; | |
| 43 | + mutable QScopedPointer<flann::Index> index; | |
| 44 | + mutable QMutex mutex; | |
| 45 | + | |
| 46 | + void reindex() | |
| 47 | + { | |
| 48 | + index.reset(new flann::Index(centers, flann::LinearIndexParams())); | |
| 49 | + } | |
| 50 | + | |
| 51 | + void train(const TemplateList &data) | |
| 52 | + { | |
| 53 | + Mat flat = OpenCVUtils::toMatByRow(data.data()); | |
| 54 | + QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true); | |
| 55 | + foreach (const int &idx, sample) | |
| 56 | + centers.push_back(flat.row(idx)); | |
| 57 | + reindex(); | |
| 58 | + } | |
| 59 | + | |
| 60 | + void project(const Template &src, Template &dst) const | |
| 61 | + { | |
| 62 | + QMutexLocker locker(&mutex); | |
| 63 | + Mat dists, indicies; | |
| 64 | + index->knnSearch(src, indicies, dists, kSearch); | |
| 65 | + dst = indicies.reshape(1, 1); | |
| 66 | + } | |
| 67 | + | |
| 68 | + void load(QDataStream &stream) | |
| 69 | + { | |
| 70 | + stream >> centers; | |
| 71 | + reindex(); | |
| 72 | + } | |
| 73 | + | |
| 74 | + void store(QDataStream &stream) const | |
| 75 | + { | |
| 76 | + stream << centers; | |
| 77 | + } | |
| 78 | +}; | |
| 79 | + | |
| 80 | +BR_REGISTER(Transform, RandomCentroidsTransform) | |
| 81 | + | |
| 82 | +} //namespace br | |
| 83 | + | |
| 84 | +#include "cluster/randomcentroids.moc" | ... | ... |
openbr/plugins/dlib.cmake renamed to openbr/plugins/cmake/dlib.cmake
| ... | ... | @@ -5,7 +5,7 @@ if(${BR_WITH_DLIB}) |
| 5 | 5 | |
| 6 | 6 | add_definitions(-DDLIB_NO_GUI_SUPPORT) |
| 7 | 7 | |
| 8 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/dlib.cpp) | |
| 8 | + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/classification/dlib.cpp) | |
| 9 | 9 | set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${DLib_DIR}/dlib/all/source.cpp) |
| 10 | 10 | |
| 11 | 11 | #install(DIRECTORY ${DLib_DIR}/models/ DESTINATION share/openbr/models/dlib) | ... | ... |
openbr/plugins/cmake/eigen3.cmake
0 → 100644
| 1 | +set(BR_WITH_EIGEN3 ON CACHE BOOL "Build Eigen3 plugins") | |
| 2 | + | |
| 3 | +if(${BR_WITH_EIGEN3}) | |
| 4 | + find_package(Eigen3 REQUIRED) | |
| 5 | + install(FILES ${EIGEN3_LICENSE} RENAME Eigen3 DESTINATION share/openbr/licenses) | |
| 6 | +else() | |
| 7 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/lda.cpp) | |
| 8 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/distance/L1.cpp) | |
| 9 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/distance/L2.cpp) | |
| 10 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp) | |
| 11 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/integralsampler.cpp) | |
| 12 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/recursiveintegralsampler.cpp) | |
| 13 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/consolidatedetections.cpp) | |
| 14 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/delaunay.cpp) | |
| 15 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/procrustes.cpp) | |
| 16 | +endif() | ... | ... |
openbr/plugins/ipc2013.cmake renamed to openbr/plugins/cmake/ipc2013.cmake
| ... | ... | @@ -2,7 +2,8 @@ set(BR_WITH_IPC2013 OFF CACHE BOOL "Build with Intel Perceptual Computing SDK 20 |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_IPC2013}) |
| 4 | 4 | find_package(IPC2013 REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/ipc2013.cpp) | |
| 6 | 5 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${IPC2013_LIBS}) |
| 7 | 6 | install(DIRECTORY ${IPC2013_DIR}/bin/x64/ DESTINATION bin) |
| 7 | +else() | |
| 8 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/ipc2013.cpp) | |
| 8 | 9 | endif() | ... | ... |
openbr/plugins/jni.cmake renamed to openbr/plugins/cmake/jni.cmake
| ... | ... | @@ -3,10 +3,10 @@ set(BR_WITH_JAVA OFF CACHE BOOL "Use Java Code") |
| 3 | 3 | if (${BR_WITH_JAVA}) |
| 4 | 4 | find_package(JNI REQUIRED) |
| 5 | 5 | find_package(JAVA REQUIRED) |
| 6 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/jni.cpp) | |
| 7 | 6 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES}) |
| 8 | 7 | |
| 9 | 8 | include_directories(${JAVA_INCLUDE_PATH}) |
| 10 | 9 | include_directories(${JAVA_INCLUDE_PATH2}) |
| 11 | - | |
| 10 | +else() | |
| 11 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/jni.cpp) | |
| 12 | 12 | endif() | ... | ... |
openbr/plugins/cmake/libav.cmake
0 → 100644
| 1 | +set(BR_WITH_LIBAV OFF CACHE BOOL "Build with LibAV") | |
| 2 | + | |
| 3 | +if(${BR_WITH_LIBAV}) | |
| 4 | + find_package(LibAV REQUIRED) | |
| 5 | + include_directories(${LIBAV_INCLUDE_DIR}) | |
| 6 | + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${LIBAV_LIBRARIES}) | |
| 7 | + | |
| 8 | + foreach(LIBAV_LIB ${LIBAV_LIBRARIES}) | |
| 9 | + install(FILES ${LIBAV_LIB} DESTINATION lib) | |
| 10 | + endforeach() | |
| 11 | +else() | |
| 12 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/keyframes.cpp) | |
| 13 | +endif() | ... | ... |
openbr/plugins/liblinear.cmake renamed to openbr/plugins/cmake/liblinear.cmake
| ... | ... | @@ -3,5 +3,6 @@ set(BR_WITH_LIBLINEAR OFF CACHE BOOL "Build with LibLinear") |
| 3 | 3 | if(${BR_WITH_LIBLINEAR}) |
| 4 | 4 | find_package(LibLinear REQUIRED) |
| 5 | 5 | set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${LibLinear_SRC}) |
| 6 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/liblinear.cpp) | |
| 6 | +else() | |
| 7 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/liblinear.cpp) | |
| 7 | 8 | endif() | ... | ... |
openbr/plugins/likely.cmake renamed to openbr/plugins/cmake/likely.cmake
| ... | ... | @@ -2,6 +2,9 @@ set(BR_WITH_LIKELY OFF CACHE BOOL "Build with Likely") |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_LIKELY}) |
| 4 | 4 | find_package(Likely REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/likely.cpp) | |
| 6 | 5 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS}) |
| 6 | +else() | |
| 7 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/likely.cpp) | |
| 8 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/lmat.cpp) | |
| 9 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lmat.cpp) | |
| 7 | 10 | endif() | ... | ... |
openbr/plugins/mongoose.cmake renamed to openbr/plugins/cmake/mongoose.cmake
| 1 | 1 | set(BR_WITH_MONGOOSE OFF CACHE BOOL "Build with Mongoose") |
| 2 | 2 | if(${BR_WITH_MONGOOSE}) |
| 3 | 3 | find_package(Mongoose) |
| 4 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/mongoose.cpp ${MONGOOSE_SRC}) | |
| 4 | + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${MONGOOSE_SRC}) | |
| 5 | 5 | install(FILES ${MONGOOSE_LICENSE} RENAME mongoose DESTINATION share/openbr/licenses) |
| 6 | +else() | |
| 7 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/mongoose.cpp) | |
| 6 | 8 | endif() | ... | ... |
openbr/plugins/qtnetwork.cmake renamed to openbr/plugins/cmake/network.cmake
| ... | ... | @@ -3,6 +3,10 @@ if(${BR_WITH_QTNETWORK}) |
| 3 | 3 | find_package(Qt5Network) |
| 4 | 4 | find_package(HttpParser) |
| 5 | 5 | set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Network) |
| 6 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/qtnetwork.cpp ${HTTPPARSER_SRC}) | |
| 6 | + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${HTTPPARSER_SRC}) | |
| 7 | 7 | install(FILES ${HTTPPARSER_LICENSE} RENAME http-parser DESTINATION share/openbr/licenses) |
| 8 | +else() | |
| 9 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/url.cpp) | |
| 10 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/post.cpp) | |
| 11 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/post.cpp) | |
| 8 | 12 | endif() | ... | ... |
openbr/plugins/nt4.cmake renamed to openbr/plugins/cmake/nt4.cmake
| ... | ... | @@ -2,7 +2,8 @@ set(BR_WITH_NT4 OFF CACHE BOOL "Build with Neurotec Biometric 4") |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_NT4}) |
| 4 | 4 | find_package(NT4 REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/nt4.cpp) | |
| 6 | 5 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${NT4_LIBS}) |
| 7 | 6 | install(DIRECTORY ${NT4_DIR_LIB}/ DESTINATION lib) |
| 7 | +else() | |
| 8 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/nt4.cpp) | |
| 8 | 9 | endif() | ... | ... |
openbr/plugins/pp4.cmake renamed to openbr/plugins/cmake/pp4.cmake
| ... | ... | @@ -2,8 +2,9 @@ set(BR_WITH_PP4 OFF CACHE BOOL "Build with PittPatt 4") |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_PP4}) |
| 4 | 4 | find_package(PP4 REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp) | |
| 6 | 5 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS}) |
| 7 | 6 | install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib) |
| 8 | 7 | install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4) |
| 8 | +else() | |
| 9 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp4.cpp) | |
| 9 | 10 | endif() | ... | ... |
openbr/plugins/pp5.cmake renamed to openbr/plugins/cmake/pp5.cmake
| ... | ... | @@ -2,7 +2,6 @@ set(BR_WITH_PP5 OFF CACHE BOOL "Build with PittPatt 5") |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_PP5}) |
| 4 | 4 | find_package(PP5 REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp5.cpp) | |
| 6 | 5 | set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP5_LIBS}) |
| 7 | 6 | |
| 8 | 7 | if(WIN32) |
| ... | ... | @@ -12,4 +11,6 @@ if(${BR_WITH_PP5}) |
| 12 | 11 | endif() |
| 13 | 12 | |
| 14 | 13 | install(DIRECTORY ${PP5_DIR}/models/ DESTINATION share/openbr/models/pp5) |
| 14 | +else() | |
| 15 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp5.cpp) | |
| 15 | 16 | endif() | ... | ... |
openbr/plugins/cmake/show.cmake
0 → 100644
openbr/plugins/stasm4.cmake renamed to openbr/plugins/cmake/stasm4.cmake
| ... | ... | @@ -2,14 +2,9 @@ set(BR_WITH_STASM4 ON CACHE BOOL "Build with Stasm") |
| 2 | 2 | |
| 3 | 3 | if(${BR_WITH_STASM4}) |
| 4 | 4 | find_package(Stasm4 REQUIRED) |
| 5 | - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/stasm4.cpp) | |
| 6 | - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Stasm4_LIBS}) | |
| 7 | - | |
| 8 | - if(WIN32) | |
| 9 | - install(DIRECTORY ${Stasm_DIR}/build/ DESTINATION bin) | |
| 10 | - else() | |
| 11 | - install(DIRECTORY ${Stasm_DIR}/build/ DESTINATION lib) | |
| 12 | - endif() | |
| 13 | - | |
| 5 | + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${Stasm_SRC}) | |
| 14 | 6 | install(DIRECTORY ${Stasm_DIR}/data/ DESTINATION share/openbr/models/stasm) |
| 7 | +else() | |
| 8 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/stasm4.cpp) | |
| 9 | + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp) | |
| 15 | 10 | endif() | ... | ... |
openbr/plugins/algorithms.cpp renamed to openbr/plugins/core/algorithms.cpp
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | * limitations under the License. * |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | -#include "openbr_internal.h" | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | 18 | |
| 19 | 19 | namespace br |
| 20 | 20 | { |
| ... | ... | @@ -43,7 +43,7 @@ class AlgorithmsInitializer : public Initializer |
| 43 | 43 | Globals->abbreviations.insert("OpenBR", "FaceRecognition"); |
| 44 | 44 | Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); |
| 45 | 45 | Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); |
| 46 | - Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+Bin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+Bin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1"); | |
| 46 | + Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+HistBin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+HistBin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1"); | |
| 47 | 47 | Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)"); |
| 48 | 48 | Globals->abbreviations.insert("4SF", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Cat+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)"); |
| 49 | 49 | |
| ... | ... | @@ -55,9 +55,9 @@ class AlgorithmsInitializer : public Initializer |
| 55 | 55 | Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard"); |
| 56 | 56 | Globals->abbreviations.insert("ShowMotionSegmentation", "DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard"); |
| 57 | 57 | |
| 58 | - Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | |
| 59 | - Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); | |
| 60 | - Globals->abbreviations.insert("HOGHOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+(OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | |
| 58 | + Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | |
| 59 | + Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); | |
| 60 | + Globals->abbreviations.insert("HOGHOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+(OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat+Contract)/(First+Cvt(Gray)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+HistBin(0,360,8)+Hist(8)+Cat+Contract)+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | |
| 61 | 61 | |
| 62 | 62 | // Generic Image Processing |
| 63 | 63 | Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); |
| ... | ... | @@ -66,7 +66,7 @@ class AlgorithmsInitializer : public Initializer |
| 66 | 66 | Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); |
| 67 | 67 | Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); |
| 68 | 68 | Globals->abbreviations.insert("ImageSimilarity", "Open+EnsureChannels(3)+Resize(256,256)+SplitChannels+RectRegions(64,64,64,64)+Hist(256,0,8)+Cat:NegativeLogPlusOne(L2)"); |
| 69 | - Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+Bin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Singleton(KMeans(256)))+Cat+CvtFloat+Hist(256)+KNN(5,Dist(L1),false,5)+Rename(KNN,Subject)"); | |
| 69 | + Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+HistBin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Singleton(KMeans(256)))+Cat+CvtFloat+Hist(256)+KNN(5,Dist(L1),false,5)+Rename(KNN,Subject)"); | |
| 70 | 70 | Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)"); |
| 71 | 71 | |
| 72 | 72 | // Hash |
| ... | ... | @@ -89,7 +89,7 @@ class AlgorithmsInitializer : public Initializer |
| 89 | 89 | // Transforms |
| 90 | 90 | Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); |
| 91 | 91 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); |
| 92 | - Globals->abbreviations.insert("DenseHOG", "Gradient+RectRegions(8,8,6,6)+Bin(0,360,8)+Hist(8)"); | |
| 92 | + Globals->abbreviations.insert("DenseHOG", "Gradient+RectRegions(8,8,6,6)+HistBin(0,360,8)+Hist(8)"); | |
| 93 | 93 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 94 | 94 | Globals->abbreviations.insert("DenseSIFT2", "(Grid(5,5)+SIFTDescriptor(12)+ByRow)"); |
| 95 | 95 | Globals->abbreviations.insert("FaceRecognitionRegistration", "ASEFEyes+Affine(88,88,0.25,0.35)"); |
| ... | ... | @@ -108,4 +108,4 @@ BR_REGISTER(Initializer, AlgorithmsInitializer) |
| 108 | 108 | |
| 109 | 109 | } // namespace br |
| 110 | 110 | |
| 111 | -#include "algorithms.moc" | |
| 111 | +#include "core/algorithms.moc" | ... | ... |
openbr/plugins/core/align.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2015 Noblis * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <opencv2/opencv.hpp> | |
| 18 | +#include "openbr/plugins/openbr_internal.h" | |
| 19 | +#include "openbr/core/qtutils.h" | |
| 20 | +#include "openbr/core/opencvutils.h" | |
| 21 | +#include "openbr/core/eigenutils.h" | |
| 22 | +#include "openbr/core/common.h" | |
| 23 | +#include <QString> | |
| 24 | +#include <Eigen/SVD> | |
| 25 | +#include <Eigen/Dense> | |
| 26 | + | |
| 27 | +using namespace std; | |
| 28 | +using namespace cv; | |
| 29 | +using namespace Eigen; | |
| 30 | + | |
| 31 | +namespace br | |
| 32 | +{ | |
| 33 | + | |
| 34 | +/*! | |
| 35 | + * \ingroup transforms | |
| 36 | + * \brief Improved procrustes alignment of points, to include a post processing scaling of points | |
| 37 | + * to faciliate subsequent texture mapping. | |
| 38 | + * \author Brendan Klare \cite bklare | |
| 39 | + * \param width Width of output coordinate space (before padding) | |
| 40 | + * \param padding Amount of padding around the coordinate space | |
| 41 | + * \param useFirst whether or not to use the first instance as the reference object | |
| 42 | + */ | |
| 43 | +class ProcrustesAlignTransform : public Transform | |
| 44 | +{ | |
| 45 | + Q_OBJECT | |
| 46 | + | |
| 47 | + Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false) | |
| 48 | + Q_PROPERTY(float padding READ get_padding WRITE set_padding RESET reset_padding STORED false) | |
| 49 | + Q_PROPERTY(bool useFirst READ get_useFirst WRITE set_useFirst RESET reset_useFirst STORED false) | |
| 50 | + BR_PROPERTY(float, width, 80) | |
| 51 | + BR_PROPERTY(float, padding, 8) | |
| 52 | + BR_PROPERTY(bool, useFirst, false) | |
| 53 | + | |
| 54 | + | |
| 55 | + Eigen::MatrixXf referenceShape; | |
| 56 | + float minX; | |
| 57 | + float minY; | |
| 58 | + float maxX; | |
| 59 | + float maxY; | |
| 60 | + float aspectRatio; | |
| 61 | + | |
| 62 | + void init() { | |
| 63 | + aspectRatio = 0; | |
| 64 | + } | |
| 65 | + | |
| 66 | + static MatrixXf getRotation(MatrixXf ref, MatrixXf sample) { | |
| 67 | + MatrixXf R = sample.transpose() * ref; | |
| 68 | + JacobiSVD<MatrixXf> svd(R, ComputeFullU | ComputeFullV); | |
| 69 | + R = svd.matrixU() * svd.matrixV().transpose(); | |
| 70 | + return R; | |
| 71 | + } | |
| 72 | + | |
| 73 | + //Converts x y points in a single vector to two column matrix | |
| 74 | + static MatrixXf vectorToMatrix(MatrixXf vector) { | |
| 75 | + int n = vector.rows(); | |
| 76 | + MatrixXf matrix(n / 2, 2); | |
| 77 | + for (int i = 0; i < n / 2; i++) { | |
| 78 | + for (int j = 0; j < 2; j++) { | |
| 79 | + matrix(i, j) = vector(i * 2 + j); | |
| 80 | + } | |
| 81 | + } | |
| 82 | + return matrix; | |
| 83 | + } | |
| 84 | + | |
| 85 | + static MatrixXf matrixToVector(MatrixXf matrix) { | |
| 86 | + int n2 = matrix.rows(); | |
| 87 | + MatrixXf vector(n2 * 2, 1); | |
| 88 | + for (int i = 0; i < n2; i++) { | |
| 89 | + for (int j = 0; j < 2; j++) { | |
| 90 | + vector(i * 2 + j) = matrix(i, j); | |
| 91 | + } | |
| 92 | + } | |
| 93 | + return vector; | |
| 94 | + } | |
| 95 | + | |
| 96 | + void train(const TemplateList &data) | |
| 97 | + { | |
| 98 | + MatrixXf points(data[0].file.points().size() * 2, data.size()); | |
| 99 | + | |
| 100 | + // Normalize all sets of points | |
| 101 | + int skip = 0; | |
| 102 | + for (int j = 0; j < data.size(); j++) { | |
| 103 | + QList<QPointF> imagePoints = data[j].file.points(); | |
| 104 | + if (imagePoints.size() == 0) { | |
| 105 | + skip++; | |
| 106 | + continue; | |
| 107 | + } | |
| 108 | + | |
| 109 | + float meanX = 0, | |
| 110 | + meanY = 0; | |
| 111 | + for (int i = 0; i < imagePoints.size(); i++) { | |
| 112 | + points(i * 2, j - skip) = imagePoints[i].x(); | |
| 113 | + points(i * 2 + 1, j - skip) = imagePoints[i].y(); | |
| 114 | + | |
| 115 | + meanX += imagePoints[i].x(); | |
| 116 | + meanY += imagePoints[i].y(); | |
| 117 | + } | |
| 118 | + | |
| 119 | + meanX /= imagePoints.size(); | |
| 120 | + meanY /= imagePoints.size(); | |
| 121 | + | |
| 122 | + for (int i = 0; i < imagePoints.size(); i++) { | |
| 123 | + points(i * 2, j - skip) -= meanX; | |
| 124 | + points(i * 2 + 1, j - skip) -= meanY; | |
| 125 | + } | |
| 126 | + } | |
| 127 | + | |
| 128 | + points = MatrixXf(points.leftCols(data.size() - skip)); | |
| 129 | + | |
| 130 | + //normalize scale | |
| 131 | + for (int i = 0; i < points.cols(); i++) | |
| 132 | + points.col(i) = points.col(i) / points.col(i).norm(); | |
| 133 | + | |
| 134 | + //Normalize rotation | |
| 135 | + if (!useFirst) { | |
| 136 | + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); | |
| 137 | + } else { | |
| 138 | + referenceShape = vectorToMatrix(points.col(0)); | |
| 139 | + } | |
| 140 | + | |
| 141 | + for (int i = 0; i < points.cols(); i++) { | |
| 142 | + MatrixXf p = vectorToMatrix(points.col(i)); | |
| 143 | + MatrixXf R = getRotation(referenceShape, p); | |
| 144 | + points.col(i) = matrixToVector(p * R); | |
| 145 | + } | |
| 146 | + | |
| 147 | + //Choose crop boundaries and adjustments that captures most data | |
| 148 | + MatrixXf minXs(points.cols(),1); | |
| 149 | + MatrixXf minYs(points.cols(),1); | |
| 150 | + MatrixXf maxXs(points.cols(),1); | |
| 151 | + MatrixXf maxYs(points.cols(),1); | |
| 152 | + for (int j = 0; j < points.cols(); j++) { | |
| 153 | + minX = FLT_MAX, | |
| 154 | + minY = FLT_MAX, | |
| 155 | + maxX = -FLT_MAX, | |
| 156 | + maxY = -FLT_MAX; | |
| 157 | + for (int i = 0; i < points.rows(); i++) { | |
| 158 | + if (i % 2 == 0) { | |
| 159 | + if (points(i,j) > maxX) | |
| 160 | + maxX = points(i, j); | |
| 161 | + if (points(i,j) < minX) | |
| 162 | + minX = points(i, j); | |
| 163 | + } else { | |
| 164 | + if (points(i,j) > maxY) | |
| 165 | + maxY = points(i, j); | |
| 166 | + if (points(i,j) < minY) | |
| 167 | + minY = points(i, j); | |
| 168 | + } | |
| 169 | + } | |
| 170 | + | |
| 171 | + minXs(j) = minX; | |
| 172 | + maxXs(j) = maxX; | |
| 173 | + minYs(j) = minY; | |
| 174 | + maxYs(j) = maxY; | |
| 175 | + } | |
| 176 | + | |
| 177 | + minX = minXs.mean() - 0 * EigenUtils::stddev(minXs); | |
| 178 | + minY = minYs.mean() - 0 * EigenUtils::stddev(minYs); | |
| 179 | + maxX = maxXs.mean() + 0 * EigenUtils::stddev(maxXs); | |
| 180 | + maxY = maxYs.mean() + 0 * EigenUtils::stddev(maxYs); | |
| 181 | + aspectRatio = (maxX - minX) / (maxY - minY); | |
| 182 | + } | |
| 183 | + | |
| 184 | + void project(const Template &src, Template &dst) const | |
| 185 | + { | |
| 186 | + QList<QPointF> imagePoints = src.file.points(); | |
| 187 | + if (imagePoints.size() == 0) { | |
| 188 | + dst.file.fte = true; | |
| 189 | + qDebug() << "No points for file " << src.file.name; | |
| 190 | + return; | |
| 191 | + } | |
| 192 | + | |
| 193 | + MatrixXf p(imagePoints.size() * 2, 1); | |
| 194 | + for (int i = 0; i < imagePoints.size(); i++) { | |
| 195 | + p(i * 2) = imagePoints[i].x(); | |
| 196 | + p(i * 2 + 1) = imagePoints[i].y(); | |
| 197 | + } | |
| 198 | + p = vectorToMatrix(p); | |
| 199 | + | |
| 200 | + //Normalize translation | |
| 201 | + p.col(0) = p.col(0) - MatrixXf::Ones(p.rows(),1) * (p.col(0).sum() / p.rows()); | |
| 202 | + p.col(1) = p.col(1) - MatrixXf::Ones(p.rows(),1) * (p.col(1).sum() / p.rows()); | |
| 203 | + | |
| 204 | + //Normalize scale | |
| 205 | + p /= matrixToVector(p).norm(); | |
| 206 | + | |
| 207 | + //Normalize rotation | |
| 208 | + MatrixXf R = getRotation(referenceShape, p); | |
| 209 | + p = p * R; | |
| 210 | + | |
| 211 | + //Translate and scale into output space and store in output list | |
| 212 | + QList<QPointF> procrustesPoints; | |
| 213 | + for (int i = 0; i < p.rows(); i++) | |
| 214 | + procrustesPoints.append( QPointF( | |
| 215 | + (p(i, 0) - minX) / (maxX - minX) * (width - 1) + padding, | |
| 216 | + (p(i, 1) - minY) / (maxY - minY) * (qRound( width / aspectRatio) - 1) + padding)); | |
| 217 | + | |
| 218 | + dst = src; | |
| 219 | + dst.file.setList<QPointF>("ProcrustesPoints", procrustesPoints); | |
| 220 | + dst.file.set("ProcrustesBound", QRectF(0, 0, width + 2 * padding, (qRound(width / aspectRatio) + 2 * padding))); | |
| 221 | + dst.file.set("ProcrustesPadding", padding); | |
| 222 | + } | |
| 223 | + | |
| 224 | + void store(QDataStream &stream) const | |
| 225 | + { | |
| 226 | + stream << referenceShape; | |
| 227 | + stream << minX; | |
| 228 | + stream << minY; | |
| 229 | + stream << maxX; | |
| 230 | + stream << maxY; | |
| 231 | + stream << aspectRatio; | |
| 232 | + } | |
| 233 | + | |
| 234 | + void load(QDataStream &stream) | |
| 235 | + { | |
| 236 | + stream >> referenceShape; | |
| 237 | + stream >> minX; | |
| 238 | + stream >> minY; | |
| 239 | + stream >> maxX; | |
| 240 | + stream >> maxY; | |
| 241 | + stream >> aspectRatio; | |
| 242 | + } | |
| 243 | +}; | |
| 244 | +BR_REGISTER(Transform, ProcrustesAlignTransform) | |
| 245 | + | |
| 246 | +/*! | |
| 247 | + * \ingroup transforms | |
| 248 | + * \brief Maps texture from one set of points to another. Assumes that points are rigidly transformed | |
| 249 | + * \author Brendan Klare \cite bklare | |
| 250 | + * \author Scott Klum \cite sklum | |
| 251 | + */ | |
| 252 | +class TextureMapTransform : public UntrainableTransform | |
| 253 | +{ | |
| 254 | + Q_OBJECT | |
| 255 | + | |
| 256 | +public: | |
| 257 | + static QRectF getBounds(const QList<QPointF> &points, int dstPadding) | |
| 258 | + { | |
| 259 | + float srcMinX = FLT_MAX; | |
| 260 | + float srcMinY = FLT_MAX; | |
| 261 | + float srcMaxX = -FLT_MAX; | |
| 262 | + float srcMaxY = -FLT_MAX; | |
| 263 | + foreach (const QPointF &point, points) { | |
| 264 | + if (point.x() < srcMinX) srcMinX = point.x(); | |
| 265 | + if (point.y() < srcMinY) srcMinY = point.y(); | |
| 266 | + if (point.x() > srcMaxX) srcMaxX = point.x(); | |
| 267 | + if (point.y() > srcMaxY) srcMaxY = point.y(); | |
| 268 | + } | |
| 269 | + | |
| 270 | + const float padding = (srcMaxX - srcMinX) / 80 * dstPadding; | |
| 271 | + return QRectF(qRound(srcMinX - padding), qRound(srcMinY - padding), qRound(srcMaxX - srcMinX + 2 * padding), qRound(srcMaxY - srcMinY + 2 * padding)); | |
| 272 | + } | |
| 273 | + | |
| 274 | + static int getVertexIndex(const QPointF &trianglePts, const QList<QPointF> &pts) | |
| 275 | + { | |
| 276 | + for (int i = 0; i < pts.size(); i++) | |
| 277 | + // Check points using single precision accuracy to avoid potential rounding error | |
| 278 | + if ((float(trianglePts.x()) == float(pts[i].x())) && (float(trianglePts.y()) == float(pts[i].y()))) | |
| 279 | + return i; | |
| 280 | + qFatal("Couldn't identify index of requested point!"); | |
| 281 | + return -1; | |
| 282 | + } | |
| 283 | + | |
| 284 | + static QList<QPointF> addBounds(QList<QPointF> points, const QRectF &bound) | |
| 285 | + { | |
| 286 | + points.append(bound.topLeft()); | |
| 287 | + points.append(QPointF(bound.right() - 1, bound.top())); | |
| 288 | + points.append(QPointF(bound.left(), bound.bottom() - 1)); | |
| 289 | + points.append(QPointF(bound.right() - 1, bound.bottom() - 1)); | |
| 290 | + return points; | |
| 291 | + } | |
| 292 | + | |
| 293 | + static QList<QPointF> removeBounds(const QList<QPointF> &points) | |
| 294 | + { | |
| 295 | + return points.mid(0, points.size() - 4); | |
| 296 | + } | |
| 297 | + | |
| 298 | + //Expand out bounds placed at end of point list by addBounds | |
| 299 | + static QList<QPointF> expandBounds(QList<QPointF> points, int pad) | |
| 300 | + { | |
| 301 | + const int n = points.size(); | |
| 302 | + points[n-4] = QPointF(points[n-4].x() - pad, points[n-4].y() - pad); | |
| 303 | + points[n-3] = QPointF(points[n-3].x() + pad, points[n-3].y() - pad); | |
| 304 | + points[n-2] = QPointF(points[n-2].x() - pad, points[n-2].y() + pad); | |
| 305 | + points[n-1] = QPointF(points[n-1].x() + pad, points[n-1].y() + pad); | |
| 306 | + return points; | |
| 307 | + } | |
| 308 | + | |
| 309 | + //Contract in bounds placed at end of point list by addBounds | |
| 310 | + static QList<QPointF> contractBounds(QList<QPointF> points, int pad) | |
| 311 | + { | |
| 312 | + const int n = points.size(); | |
| 313 | + points[n-4] = QPointF(points[n-4].x() + pad, points[n-4].y() + pad); | |
| 314 | + points[n-3] = QPointF(points[n-3].x() - pad, points[n-3].y() + pad); | |
| 315 | + points[n-2] = QPointF(points[n-2].x() + pad, points[n-2].y() - pad); | |
| 316 | + points[n-1] = QPointF(points[n-1].x() - pad, points[n-1].y() - pad); | |
| 317 | + return points; | |
| 318 | + } | |
| 319 | + | |
| 320 | + static QList<QList<int> > getTriangulation(const QList<QPointF> &points, const QRectF &bound) | |
| 321 | + { | |
| 322 | + Subdiv2D subdiv(OpenCVUtils::toRect(bound)); | |
| 323 | + foreach (const QPointF &point, points) { | |
| 324 | + if (!bound.contains(point)) | |
| 325 | + return QList<QList<int> >(); | |
| 326 | + subdiv.insert(OpenCVUtils::toPoint(point)); | |
| 327 | + } | |
| 328 | + | |
| 329 | + | |
| 330 | + vector<Vec6f> triangleList; | |
| 331 | + subdiv.getTriangleList(triangleList); | |
| 332 | + | |
| 333 | + QList<QList<int> > triangleIndices; | |
| 334 | + foreach (const Vec6f &triangle, triangleList) { | |
| 335 | + bool valid = true; | |
| 336 | + const QPointF vertices[3] = { QPointF(triangle[0], triangle[1]), | |
| 337 | + QPointF(triangle[2], triangle[3]), | |
| 338 | + QPointF(triangle[4], triangle[5]) }; | |
| 339 | + for (int j = 0; j < 3; j++) | |
| 340 | + if (vertices[j].x() > bound.right() || vertices[j].y() > bound.bottom() || vertices[j].x() < bound.left() || vertices[j].y() < bound.top()) { | |
| 341 | + valid = false; | |
| 342 | + break; | |
| 343 | + } | |
| 344 | + | |
| 345 | + if (valid) { | |
| 346 | + QList<int> tri; | |
| 347 | + for (int j = 0; j < 3; j++) | |
| 348 | + tri.append(getVertexIndex(vertices[j], points)); | |
| 349 | + triangleIndices.append(tri); | |
| 350 | + } | |
| 351 | + } | |
| 352 | + | |
| 353 | + return triangleIndices; | |
| 354 | + } | |
| 355 | + | |
| 356 | +private: | |
| 357 | + void project(const Template &src, Template &dst) const | |
| 358 | + { | |
| 359 | + QList<QPointF> dstPoints = dst.file.getList<QPointF>("ProcrustesPoints"); | |
| 360 | + QList<QPointF> srcPoints = dst.file.points(); | |
| 361 | + if (dstPoints.empty() || srcPoints.empty()) { | |
| 362 | + dst = src; | |
| 363 | + if (Globals->verbose) { | |
| 364 | + qWarning("Delauney triangulation failed because points or rects are empty."); | |
| 365 | + dst.file.fte = true; | |
| 366 | + } | |
| 367 | + return; | |
| 368 | + } | |
| 369 | + | |
| 370 | + QRectF dstBound = dst.file.get<QRectF>("ProcrustesBound"); | |
| 371 | + dstPoints = addBounds(dstPoints, dstBound); | |
| 372 | + | |
| 373 | + /*Add a wider bound for triangulation to prevent border triangles from being missing*/ | |
| 374 | + QRectF srcBound = getBounds(srcPoints, dst.file.get<int>("ProcrustesPadding") + 20); | |
| 375 | + srcPoints = addBounds(srcPoints, srcBound); | |
| 376 | + QList<QList<int> > triIndices = getTriangulation(srcPoints, srcBound); | |
| 377 | + | |
| 378 | + /*Remove wider bound for texture mapping*/ | |
| 379 | + srcPoints = removeBounds(srcPoints); | |
| 380 | + srcBound = getBounds(srcPoints, dst.file.get<int>("ProcrustesPadding")); | |
| 381 | + srcPoints = addBounds(srcPoints, srcBound); | |
| 382 | + | |
| 383 | + int dstWidth = dstBound.width() + dstBound.x(); | |
| 384 | + int dstHeight = dstBound.height() + dstBound.y(); | |
| 385 | + dst.m() = Mat::zeros(dstHeight, dstWidth, src.m().type()); | |
| 386 | + for (int i = 0; i < triIndices.size(); i++) { | |
| 387 | + Point2f srcPoint1[3]; | |
| 388 | + Point2f dstPoint1[3]; | |
| 389 | + for (int j = 0; j < 3; j++) { | |
| 390 | + srcPoint1[j] = OpenCVUtils::toPoint(srcPoints[triIndices[i][j]]); | |
| 391 | + dstPoint1[j] = OpenCVUtils::toPoint(dstPoints[triIndices[i][j]]); | |
| 392 | + } | |
| 393 | + | |
| 394 | + Mat buffer(dstHeight, dstWidth, src.m().type()); | |
| 395 | + warpAffine(src.m(), buffer, getAffineTransform(srcPoint1, dstPoint1), Size(dstBound.width(), dstBound.height())); | |
| 396 | + | |
| 397 | + Mat mask = Mat::zeros(dstHeight, dstWidth, CV_8UC1); | |
| 398 | + Point maskPoints[1][3]; | |
| 399 | + maskPoints[0][0] = dstPoint1[0]; | |
| 400 | + maskPoints[0][1] = dstPoint1[1]; | |
| 401 | + maskPoints[0][2] = dstPoint1[2]; | |
| 402 | + const Point* ppt = { maskPoints[0] }; | |
| 403 | + fillConvexPoly(mask, ppt, 3, Scalar(255, 255, 255), 8); | |
| 404 | + | |
| 405 | + for (int i = 0; i < dstHeight; i++) { | |
| 406 | + for (int j = 0; j < dstWidth; j++) { | |
| 407 | + if (mask.at<uchar>(i,j) == 255) { | |
| 408 | + if (dst.m().type() == CV_32FC3 || dst.m().type() == CV_8UC3) | |
| 409 | + dst.m().at<cv::Vec3b>(i,j) = buffer.at<cv::Vec3b>(i,j); | |
| 410 | + else if (dst.m().type() == CV_32F) | |
| 411 | + dst.m().at<float>(i,j) = buffer.at<float>(i,j); | |
| 412 | + else if (dst.m().type() == CV_8U) | |
| 413 | + dst.m().at<uchar>(i,j) = buffer.at<uchar>(i,j); | |
| 414 | + else | |
| 415 | + qFatal("Unsupported pixel format."); | |
| 416 | + } | |
| 417 | + } | |
| 418 | + } | |
| 419 | + | |
| 420 | + } | |
| 421 | + | |
| 422 | + dst.file = src.file; | |
| 423 | + dst.file.clearPoints(); | |
| 424 | + dst.file.clearRects(); | |
| 425 | + dst.file.remove("ProcrustesPoints"); | |
| 426 | + dst.file.remove("ProcrustesPadding"); | |
| 427 | + dst.file.remove("ProcrustesBounds"); | |
| 428 | + } | |
| 429 | +}; | |
| 430 | + | |
| 431 | +BR_REGISTER(Transform, TextureMapTransform) | |
| 432 | + | |
| 433 | +// SynthesizePointsTransform helper class | |
| 434 | +struct TriangleIndicies | |
| 435 | +{ | |
| 436 | + int indicies[3]; | |
| 437 | + | |
| 438 | + TriangleIndicies() | |
| 439 | + { | |
| 440 | + indicies[0] = 0; | |
| 441 | + indicies[1] = 0; | |
| 442 | + indicies[2] = 0; | |
| 443 | + } | |
| 444 | + | |
| 445 | + TriangleIndicies(QList<int> indexList) | |
| 446 | + { | |
| 447 | + assert(indexList.size() == 3); | |
| 448 | + qSort(indexList); | |
| 449 | + indicies[0] = indexList[0]; | |
| 450 | + indicies[1] = indexList[1]; | |
| 451 | + indicies[2] = indexList[2]; | |
| 452 | + } | |
| 453 | +}; | |
| 454 | + | |
| 455 | +inline bool operator==(const TriangleIndicies &a, const TriangleIndicies &b) | |
| 456 | +{ | |
| 457 | + return (a.indicies[0] == b.indicies[0]) && (a.indicies[1] == b.indicies[1]) && (a.indicies[2] == b.indicies[2]); | |
| 458 | +} | |
| 459 | + | |
| 460 | +inline uint qHash(const TriangleIndicies &key) | |
| 461 | +{ | |
| 462 | + return ::qHash(key.indicies[0]) ^ ::qHash(key.indicies[1]) ^ ::qHash(key.indicies[2]); | |
| 463 | +} | |
| 464 | + | |
| 465 | +QDataStream &operator<<(QDataStream &stream, const TriangleIndicies &ti) | |
| 466 | +{ | |
| 467 | + return stream << ti.indicies[0] << ti.indicies[1] << ti.indicies[2]; | |
| 468 | +} | |
| 469 | + | |
| 470 | +QDataStream &operator>>(QDataStream &stream, TriangleIndicies &ti) | |
| 471 | +{ | |
| 472 | + return stream >> ti.indicies[0] >> ti.indicies[1] >> ti.indicies[2]; | |
| 473 | +} | |
| 474 | + | |
| 475 | +/*! | |
| 476 | + * \ingroup transforms | |
| 477 | + * \brief Synthesize additional points via triangulation. | |
| 478 | + * \author Josh Klontz \cite jklontz | |
| 479 | + */ | |
| 480 | + class SynthesizePointsTransform : public MetadataTransform | |
| 481 | + { | |
| 482 | + Q_OBJECT | |
| 483 | + Q_PROPERTY(float minRelativeDistance READ get_minRelativeDistance WRITE set_minRelativeDistance RESET reset_minRelativeDistance STORED false) | |
| 484 | + BR_PROPERTY(float, minRelativeDistance, 0) // [0, 1] range controlling whether or not to nearby synthetic points. | |
| 485 | + // 0 = keep all points, 1 = keep only the most distance point. | |
| 486 | + | |
| 487 | + QList<TriangleIndicies> triangles; | |
| 488 | + | |
| 489 | + void train(const TemplateList &data) | |
| 490 | + { | |
| 491 | + // Because not all triangulations are the same, we have to decide on a canonical set of triangles at training time. | |
| 492 | + QHash<TriangleIndicies, int> counts; | |
| 493 | + foreach (const Template &datum, data) { | |
| 494 | + | |
| 495 | + const QList<QPointF> points = datum.file.points(); | |
| 496 | + if (points.size() == 0) | |
| 497 | + continue; | |
| 498 | + const QList< QList<int> > triangulation = TextureMapTransform::getTriangulation(points, TextureMapTransform::getBounds(points, 10)); | |
| 499 | + if (triangulation.empty()) | |
| 500 | + continue; | |
| 501 | + | |
| 502 | + foreach (const QList<int> &indicies, triangulation) | |
| 503 | + counts[TriangleIndicies(indicies)]++; | |
| 504 | + } | |
| 505 | + | |
| 506 | + triangles.clear(); | |
| 507 | + QHash<TriangleIndicies, int>::const_iterator i = counts.constBegin(); | |
| 508 | + while (i != counts.constEnd()) { | |
| 509 | + if (3 * i.value() > data.size()) | |
| 510 | + triangles.append(i.key()); // Keep triangles that occur in at least a third of the training instances | |
| 511 | + ++i; | |
| 512 | + } | |
| 513 | + | |
| 514 | + if (minRelativeDistance > 0) { // Discard relatively small triangles | |
| 515 | + QVector<float> averageMinDistances(triangles.size()); | |
| 516 | + foreach (const Template &datum, data) { | |
| 517 | + File dst; | |
| 518 | + projectMetadata(datum.file, dst); | |
| 519 | + const QList<QPointF> points = dst.points(); | |
| 520 | + | |
| 521 | + QVector<float> minDistances(triangles.size()); | |
| 522 | + for (int i=0; i<triangles.size(); i++) { | |
| 523 | + // Work backwards so that we can also consider distances between synthetic points | |
| 524 | + const QPointF &point = points[points.size()-1-i]; | |
| 525 | + float minDistance = std::numeric_limits<float>::max(); | |
| 526 | + for (int j=0; j<points.size()-1-i; j++) | |
| 527 | + minDistance = min(minDistance, sqrtf(powf(point.x() - points[j].x(), 2.f) + powf(point.y() - points[j].y(), 2.f))); | |
| 528 | + minDistances[triangles.size()-1-i] = minDistance; | |
| 529 | + } | |
| 530 | + | |
| 531 | + const float maxMinDistance = Common::Max(minDistances); | |
| 532 | + for (int i=0; i<minDistances.size(); i++) | |
| 533 | + averageMinDistances[i] += (minDistances[i] / maxMinDistance); | |
| 534 | + } | |
| 535 | + | |
| 536 | + const float maxAverageMinDistance = Common::Max(averageMinDistances); | |
| 537 | + for (int i=averageMinDistances.size()-1; i>=0; i--) | |
| 538 | + if (averageMinDistances[i] / maxAverageMinDistance < minRelativeDistance) | |
| 539 | + triangles.removeAt(i); | |
| 540 | + } | |
| 541 | + | |
| 542 | + if (Globals->verbose) | |
| 543 | + qDebug() << "Kept" << triangles.size() << "of" << counts.size() << "triangles."; | |
| 544 | + } | |
| 545 | + | |
| 546 | + void projectMetadata(const File &src, File &dst) const | |
| 547 | + { | |
| 548 | + QList<QPointF> points = src.points(); | |
| 549 | + if (points.size() == 0) { | |
| 550 | + dst.fte = true; | |
| 551 | + return; | |
| 552 | + } | |
| 553 | + | |
| 554 | + foreach (const TriangleIndicies &triangle, triangles) { | |
| 555 | + const QPointF &p0 = points[triangle.indicies[0]]; | |
| 556 | + const QPointF &p1 = points[triangle.indicies[1]]; | |
| 557 | + const QPointF &p2 = points[triangle.indicies[2]]; | |
| 558 | + points.append((p0 + p1 + p2) / 3 /* append the centroid of the triangle */); | |
| 559 | + } | |
| 560 | + dst.setPoints(points); | |
| 561 | + } | |
| 562 | + | |
| 563 | + void store(QDataStream &stream) const | |
| 564 | + { | |
| 565 | + stream << triangles; | |
| 566 | + } | |
| 567 | + | |
| 568 | + void load(QDataStream &stream) | |
| 569 | + { | |
| 570 | + stream >> triangles; | |
| 571 | + } | |
| 572 | + }; | |
| 573 | + BR_REGISTER(Transform, SynthesizePointsTransform) | |
| 574 | + | |
| 575 | +/*! | |
| 576 | + * \ingroup initializers | |
| 577 | + * \brief Initialize Procrustes croppings | |
| 578 | + * \author Brendan Klare \cite bklare | |
| 579 | + */ | |
| 580 | +class ProcrustesInitializer : public Initializer | |
| 581 | +{ | |
| 582 | + Q_OBJECT | |
| 583 | + | |
| 584 | + void initialize() const | |
| 585 | + { | |
| 586 | + Globals->abbreviations.insert("ProcrustesStasmFace","SelectPoints([17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76])+ProcrustesAlign(padding=6,width=120)+TextureMap+Resize(96,96)"); | |
| 587 | + Globals->abbreviations.insert("ProcrustesStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)"); | |
| 588 | + Globals->abbreviations.insert("ProcrustesStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=10)+TextureMap+Resize(36,48)"); | |
| 589 | + Globals->abbreviations.insert("ProcrustesStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)"); | |
| 590 | + Globals->abbreviations.insert("ProcrustesStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=12)+TextureMap+Resize(36,48)"); | |
| 591 | + Globals->abbreviations.insert("ProcrustesStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=10)+TextureMap+Resize(36,48)"); | |
| 592 | + Globals->abbreviations.insert("ProcrustesStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(36,48)"); | |
| 593 | + | |
| 594 | + Globals->abbreviations.insert("ProcrustesEyes","SelectPoints([19,20,21,22,23,24,25,26,27,28,29,30])+ProcrustesAlign(padding=8)+TextureMap+Resize(24,48)"); | |
| 595 | + Globals->abbreviations.insert("ProcrustesNose","SelectPoints([12,13,14,15,16,17,18])+ProcrustesAlign(padding=30)+TextureMap+Resize(36,48)"); | |
| 596 | + Globals->abbreviations.insert("ProcrustesMouth","SelectPoints([31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50])+ProcrustesAlign(padding=6)+TextureMap+Resize(36,48)"); | |
| 597 | + Globals->abbreviations.insert("ProcrustesBrow","SelectPoints([0,1,2,3,4,5,6,7,8,9])+ProcrustesAlign(padding=6)+TextureMap+Resize(24,48)"); | |
| 598 | + Globals->abbreviations.insert("ProcrustesFace","ProcrustesAlign(padding=6,width=120)+TextureMap+Resize(96,96)"); | |
| 599 | + | |
| 600 | + Globals->abbreviations.insert("ProcrustesLargeStasmFace","ProcrustesAlign(padding=18)+TextureMap+Resize(480,480)"); | |
| 601 | + Globals->abbreviations.insert("ProcrustesLargeStasmEyes","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)"); | |
| 602 | + Globals->abbreviations.insert("ProcrustesLargeStasmPeriocular","SelectPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=10)+TextureMap+Resize(360,480)"); | |
| 603 | + Globals->abbreviations.insert("ProcrustesLargeStasmBrow","SelectPoints([16,17,18,19,20,21,22,23,24,25,26,27])+ProcrustesAlign(padding=8)+TextureMap+Resize(240,480)"); | |
| 604 | + Globals->abbreviations.insert("ProcrustesLargeStasmNose","SelectPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58])+ProcrustesAlign(padding=12)+TextureMap+Resize(360,480)"); | |
| 605 | + Globals->abbreviations.insert("ProcrustesLargeStasmMouth","SelectPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76])+ProcrustesAlign(padding=20)+TextureMap+Resize(360,480)"); | |
| 606 | + Globals->abbreviations.insert("ProcrustesLargeStasmJaw", "SelectPoints([2,3,4,5,6,7,8,9,10])+ProcrustesAlign(padding=8)+TextureMap+Resize(360,480)"); | |
| 607 | + } | |
| 608 | +}; | |
| 609 | +BR_REGISTER(Initializer, ProcrustesInitializer) | |
| 610 | + | |
| 611 | +} // namespace br | |
| 612 | + | |
| 613 | +#include "align.moc" | ... | ... |
openbr/plugins/core/attributealgorithms.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup initializers | |
| 24 | + * \brief Initializes global abbreviations with implemented algorithms for attributes | |
| 25 | + * \author Babatunde Ogunfemi \cite baba1472 | |
| 26 | + */ | |
| 27 | +class AttributeAlgorithmsInitializer : public Initializer | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + void initialize() const | |
| 32 | + { | |
| 33 | + // Constants | |
| 34 | + QString BASE="Open+PP5Register+Rename(PP5_Landmark0_Right_Eye,Affine_0)+Rename(PP5_Landmark1_Left_Eye,Affine_1)+Affine(192,240,.345,.475)+Cvt(Gray)+Stasm(false,true,[(66.24,114),(125.76,114)])"; | |
| 35 | + QString SUBSPACE ="Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,4,4)+Hist(59)+Cat+PCA(0.95)"; | |
| 36 | + | |
| 37 | + QString NOSE="RectFromStasmNoseWithBridge+ROI+Resize(36,24)+" + SUBSPACE; | |
| 38 | + QString MOUTH="RectFromStasmMouth+ROI+Resize(24,36)+" + SUBSPACE; | |
| 39 | + QString EYES="RectFromStasmEyes+ROI+Resize(24,36)+" + SUBSPACE; | |
| 40 | + QString HAIR="RectFromStasmHair+ROI+Resize(24,36)+" + SUBSPACE; | |
| 41 | + QString BROW="RectFromStasmBrow+ROI+Resize(24,36)+" + SUBSPACE; | |
| 42 | + QString JAW="RectFromStasmJaw+ROI+Resize(36,36)+" + SUBSPACE; | |
| 43 | + QString FACE = "Crop(24,30,144,190)+Resize(36,36)+" + SUBSPACE; | |
| 44 | + | |
| 45 | + // All Attributes | |
| 46 | + Globals->abbreviations.insert("AllAttributes", "AttributeBrow/AttributeMouth/AttributeEyes/AttributeFace/AttributeHair/AttributeNose/AttributeJaw"); | |
| 47 | + Globals->abbreviations.insert("AllAttributesMatching", "(AttributeBrow)/(AttributeMouth)/(AttributeEyes)/(AttributeFace)/(AttributeHair)/(AttributeNose)/(AttributeJaw):AttributeMatch"); | |
| 48 | + | |
| 49 | + //Individual Attributes | |
| 50 | + Globals->abbreviations.insert("AttributeBrow", "(" + BASE+ "+" + BROW + "+" | |
| 51 | + "TurkClassifier(eyebrowposition,[closebrows,highbrows],3)/" | |
| 52 | + "TurkClassifier(unibrow,[unibrow],3)/" | |
| 53 | + "TurkClassifier(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3)/" | |
| 54 | + "TurkClassifier(thickeyebrows,[thickeyebrows,lighteyebrows],3))"); | |
| 55 | + Globals->abbreviations.insert("AttributeMouth", "(" + BASE + "+" + MOUTH + "+" | |
| 56 | + "TurkClassifier(smiling,[smiling],3)/" | |
| 57 | + "TurkClassifier(lipthickness,[cherry,big,small],3)/" | |
| 58 | + "TurkClassifier(mouthbite,[underbite,overbite],3)/" | |
| 59 | + "TurkClassifier(mouthopen,[closed,noteeth,halfteeth,allteeth],3)/" | |
| 60 | + "TurkClassifier(mouthwidth,[small,wide],3)/" | |
| 61 | + "TurkClassifier(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3)/" | |
| 62 | + "TurkClassifier(mouthasymmetry,[asymmetrical],3))"); | |
| 63 | + Globals->abbreviations.insert("AttributeEyes", "(" + BASE + "+" + EYES + "+ " | |
| 64 | + "TurkClassifier(eyeseparation,[close,wide],3)/" | |
| 65 | + "TurkClassifier(eyeslant,[slant2,slant1,wild],3)/" | |
| 66 | + "TurkClassifier(benteyes,[bent])/" | |
| 67 | + "TurkClassifier(eyecolor,[darkeyes,lighteyes],3)/" | |
| 68 | + "TurkClassifier(baggyeyes,[baggy],3)/" | |
| 69 | + "TurkClassifier(almondeyes,[almond],3)/" | |
| 70 | + "TurkClassifier(buriedeyes,[buriedeyes],3)/" | |
| 71 | + "TurkClassifier(sleepyeyes,[sleepy],3)/" | |
| 72 | + "TurkClassifier(lineeyes,[line],3)/" | |
| 73 | + "TurkClassifier(roundeyes,[round],3)/" | |
| 74 | + "TurkClassifier(sharpeyes,[sharp],3)/" | |
| 75 | + "TurkClassifier(smalleyes,[smalleyes],3)/" | |
| 76 | + "TurkClassifier(glasses,[glasses],3)/" | |
| 77 | + "TurkClassifier(eyelashvisibility,[feweyelashes],3))"); | |
| 78 | + Globals->abbreviations.insert("AttributeFace", "(" + BASE + "+" + FACE + "+" | |
| 79 | + "TurkClassifier(gender,[male],3)/" | |
| 80 | + "TurkClassifier(faceshape,[round,triangular,rectangular],3)/" | |
| 81 | + "TurkClassifier(cheekdensity,[puffy,in,normal],3)/" | |
| 82 | + "TurkClassifier(facemarks,[scars,moles,normal],3)/" | |
| 83 | + "TurkClassifier(facelength,[long],3)/" | |
| 84 | + "TurkClassifier(nosetoeyedist,[short,long],3)/" | |
| 85 | + "TurkClassifier(nosetomouthdist,[long,small],3))"); | |
| 86 | + Globals->abbreviations.insert("AttributeHair", "(" + BASE + "+" + HAIR + "+" | |
| 87 | + "TurkClassifier(foreheadwrinkles,[wrinkled],3)/" | |
| 88 | + "TurkClassifier(foreheadsize,[smallforehead,largeforehead],3)/" | |
| 89 | + "TurkClassifier(haircolor,[darkhair,lighthair,greyhair],3)/" | |
| 90 | + "TurkClassifier(hairdensity,[thick,bald,thin,halfbald],3)/" | |
| 91 | + "TurkClassifier(widowspeak,[widowspeak],3)/" | |
| 92 | + "TurkClassifier(hairstyle,[curlyhair],3))"); | |
| 93 | + Globals->abbreviations.insert("AttributeNose", "(" + BASE + "+" + NOSE + "+" | |
| 94 | + "TurkClassifier(noseorientation,[upnose,downnose],3)/" | |
| 95 | + "TurkClassifier(nosewidth,[small,thick],3)/" | |
| 96 | + "TurkClassifier(nosesize,[smallnose,bignose],3)/" | |
| 97 | + "TurkClassifier(brokennose,[broken],3))"); | |
| 98 | + Globals->abbreviations.insert("AttributeJaw", "(" + BASE + "+" + JAW + "+" | |
| 99 | + "TurkClassifier(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3)/" | |
| 100 | + "TurkClassifier(chinsize,[shortchin,longchin],3))"); | |
| 101 | + Globals->abbreviations.insert("AttributeMatch", "Fuse([" | |
| 102 | + "Turk(eyebrowposition,[closebrows,highbrows],3)," | |
| 103 | + "Turk(unibrow,[unibrow],3)," | |
| 104 | + "Turk(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3)," | |
| 105 | + "Turk(thickeyebrows,[thickeyebrows,lighteyebrows],3)," | |
| 106 | + "Turk(smiling,[smiling],3)," | |
| 107 | + "Turk(lipthickness,[cherry,big,small],3)," | |
| 108 | + "Turk(mouthbite,[underbite,overbite],3)," | |
| 109 | + "Turk(mouthopen,[closed,noteeth,halfteeth,allteeth],3)," | |
| 110 | + "Turk(mouthwidth,[small,wide],3)," | |
| 111 | + "Turk(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3)," | |
| 112 | + "Turk(mouthasymmetry,[asymmetrical],3)," | |
| 113 | + "Turk(eyeseparation,[close,wide],3)," | |
| 114 | + "Turk(eyeslant,[slant2,slant1,wild],3)," | |
| 115 | + "Turk(benteyes,[bent],3)," | |
| 116 | + "Turk(eyecolor,[darkeyes,lighteyes],3)," | |
| 117 | + "Turk(baggyeyes,[baggy],3)," | |
| 118 | + "Turk(almondeyes,[almond],3)," | |
| 119 | + "Turk(buriedeyes,[buriedeyes],3)," | |
| 120 | + "Turk(sleepyeyes,[sleepy],3)," | |
| 121 | + "Turk(lineeyes,[line],3)," | |
| 122 | + "Turk(roundeyes,[round],3)," | |
| 123 | + "Turk(sharpeyes,[sharp],3)," | |
| 124 | + "Turk(smalleyes,[smalleyes],3)," | |
| 125 | + "Turk(glasses,[glasses],3)," | |
| 126 | + "Turk(eyelashvisibility,[feweyelashes],3)," | |
| 127 | + "Turk(gender,[male],3)," | |
| 128 | + "Turk(faceshape,[round,triangular,rectangular],3)," | |
| 129 | + "Turk(cheekdensity,[puffy,in,normal],3)," | |
| 130 | + "Turk(facemarks,[scars,moles,normal],3)," | |
| 131 | + "Turk(facelength,[long],3)," | |
| 132 | + "Turk(nosetoeyedist,[short,long],3)," | |
| 133 | + "Turk(nosetomouthdist,[long,small],3)," | |
| 134 | + "Turk(foreheadwrinkles,[wrinkled],3)," | |
| 135 | + "Turk(foreheadsize,[smallforehead,largeforehead],3)," | |
| 136 | + "Turk(haircolor,[darkhair,lighthair,greyhair],3)," | |
| 137 | + "Turk(hairdensity,[thick,bald,thin,halfbald],3)," | |
| 138 | + "Turk(widowspeak,[widowspeak],3)," | |
| 139 | + "Turk(hairstyle,[curlyhair],3)," | |
| 140 | + "Turk(noseorientation,[upnose,downnose],3)," | |
| 141 | + "Turk(nosewidth,[small,thick],3)," | |
| 142 | + "Turk(nosesize,[smallnose,bignose],3)," | |
| 143 | + "Turk(brokennose,[broken],3)," | |
| 144 | + "Turk(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3)," | |
| 145 | + "Turk(chinsize,[shortchin,longchin],3)])"); | |
| 146 | + } | |
| 147 | +}; | |
| 148 | + | |
| 149 | +BR_REGISTER(Initializer, AttributeAlgorithmsInitializer) | |
| 150 | + | |
| 151 | +} // namespace br | |
| 152 | + | |
| 153 | +#include "core/attributealgorithms.moc" | ... | ... |
openbr/plugins/core/cache.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Caches br::Transform::project() results. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class CacheTransform : public MetaTransform | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | |
| 31 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 32 | + | |
| 33 | + static QHash<QString, Template> cache; | |
| 34 | + static QMutex cacheLock; | |
| 35 | + | |
| 36 | +public: | |
| 37 | + ~CacheTransform() | |
| 38 | + { | |
| 39 | + if (cache.isEmpty()) return; | |
| 40 | + | |
| 41 | + // Write to cache | |
| 42 | + QFile file("Cache"); | |
| 43 | + if (!file.open(QFile::WriteOnly)) | |
| 44 | + qFatal("Unable to open %s for writing.", qPrintable(file.fileName())); | |
| 45 | + QDataStream stream(&file); | |
| 46 | + stream << cache; | |
| 47 | + file.close(); | |
| 48 | + } | |
| 49 | + | |
| 50 | +private: | |
| 51 | + void init() | |
| 52 | + { | |
| 53 | + if (!transform) return; | |
| 54 | + | |
| 55 | + trainable = transform->trainable; | |
| 56 | + if (!cache.isEmpty()) return; | |
| 57 | + | |
| 58 | + // Read from cache | |
| 59 | + QFile file("Cache"); | |
| 60 | + if (file.exists()) { | |
| 61 | + if (!file.open(QFile::ReadOnly)) | |
| 62 | + qFatal("Unable to open %s for reading.", qPrintable(file.fileName())); | |
| 63 | + QDataStream stream(&file); | |
| 64 | + stream >> cache; | |
| 65 | + file.close(); | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + void train(const QList<TemplateList> &data) | |
| 70 | + { | |
| 71 | + transform->train(data); | |
| 72 | + } | |
| 73 | + | |
| 74 | + void project(const Template &src, Template &dst) const | |
| 75 | + { | |
| 76 | + const QString &file = src.file; | |
| 77 | + if (cache.contains(file)) { | |
| 78 | + dst = cache[file]; | |
| 79 | + } else { | |
| 80 | + transform->project(src, dst); | |
| 81 | + cacheLock.lock(); | |
| 82 | + cache[file] = dst; | |
| 83 | + cacheLock.unlock(); | |
| 84 | + } | |
| 85 | + } | |
| 86 | +}; | |
| 87 | + | |
| 88 | +QHash<QString, Template> CacheTransform::cache; | |
| 89 | +QMutex CacheTransform::cacheLock; | |
| 90 | + | |
| 91 | +BR_REGISTER(Transform, CacheTransform) | |
| 92 | + | |
| 93 | +} // namespace br | |
| 94 | + | |
| 95 | +#include "core/cache.moc" | ... | ... |
openbr/plugins/core/contract.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief It's like the opposite of ExpandTransform, but not really | |
| 25 | + * \author Charles Otto \cite caotto | |
| 26 | + * | |
| 27 | + * Given a set of templatelists as input, concatenate them onto a single Template | |
| 28 | + */ | |
| 29 | +class ContractTransform : public UntrainableMetaTransform | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + | |
| 33 | + virtual void project(const TemplateList &src, TemplateList &dst) const | |
| 34 | + { | |
| 35 | + if (src.empty()) return; | |
| 36 | + Template out; | |
| 37 | + | |
| 38 | + foreach (const Template &t, src) { | |
| 39 | + out.merge(t); | |
| 40 | + } | |
| 41 | + out.file.clearRects(); | |
| 42 | + foreach (const Template &t, src) { | |
| 43 | + if (!t.file.rects().empty()) | |
| 44 | + out.file.appendRects(t.file.rects()); | |
| 45 | + } | |
| 46 | + dst.clear(); | |
| 47 | + dst.append(out); | |
| 48 | + } | |
| 49 | + | |
| 50 | + virtual void project(const Template &src, Template &dst) const | |
| 51 | + { | |
| 52 | + qFatal("this has gone bad"); | |
| 53 | + (void) src; (void) dst; | |
| 54 | + } | |
| 55 | +}; | |
| 56 | + | |
| 57 | +BR_REGISTER(Transform, ContractTransform) | |
| 58 | + | |
| 59 | +} // namespace br | |
| 60 | + | |
| 61 | +#include "core/contract.moc" | ... | ... |
openbr/plugins/validate.cpp renamed to openbr/plugins/core/crossvalidate.cpp
| 1 | -#include <QFutureSynchronizer> | |
| 2 | -#include <QtConcurrentRun> | |
| 3 | -#include "openbr_internal.h" | |
| 4 | -#include "openbr/core/common.h" | |
| 5 | -#include <openbr/core/qtutils.h> | |
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/common.h> | |
| 6 | 21 | |
| 7 | 22 | namespace br |
| 8 | 23 | { |
| ... | ... | @@ -134,138 +149,6 @@ class CrossValidateTransform : public MetaTransform |
| 134 | 149 | |
| 135 | 150 | BR_REGISTER(Transform, CrossValidateTransform) |
| 136 | 151 | |
| 137 | -/*! | |
| 138 | - * \ingroup distances | |
| 139 | - * \brief Cross validate a distance metric. | |
| 140 | - * \author Josh Klontz \cite jklontz | |
| 141 | - */ | |
| 142 | -class CrossValidateDistance : public UntrainableDistance | |
| 143 | -{ | |
| 144 | - Q_OBJECT | |
| 145 | - | |
| 146 | - float compare(const Template &a, const Template &b) const | |
| 147 | - { | |
| 148 | - static const QString key("Partition"); // More efficient to preallocate this | |
| 149 | - const int partitionA = a.file.get<int>(key, 0); | |
| 150 | - const int partitionB = b.file.get<int>(key, 0); | |
| 151 | - return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0; | |
| 152 | - } | |
| 153 | -}; | |
| 154 | - | |
| 155 | -BR_REGISTER(Distance, CrossValidateDistance) | |
| 156 | - | |
| 157 | -/*! | |
| 158 | - * \ingroup distances | |
| 159 | - * \brief Checks target metadata against filters. | |
| 160 | - * \author Josh Klontz \cite jklontz | |
| 161 | - */ | |
| 162 | -class FilterDistance : public UntrainableDistance | |
| 163 | -{ | |
| 164 | - Q_OBJECT | |
| 165 | - | |
| 166 | - float compare(const Template &a, const Template &b) const | |
| 167 | - { | |
| 168 | - (void) b; // Query template isn't checked | |
| 169 | - foreach (const QString &key, Globals->filters.keys()) { | |
| 170 | - bool keep = false; | |
| 171 | - const QString metadata = a.file.get<QString>(key, ""); | |
| 172 | - if (Globals->filters[key].isEmpty()) continue; | |
| 173 | - if (metadata.isEmpty()) return -std::numeric_limits<float>::max(); | |
| 174 | - foreach (const QString &value, Globals->filters[key]) { | |
| 175 | - if (metadata == value) { | |
| 176 | - keep = true; | |
| 177 | - break; | |
| 178 | - } | |
| 179 | - } | |
| 180 | - if (!keep) return -std::numeric_limits<float>::max(); | |
| 181 | - } | |
| 182 | - return 0; | |
| 183 | - } | |
| 184 | -}; | |
| 185 | - | |
| 186 | -BR_REGISTER(Distance, FilterDistance) | |
| 187 | - | |
| 188 | -/*! | |
| 189 | - * \ingroup distances | |
| 190 | - * \brief Checks target metadata against query metadata. | |
| 191 | - * \author Scott Klum \cite sklum | |
| 192 | - */ | |
| 193 | -class MetadataDistance : public UntrainableDistance | |
| 194 | -{ | |
| 195 | - Q_OBJECT | |
| 196 | - | |
| 197 | - Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false) | |
| 198 | - BR_PROPERTY(QStringList, filters, QStringList()) | |
| 199 | - | |
| 200 | - float compare(const Template &a, const Template &b) const | |
| 201 | - { | |
| 202 | - foreach (const QString &key, filters) { | |
| 203 | - QString aValue = a.file.get<QString>(key, QString()); | |
| 204 | - QString bValue = b.file.get<QString>(key, QString()); | |
| 205 | - | |
| 206 | - // The query value may be a range. Let's check. | |
| 207 | - if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF())); | |
| 208 | - | |
| 209 | - if (aValue.isEmpty() || bValue.isEmpty()) continue; | |
| 210 | - | |
| 211 | - bool keep = false; | |
| 212 | - bool ok; | |
| 213 | - | |
| 214 | - QPointF range = QtUtils::toPoint(bValue,&ok); | |
| 215 | - | |
| 216 | - if (ok) /* Range */ { | |
| 217 | - int value = range.x(); | |
| 218 | - int upperBound = range.y(); | |
| 219 | - | |
| 220 | - while (value <= upperBound) { | |
| 221 | - if (aValue == QString::number(value)) { | |
| 222 | - keep = true; | |
| 223 | - break; | |
| 224 | - } | |
| 225 | - value++; | |
| 226 | - } | |
| 227 | - } | |
| 228 | - else if (aValue == bValue) keep = true; | |
| 229 | - | |
| 230 | - if (!keep) return -std::numeric_limits<float>::max(); | |
| 231 | - } | |
| 232 | - return 0; | |
| 233 | - } | |
| 234 | -}; | |
| 235 | - | |
| 236 | - | |
| 237 | -BR_REGISTER(Distance, MetadataDistance) | |
| 238 | - | |
| 239 | -/*! | |
| 240 | - * \ingroup distances | |
| 241 | - * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key. | |
| 242 | - * \author Scott Klum \cite sklum | |
| 243 | - */ | |
| 244 | -class RejectDistance : public UntrainableDistance | |
| 245 | -{ | |
| 246 | - Q_OBJECT | |
| 247 | - | |
| 248 | - Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) | |
| 249 | - BR_PROPERTY(QStringList, keys, QStringList()) | |
| 250 | - Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false) | |
| 251 | - BR_PROPERTY(bool, rejectIfContains, false) | |
| 252 | - | |
| 253 | - float compare(const Template &a, const Template &b) const | |
| 254 | - { | |
| 255 | - // We don't look at the query | |
| 256 | - (void) b; | |
| 257 | - | |
| 258 | - foreach (const QString &key, keys) | |
| 259 | - if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key))) | |
| 260 | - return -std::numeric_limits<float>::max(); | |
| 261 | - | |
| 262 | - return 0; | |
| 263 | - } | |
| 264 | -}; | |
| 265 | - | |
| 266 | - | |
| 267 | -BR_REGISTER(Distance, RejectDistance) | |
| 268 | - | |
| 269 | 152 | } // namespace br |
| 270 | 153 | |
| 271 | -#include "validate.moc" | |
| 154 | +#include "core/crossvalidate.moc" | ... | ... |
openbr/plugins/core/discard.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Removes all template's matrices. | |
| 25 | + * \see IdentityTransform FirstTransform RestTransform RemoveTransform | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class DiscardTransform : public UntrainableMetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + void project(const Template &src, Template &dst) const | |
| 33 | + { | |
| 34 | + dst.file = src.file; | |
| 35 | + } | |
| 36 | +}; | |
| 37 | + | |
| 38 | +BR_REGISTER(Transform, DiscardTransform) | |
| 39 | + | |
| 40 | +} // namespace br | |
| 41 | + | |
| 42 | +#include "core/discard.moc" | ... | ... |
openbr/plugins/core/discardtemplates.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +class DiscardTemplatesTransform : public UntrainableMetaTransform | |
| 23 | +{ | |
| 24 | + Q_OBJECT | |
| 25 | + | |
| 26 | + void project(const Template &src, Template &dst) const | |
| 27 | + { | |
| 28 | + (void) src; (void) dst; | |
| 29 | + qFatal("Incorrect project called on DiscardTemplatesTransform"); | |
| 30 | + } | |
| 31 | + void project(const TemplateList &src, TemplateList &dst) const | |
| 32 | + { | |
| 33 | + (void) src; | |
| 34 | + dst.clear(); | |
| 35 | + } | |
| 36 | +}; | |
| 37 | + | |
| 38 | +BR_REGISTER(Transform, DiscardTemplatesTransform) | |
| 39 | + | |
| 40 | +} // namespace br | |
| 41 | + | |
| 42 | +#include "core/discardtemplates.moc" | ... | ... |
openbr/plugins/core/distributetemplate.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +static void _projectList(const Transform *transform, const TemplateList *src, TemplateList *dst) | |
| 25 | +{ | |
| 26 | + transform->project(*src, *dst); | |
| 27 | +} | |
| 28 | + | |
| 29 | +class DistributeTemplateTransform : public MetaTransform | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | |
| 33 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 34 | + | |
| 35 | +public: | |
| 36 | + | |
| 37 | + Transform *smartCopy(bool &newTransform) | |
| 38 | + { | |
| 39 | + if (!transform->timeVarying()) { | |
| 40 | + newTransform = false; | |
| 41 | + return this; | |
| 42 | + } | |
| 43 | + newTransform = true; | |
| 44 | + | |
| 45 | + DistributeTemplateTransform *output = new DistributeTemplateTransform; | |
| 46 | + bool newChild = false; | |
| 47 | + output->transform = transform->smartCopy(newChild); | |
| 48 | + if (newChild) | |
| 49 | + output->transform->setParent(output); | |
| 50 | + | |
| 51 | + return output; | |
| 52 | + } | |
| 53 | + | |
| 54 | + void train(const QList<TemplateList> &data) | |
| 55 | + { | |
| 56 | + if (!transform->trainable) { | |
| 57 | + qWarning("Attempted to train untrainable transform, nothing will happen."); | |
| 58 | + return; | |
| 59 | + } | |
| 60 | + | |
| 61 | + QList<TemplateList> separated; | |
| 62 | + foreach (const TemplateList &list, data) { | |
| 63 | + foreach (const Template &t, list) { | |
| 64 | + separated.append(TemplateList()); | |
| 65 | + separated.last().append(t); | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + transform->train(separated); | |
| 70 | + } | |
| 71 | + | |
| 72 | + void project(const Template &src, Template &dst) const | |
| 73 | + { | |
| 74 | + TemplateList input; | |
| 75 | + input.append(src); | |
| 76 | + TemplateList output; | |
| 77 | + project(input, output); | |
| 78 | + | |
| 79 | + if (output.size() != 1) qFatal("output contains more than 1 template"); | |
| 80 | + else dst = output[0]; | |
| 81 | + } | |
| 82 | + | |
| 83 | + // For each input template, form a single element TemplateList, push all those | |
| 84 | + // lists through transform, and form dst by concatenating the results. | |
| 85 | + // Process the single elemnt templates in parallel if parallelism is enabled. | |
| 86 | + void project(const TemplateList &src, TemplateList &dst) const | |
| 87 | + { | |
| 88 | + // Pre-allocate output for each template | |
| 89 | + QList<TemplateList> output_buffer; | |
| 90 | + output_buffer.reserve(src.size()); | |
| 91 | + | |
| 92 | + // Can't declare this local to the loop because it would go out of scope | |
| 93 | + QList<TemplateList> input_buffer; | |
| 94 | + input_buffer.reserve(src.size()); | |
| 95 | + | |
| 96 | + QFutureSynchronizer<void> futures; | |
| 97 | + | |
| 98 | + for (int i =0; i < src.size();i++) { | |
| 99 | + input_buffer.append(TemplateList()); | |
| 100 | + output_buffer.append(TemplateList()); | |
| 101 | + } | |
| 102 | + QList<QFuture<void> > temp; | |
| 103 | + temp.reserve(src.size()); | |
| 104 | + for (int i=0; i<src.size(); i++) { | |
| 105 | + input_buffer[i].append(src[i]); | |
| 106 | + | |
| 107 | + if (Globals->parallelism > 1) temp.append(QtConcurrent::run(_projectList, transform, &input_buffer[i], &output_buffer[i])); | |
| 108 | + else _projectList(transform, &input_buffer[i], &output_buffer[i]); | |
| 109 | + } | |
| 110 | + // We add the futures in reverse order, since in Qt 5.1 at least the | |
| 111 | + // waiting thread will wait on them in the order added (which for uniform priority | |
| 112 | + // threads is the order of execution), and we want the waiting thread to go in the opposite order | |
| 113 | + // so that it can steal runnables and do something besides wait. | |
| 114 | + for (int i = temp.size() - 1; i >= 0; i--) { | |
| 115 | + futures.addFuture(temp[i]); | |
| 116 | + } | |
| 117 | + | |
| 118 | + futures.waitForFinished(); | |
| 119 | + | |
| 120 | + for (int i=0; i<src.size(); i++) dst.append(output_buffer[i]); | |
| 121 | + } | |
| 122 | + | |
| 123 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 124 | + { | |
| 125 | + this->project(src, dst); | |
| 126 | + return; | |
| 127 | + } | |
| 128 | + | |
| 129 | + void init() | |
| 130 | + { | |
| 131 | + if (!transform) | |
| 132 | + return; | |
| 133 | + | |
| 134 | + trainable = transform->trainable; | |
| 135 | + } | |
| 136 | + | |
| 137 | +}; | |
| 138 | +BR_REGISTER(Transform, DistributeTemplateTransform) | |
| 139 | + | |
| 140 | +} // namespace br | |
| 141 | + | |
| 142 | +#include "core/distributetemplate.moc" | ... | ... |
openbr/plugins/core/downsampletraining.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +static TemplateList Downsample(const TemplateList &templates, int classes, int instances, float fraction, const QString &inputVariable, const QStringList &gallery, const QStringList &subjects) | |
| 23 | +{ | |
| 24 | + // Return early when no downsampling is required | |
| 25 | + if ((classes == std::numeric_limits<int>::max()) && | |
| 26 | + (instances == std::numeric_limits<int>::max()) && | |
| 27 | + (fraction >= 1) && | |
| 28 | + (gallery.isEmpty()) && | |
| 29 | + (subjects.isEmpty())) | |
| 30 | + return templates; | |
| 31 | + | |
| 32 | + const bool atLeast = instances < 0; | |
| 33 | + instances = abs(instances); | |
| 34 | + | |
| 35 | + QList<QString> allLabels = File::get<QString>(templates, inputVariable); | |
| 36 | + | |
| 37 | + QList<QString> uniqueLabels = allLabels.toSet().toList(); | |
| 38 | + qSort(uniqueLabels); | |
| 39 | + | |
| 40 | + QMap<QString,int> counts = templates.countValues<QString>(inputVariable, instances != std::numeric_limits<int>::max()); | |
| 41 | + | |
| 42 | + if ((instances != std::numeric_limits<int>::max()) && (classes != std::numeric_limits<int>::max())) | |
| 43 | + foreach (const QString &label, counts.keys()) | |
| 44 | + if (counts[label] < instances) | |
| 45 | + counts.remove(label); | |
| 46 | + | |
| 47 | + uniqueLabels = counts.keys(); | |
| 48 | + if ((classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < classes)) | |
| 49 | + qWarning("Downsample requested %d classes but only %d are available.", classes, uniqueLabels.size()); | |
| 50 | + | |
| 51 | + QList<QString> selectedLabels = uniqueLabels; | |
| 52 | + if (classes < uniqueLabels.size()) { | |
| 53 | + std::random_shuffle(selectedLabels.begin(), selectedLabels.end()); | |
| 54 | + selectedLabels = selectedLabels.mid(0, classes); | |
| 55 | + } | |
| 56 | + | |
| 57 | + TemplateList downsample; | |
| 58 | + for (int i=0; i<selectedLabels.size(); i++) { | |
| 59 | + const QString selectedLabel = selectedLabels[i]; | |
| 60 | + QList<int> indices; | |
| 61 | + for (int j=0; j<allLabels.size(); j++) | |
| 62 | + if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false)) && (!templates.value(j).file.get<bool>("PossibleFTE", false))) | |
| 63 | + indices.append(j); | |
| 64 | + | |
| 65 | + std::random_shuffle(indices.begin(), indices.end()); | |
| 66 | + const int max = atLeast ? indices.size() : std::min(indices.size(), instances); | |
| 67 | + for (int j=0; j<max; j++) | |
| 68 | + downsample.append(templates.value(indices[j])); | |
| 69 | + } | |
| 70 | + | |
| 71 | + if (fraction < 1) { | |
| 72 | + std::random_shuffle(downsample.begin(), downsample.end()); | |
| 73 | + downsample = downsample.mid(0, downsample.size()*fraction); | |
| 74 | + } | |
| 75 | + | |
| 76 | + if (!gallery.isEmpty()) | |
| 77 | + for (int i=downsample.size()-1; i>=0; i--) | |
| 78 | + if (!gallery.contains(downsample[i].file.get<QString>("Gallery"))) | |
| 79 | + downsample.removeAt(i); | |
| 80 | + | |
| 81 | + if (!subjects.isEmpty()) | |
| 82 | + for (int i=downsample.size()-1; i>=0; i--) | |
| 83 | + if (subjects.contains(downsample[i].file.get<QString>(inputVariable))) | |
| 84 | + downsample.removeAt(i); | |
| 85 | + | |
| 86 | + return downsample; | |
| 87 | +} | |
| 88 | + | |
| 89 | +class DownsampleTrainingTransform : public Transform | |
| 90 | +{ | |
| 91 | + Q_OBJECT | |
| 92 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED true) | |
| 93 | + Q_PROPERTY(int classes READ get_classes WRITE set_classes RESET reset_classes STORED false) | |
| 94 | + Q_PROPERTY(int instances READ get_instances WRITE set_instances RESET reset_instances STORED false) | |
| 95 | + Q_PROPERTY(float fraction READ get_fraction WRITE set_fraction RESET reset_fraction STORED false) | |
| 96 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 97 | + Q_PROPERTY(QStringList gallery READ get_gallery WRITE set_gallery RESET reset_gallery STORED false) | |
| 98 | + Q_PROPERTY(QStringList subjects READ get_subjects WRITE set_subjects RESET reset_subjects STORED false) | |
| 99 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 100 | + BR_PROPERTY(int, classes, std::numeric_limits<int>::max()) | |
| 101 | + BR_PROPERTY(int, instances, std::numeric_limits<int>::max()) | |
| 102 | + BR_PROPERTY(float, fraction, 1) | |
| 103 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 104 | + BR_PROPERTY(QStringList, gallery, QStringList()) | |
| 105 | + BR_PROPERTY(QStringList, subjects, QStringList()) | |
| 106 | + | |
| 107 | + | |
| 108 | + Transform *simplify(bool &newTForm) | |
| 109 | + { | |
| 110 | + Transform *res = transform->simplify(newTForm); | |
| 111 | + return res; | |
| 112 | + } | |
| 113 | + | |
| 114 | + void project(const Template &src, Template &dst) const | |
| 115 | + { | |
| 116 | + transform->project(src,dst); | |
| 117 | + } | |
| 118 | + | |
| 119 | + | |
| 120 | + void train(const TemplateList &data) | |
| 121 | + { | |
| 122 | + if (!transform || !transform->trainable) | |
| 123 | + return; | |
| 124 | + | |
| 125 | + TemplateList downsampled = Downsample(data, classes, instances, fraction, inputVariable, gallery, subjects); | |
| 126 | + | |
| 127 | + transform->train(downsampled); | |
| 128 | + } | |
| 129 | +}; | |
| 130 | + | |
| 131 | +BR_REGISTER(Transform, DownsampleTrainingTransform) | |
| 132 | + | |
| 133 | +} // namespace br | |
| 134 | + | |
| 135 | +#include "core/downsampletraining.moc" | ... | ... |
openbr/plugins/core/event.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +class EventTransform : public UntrainableMetaTransform | |
| 23 | +{ | |
| 24 | + Q_OBJECT | |
| 25 | + Q_PROPERTY(QString eventName READ get_eventName WRITE set_eventName RESET reset_eventName STORED false) | |
| 26 | + BR_PROPERTY(QString, eventName, "") | |
| 27 | + | |
| 28 | + TemplateEvent event; | |
| 29 | + | |
| 30 | + void project(const Template &src, Template &dst) const | |
| 31 | + { | |
| 32 | + dst = src; | |
| 33 | + event.pulseSignal(dst); | |
| 34 | + } | |
| 35 | + | |
| 36 | + TemplateEvent *getEvent(const QString &name) | |
| 37 | + { | |
| 38 | + return name == eventName ? &event : NULL; | |
| 39 | + } | |
| 40 | +}; | |
| 41 | + | |
| 42 | +BR_REGISTER(Transform, EventTransform) | |
| 43 | + | |
| 44 | +} // namespace br | |
| 45 | + | |
| 46 | +#include "core/event.moc" | ... | ... |
openbr/plugins/core/expand.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +static TemplateList Expanded(const TemplateList &templates) | |
| 23 | +{ | |
| 24 | + TemplateList expanded; | |
| 25 | + foreach (const Template &t, templates) { | |
| 26 | + const bool enrollAll = t.file.get<bool>("enrollAll"); | |
| 27 | + if (t.isEmpty()) { | |
| 28 | + if (!enrollAll) | |
| 29 | + expanded.append(t); | |
| 30 | + continue; | |
| 31 | + } | |
| 32 | + | |
| 33 | + const QList<QPointF> points = t.file.points(); | |
| 34 | + const QList<QRectF> rects = t.file.rects(); | |
| 35 | + if (points.size() % t.size() != 0) qFatal("Uneven point count."); | |
| 36 | + if (rects.size() % t.size() != 0) qFatal("Uneven rect count."); | |
| 37 | + const int pointStep = points.size() / t.size(); | |
| 38 | + const int rectStep = rects.size() / t.size(); | |
| 39 | + | |
| 40 | + for (int i=0; i<t.size(); i++) { | |
| 41 | + expanded.append(Template(t.file, t[i])); | |
| 42 | + expanded.last().file.setRects(rects.mid(i*rectStep, rectStep)); | |
| 43 | + expanded.last().file.setPoints(points.mid(i*pointStep, pointStep)); | |
| 44 | + } | |
| 45 | + } | |
| 46 | + return expanded; | |
| 47 | +} | |
| 48 | + | |
| 49 | +/*! | |
| 50 | + * \ingroup transforms | |
| 51 | + * \brief Performs an expansion step on input templatelists | |
| 52 | + * \author Josh Klontz \cite jklontz | |
| 53 | + * | |
| 54 | + * Each matrix in an input Template is expanded into its own template. | |
| 55 | + * | |
| 56 | + * \see PipeTransform | |
| 57 | + */ | |
| 58 | +class ExpandTransform : public UntrainableMetaTransform | |
| 59 | +{ | |
| 60 | + Q_OBJECT | |
| 61 | + | |
| 62 | + virtual void project(const TemplateList &src, TemplateList &dst) const | |
| 63 | + { | |
| 64 | + dst = Expanded(src); | |
| 65 | + } | |
| 66 | + | |
| 67 | + virtual void project(const Template &src, Template &dst) const | |
| 68 | + { | |
| 69 | + dst = src; | |
| 70 | + qDebug("Called Expand project(Template,Template), nothing will happen"); | |
| 71 | + } | |
| 72 | +}; | |
| 73 | + | |
| 74 | +BR_REGISTER(Transform, ExpandTransform) | |
| 75 | + | |
| 76 | +} // namespace br | |
| 77 | + | |
| 78 | +#include "core/expand.moc" | ... | ... |
openbr/plugins/core/first.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Removes all but the first matrix from the template. | |
| 25 | + * \see IdentityTransform DiscardTransform RestTransform RemoveTransform | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class FirstTransform : public UntrainableMetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + void project(const Template &src, Template &dst) const | |
| 33 | + { | |
| 34 | + // AggregateFrames will leave the Template empty | |
| 35 | + // if it hasn't filled up the buffer | |
| 36 | + // so we gotta anticipate an empty Template | |
| 37 | + if (src.empty()) return; | |
| 38 | + dst.file = src.file; | |
| 39 | + dst = src.m(); | |
| 40 | + } | |
| 41 | +}; | |
| 42 | + | |
| 43 | +BR_REGISTER(Transform, FirstTransform) | |
| 44 | + | |
| 45 | +} // namespace br | |
| 46 | + | |
| 47 | +#include "core/first.moc" | ... | ... |
openbr/plugins/core/fork.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +static void _train(Transform *transform, const QList<TemplateList> *data) | |
| 25 | +{ | |
| 26 | + transform->train(*data); | |
| 27 | +} | |
| 28 | + | |
| 29 | +/*! | |
| 30 | + * \ingroup transforms | |
| 31 | + * \brief Transforms in parallel. | |
| 32 | + * \author Josh Klontz \cite jklontz | |
| 33 | + * | |
| 34 | + * The source br::Template is seperately given to each transform and the results are appended together. | |
| 35 | + * | |
| 36 | + * \see PipeTransform | |
| 37 | + */ | |
| 38 | +class ForkTransform : public CompositeTransform | |
| 39 | +{ | |
| 40 | + Q_OBJECT | |
| 41 | + | |
| 42 | + void train(const QList<TemplateList> &data) | |
| 43 | + { | |
| 44 | + if (!trainable) return; | |
| 45 | + QFutureSynchronizer<void> futures; | |
| 46 | + for (int i=0; i<transforms.size(); i++) | |
| 47 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &data)); | |
| 48 | + futures.waitForFinished(); | |
| 49 | + } | |
| 50 | + | |
| 51 | + // same as _project, but calls projectUpdate on sub-transforms | |
| 52 | + void projectupdate(const Template &src, Template &dst) | |
| 53 | + { | |
| 54 | + foreach (Transform *f, transforms) { | |
| 55 | + try { | |
| 56 | + Template res; | |
| 57 | + f->projectUpdate(src, res); | |
| 58 | + dst.merge(res); | |
| 59 | + } catch (...) { | |
| 60 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | |
| 61 | + dst = Template(src.file); | |
| 62 | + dst.file.fte = true; | |
| 63 | + break; | |
| 64 | + } | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 69 | + { | |
| 70 | + dst.reserve(src.size()); | |
| 71 | + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file)); | |
| 72 | + foreach (Transform *f, transforms) { | |
| 73 | + TemplateList m; | |
| 74 | + f->projectUpdate(src, m); | |
| 75 | + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | |
| 76 | + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + // this is probably going to go bad, fork transform probably won't work well in a variable | |
| 81 | + // input/output scenario | |
| 82 | + virtual void finalize(TemplateList &output) | |
| 83 | + { | |
| 84 | + output.clear(); | |
| 85 | + // For each transform, | |
| 86 | + for (int i = 0; i < transforms.size(); i++) | |
| 87 | + { | |
| 88 | + // Collect any final templates | |
| 89 | + TemplateList last_set; | |
| 90 | + transforms[i]->finalize(last_set); | |
| 91 | + if (last_set.empty()) | |
| 92 | + continue; | |
| 93 | + | |
| 94 | + if (output.empty()) output = last_set; | |
| 95 | + else | |
| 96 | + { | |
| 97 | + // is the number of templates received from this transform consistent with the number | |
| 98 | + // received previously? If not we can't do anything coherent here. | |
| 99 | + if (last_set.size() != output.size()) | |
| 100 | + qFatal("mismatched template list sizes in ForkTransform"); | |
| 101 | + for (int j = 0; j < output.size(); j++) { | |
| 102 | + output[j].append(last_set[j]); | |
| 103 | + } | |
| 104 | + } | |
| 105 | + } | |
| 106 | + } | |
| 107 | + | |
| 108 | +protected: | |
| 109 | + | |
| 110 | + // Apply each transform to src, concatenate the results | |
| 111 | + void _project(const Template &src, Template &dst) const | |
| 112 | + { | |
| 113 | + foreach (const Transform *f, transforms) { | |
| 114 | + try { | |
| 115 | + dst.merge((*f)(src)); | |
| 116 | + } catch (...) { | |
| 117 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | |
| 118 | + dst = Template(src.file); | |
| 119 | + dst.file.fte = true; | |
| 120 | + break; | |
| 121 | + } | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 125 | + void _project(const TemplateList &src, TemplateList &dst) const | |
| 126 | + { | |
| 127 | + dst.reserve(src.size()); | |
| 128 | + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file)); | |
| 129 | + foreach (const Transform *f, transforms) { | |
| 130 | + TemplateList m; | |
| 131 | + f->project(src, m); | |
| 132 | + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | |
| 133 | + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]); | |
| 134 | + } | |
| 135 | + } | |
| 136 | + | |
| 137 | +}; | |
| 138 | + | |
| 139 | +BR_REGISTER(Transform, ForkTransform) | |
| 140 | + | |
| 141 | +} // namespace br | |
| 142 | + | |
| 143 | +#include "core/fork.moc" | ... | ... |
openbr/plugins/core/fte.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/common.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup transforms | |
| 25 | + * \brief Flags images that failed to enroll based on the specified transform. | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class FTETransform : public Transform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | |
| 32 | + Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min) | |
| 33 | + Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max) | |
| 34 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 35 | + BR_PROPERTY(float, min, -std::numeric_limits<float>::max()) | |
| 36 | + BR_PROPERTY(float, max, std::numeric_limits<float>::max()) | |
| 37 | + | |
| 38 | + void train(const TemplateList &data) | |
| 39 | + { | |
| 40 | + transform->train(data); | |
| 41 | + | |
| 42 | + TemplateList projectedData; | |
| 43 | + transform->project(data, projectedData); | |
| 44 | + | |
| 45 | + QList<float> vals; | |
| 46 | + foreach (const Template &t, projectedData) { | |
| 47 | + if (!t.file.contains(transform->objectName())) | |
| 48 | + qFatal("Matrix metadata missing key %s.", qPrintable(transform->objectName())); | |
| 49 | + vals.append(t.file.get<float>(transform->objectName())); | |
| 50 | + } | |
| 51 | + float q1, q3; | |
| 52 | + Common::Median(vals, &q1, &q3); | |
| 53 | + min = q1 - 1.5 * (q3 - q1); | |
| 54 | + max = q3 + 1.5 * (q3 - q1); | |
| 55 | + } | |
| 56 | + | |
| 57 | + void project(const Template &src, Template &dst) const | |
| 58 | + { | |
| 59 | + Template projectedSrc; | |
| 60 | + transform->project(src, projectedSrc); | |
| 61 | + const float val = projectedSrc.file.get<float>(transform->objectName()); | |
| 62 | + | |
| 63 | + dst = src; | |
| 64 | + dst.file.set(transform->objectName(), val); | |
| 65 | + dst.file.set("PossibleFTE", (val < min) || (val > max)); | |
| 66 | + } | |
| 67 | +}; | |
| 68 | + | |
| 69 | +BR_REGISTER(Transform, FTETransform) | |
| 70 | + | |
| 71 | +} // namespace br | |
| 72 | + | |
| 73 | +#include "core/fte.moc" | ... | ... |
openbr/plugins/core/gallerycompare.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/opencvutils.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup transforms | |
| 25 | + * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance. | |
| 26 | + * dst will contain a 1 by n vector of scores. | |
| 27 | + * \author Charles Otto \cite caotto | |
| 28 | + */ | |
| 29 | +class GalleryCompareTransform : public Transform | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true) | |
| 33 | + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) | |
| 34 | + BR_PROPERTY(br::Distance*, distance, NULL) | |
| 35 | + BR_PROPERTY(QString, galleryName, "") | |
| 36 | + | |
| 37 | + TemplateList gallery; | |
| 38 | + | |
| 39 | + void project(const Template &src, Template &dst) const | |
| 40 | + { | |
| 41 | + dst = src; | |
| 42 | + if (gallery.isEmpty()) | |
| 43 | + return; | |
| 44 | + | |
| 45 | + QList<float> line = distance->compare(gallery, src); | |
| 46 | + dst.m() = OpenCVUtils::toMat(line, 1); | |
| 47 | + } | |
| 48 | + | |
| 49 | + void init() | |
| 50 | + { | |
| 51 | + if (!galleryName.isEmpty()) | |
| 52 | + gallery = TemplateList::fromGallery(galleryName); | |
| 53 | + } | |
| 54 | + | |
| 55 | + void train(const TemplateList &data) | |
| 56 | + { | |
| 57 | + gallery = data; | |
| 58 | + } | |
| 59 | + | |
| 60 | + void store(QDataStream &stream) const | |
| 61 | + { | |
| 62 | + br::Object::store(stream); | |
| 63 | + stream << gallery; | |
| 64 | + } | |
| 65 | + | |
| 66 | + void load(QDataStream &stream) | |
| 67 | + { | |
| 68 | + br::Object::load(stream); | |
| 69 | + stream >> gallery; | |
| 70 | + } | |
| 71 | + | |
| 72 | +public: | |
| 73 | + GalleryCompareTransform() : Transform(false, true) {} | |
| 74 | +}; | |
| 75 | + | |
| 76 | +BR_REGISTER(Transform, GalleryCompareTransform) | |
| 77 | + | |
| 78 | +} // namespace br | |
| 79 | + | |
| 80 | +#include "core/gallerycompare.moc" | ... | ... |
openbr/plugins/core/identity.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief A no-op transform. | |
| 25 | + * \see DiscardTransform FirstTransform RestTransform RemoveTransform | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class IdentityTransform : public UntrainableMetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + void project(const Template &src, Template &dst) const | |
| 33 | + { | |
| 34 | + dst = src; | |
| 35 | + } | |
| 36 | +}; | |
| 37 | + | |
| 38 | +BR_REGISTER(Transform, IdentityTransform) | |
| 39 | + | |
| 40 | +} // namespace br | |
| 41 | + | |
| 42 | +#include "core/identity.moc" | ... | ... |
openbr/plugins/core/independent.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +using namespace cv; | |
| 22 | + | |
| 23 | +namespace br | |
| 24 | +{ | |
| 25 | + | |
| 26 | +/*! | |
| 27 | + * \ingroup transforms | |
| 28 | + * \brief Clones the transform so that it can be applied independently. | |
| 29 | + * \author Josh Klontz \cite jklontz | |
| 30 | + * \em Independent transforms expect single-matrix templates. | |
| 31 | + */ | |
| 32 | +class IndependentTransform : public MetaTransform | |
| 33 | +{ | |
| 34 | + Q_OBJECT | |
| 35 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED false) | |
| 36 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 37 | + | |
| 38 | + QList<Transform*> transforms; | |
| 39 | + | |
| 40 | + QString description(bool expanded) const | |
| 41 | + { | |
| 42 | + return transform->description(expanded); | |
| 43 | + } | |
| 44 | + | |
| 45 | + // can't use general setPropertyRecursive because of transforms oddness | |
| 46 | + bool setPropertyRecursive(const QString &name, QVariant value) | |
| 47 | + { | |
| 48 | + if (br::Object::setExistingProperty(name, value)) | |
| 49 | + return true; | |
| 50 | + | |
| 51 | + if (!transform->setPropertyRecursive(name, value)) | |
| 52 | + return false; | |
| 53 | + | |
| 54 | + for (int i=0;i < transforms.size();i++) | |
| 55 | + transforms[i]->setPropertyRecursive(name, value); | |
| 56 | + | |
| 57 | + return true; | |
| 58 | + } | |
| 59 | + | |
| 60 | + Transform *simplify(bool &newTransform) | |
| 61 | + { | |
| 62 | + newTransform = false; | |
| 63 | + bool newChild = false; | |
| 64 | + Transform *temp = transform->simplify(newChild); | |
| 65 | + if (temp == transform) { | |
| 66 | + return this; | |
| 67 | + } | |
| 68 | + IndependentTransform* indep = new IndependentTransform(); | |
| 69 | + indep->transform = temp; | |
| 70 | + | |
| 71 | + IndependentTransform *test = dynamic_cast<IndependentTransform *> (temp); | |
| 72 | + if (test) { | |
| 73 | + // child was independent? this changes things... | |
| 74 | + indep->transform = test->transform; | |
| 75 | + for (int i=0; i < transforms.size(); i++) { | |
| 76 | + bool newThing = false; | |
| 77 | + IndependentTransform *probe = dynamic_cast<IndependentTransform *> (transforms[i]->simplify(newThing)); | |
| 78 | + indep->transforms.append(probe->transform); | |
| 79 | + if (newThing) | |
| 80 | + probe->setParent(indep); | |
| 81 | + } | |
| 82 | + indep->file = indep->transform->file; | |
| 83 | + indep->trainable = indep->transform->trainable; | |
| 84 | + indep->setObjectName(indep->transform->objectName()); | |
| 85 | + | |
| 86 | + return indep; | |
| 87 | + } | |
| 88 | + | |
| 89 | + if (newChild) | |
| 90 | + indep->transform->setParent(indep); | |
| 91 | + | |
| 92 | + for (int i=0; i < transforms.size();i++) { | |
| 93 | + bool subTform = false; | |
| 94 | + indep->transforms.append(transforms[i]->simplify(subTform)); | |
| 95 | + if (subTform) | |
| 96 | + indep->transforms[i]->setParent(indep); | |
| 97 | + } | |
| 98 | + | |
| 99 | + indep->file = indep->transform->file; | |
| 100 | + indep->trainable = indep->transform->trainable; | |
| 101 | + indep->setObjectName(indep->transform->objectName()); | |
| 102 | + | |
| 103 | + return indep; | |
| 104 | + } | |
| 105 | + | |
| 106 | + void init() | |
| 107 | + { | |
| 108 | + transforms.clear(); | |
| 109 | + if (transform == NULL) | |
| 110 | + return; | |
| 111 | + | |
| 112 | + transform->setParent(this); | |
| 113 | + transforms.append(transform); | |
| 114 | + file = transform->file; | |
| 115 | + trainable = transform->trainable; | |
| 116 | + setObjectName(transform->objectName()); | |
| 117 | + } | |
| 118 | + | |
| 119 | + Transform *clone() const | |
| 120 | + { | |
| 121 | + IndependentTransform *independentTransform = new IndependentTransform(); | |
| 122 | + independentTransform->transform = transform->clone(); | |
| 123 | + independentTransform->init(); | |
| 124 | + return independentTransform; | |
| 125 | + } | |
| 126 | + | |
| 127 | + bool timeVarying() const { return transform->timeVarying(); } | |
| 128 | + | |
| 129 | + static void _train(Transform *transform, const TemplateList *data) | |
| 130 | + { | |
| 131 | + transform->train(*data); | |
| 132 | + } | |
| 133 | + | |
| 134 | + void train(const TemplateList &data) | |
| 135 | + { | |
| 136 | + // Don't bother if the transform is untrainable | |
| 137 | + if (!trainable) return; | |
| 138 | + | |
| 139 | + QList<TemplateList> templatesList; | |
| 140 | + foreach (const Template &t, data) { | |
| 141 | + if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) | |
| 142 | + qWarning("Independent::train (%s) template %s of size %d differs from expected size %d.", qPrintable(objectName()), qPrintable(t.file.name), t.size(), templatesList.size()); | |
| 143 | + while (templatesList.size() < t.size()) | |
| 144 | + templatesList.append(TemplateList()); | |
| 145 | + for (int i=0; i<t.size(); i++) | |
| 146 | + templatesList[i].append(Template(t.file, t[i])); | |
| 147 | + } | |
| 148 | + | |
| 149 | + while (transforms.size() < templatesList.size()) | |
| 150 | + transforms.append(transform->clone()); | |
| 151 | + | |
| 152 | + QFutureSynchronizer<void> futures; | |
| 153 | + for (int i=0; i<templatesList.size(); i++) | |
| 154 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | |
| 155 | + futures.waitForFinished(); | |
| 156 | + } | |
| 157 | + | |
| 158 | + void project(const Template &src, Template &dst) const | |
| 159 | + { | |
| 160 | + dst.file = src.file; | |
| 161 | + QList<Mat> mats; | |
| 162 | + for (int i=0; i<src.size(); i++) { | |
| 163 | + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); | |
| 164 | + mats.append(dst); | |
| 165 | + dst.clear(); | |
| 166 | + } | |
| 167 | + dst.append(mats); | |
| 168 | + } | |
| 169 | + | |
| 170 | + void projectUpdate(const Template &src, Template &dst) | |
| 171 | + { | |
| 172 | + dst.file = src.file; | |
| 173 | + QList<Mat> mats; | |
| 174 | + for (int i=0; i<src.size(); i++) { | |
| 175 | + transforms[i%transforms.size()]->projectUpdate(Template(src.file, src[i]), dst); | |
| 176 | + mats.append(dst); | |
| 177 | + dst.clear(); | |
| 178 | + } | |
| 179 | + dst.append(mats); | |
| 180 | + } | |
| 181 | + | |
| 182 | + void finalize(TemplateList &out) | |
| 183 | + { | |
| 184 | + if (transforms.empty()) | |
| 185 | + return; | |
| 186 | + | |
| 187 | + transforms[0]->finalize(out); | |
| 188 | + for (int i=1; i < transforms.size(); i++) { | |
| 189 | + TemplateList temp; | |
| 190 | + transforms[i]->finalize(temp); | |
| 191 | + | |
| 192 | + for (int j=0; j < out.size(); j++) | |
| 193 | + out[j].append(temp[j]); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + | |
| 197 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 198 | + { | |
| 199 | + dst.reserve(src.size()); | |
| 200 | + foreach (const Template &t, src) { | |
| 201 | + dst.append(Template()); | |
| 202 | + projectUpdate(t, dst.last()); | |
| 203 | + } | |
| 204 | + } | |
| 205 | + | |
| 206 | + void store(QDataStream &stream) const | |
| 207 | + { | |
| 208 | + const int size = transforms.size(); | |
| 209 | + stream << size; | |
| 210 | + for (int i=0; i<size; i++) | |
| 211 | + transforms[i]->store(stream); | |
| 212 | + } | |
| 213 | + | |
| 214 | + void load(QDataStream &stream) | |
| 215 | + { | |
| 216 | + int size; | |
| 217 | + stream >> size; | |
| 218 | + while (transforms.size() < size) | |
| 219 | + transforms.append(transform->clone()); | |
| 220 | + for (int i=0; i<size; i++) | |
| 221 | + transforms[i]->load(stream); | |
| 222 | + } | |
| 223 | +}; | |
| 224 | + | |
| 225 | +BR_REGISTER(Transform, IndependentTransform) | |
| 226 | + | |
| 227 | +} // namespace br | |
| 228 | + | |
| 229 | +#include "core/independent.moc" | ... | ... |
openbr/plugins/jni.cpp renamed to openbr/plugins/core/jni.cpp
| 1 | 1 | //Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables |
| 2 | 2 | |
| 3 | 3 | #include <limits> |
| 4 | -#include "openbr_internal.h" | |
| 5 | -#include "openbr/core/resource.h" | |
| 4 | +#include <openbr/plugins/openbr_internal.h> | |
| 5 | +#include <openbr/core/resource.h> | |
| 6 | 6 | #include <jni.h> |
| 7 | 7 | |
| 8 | 8 | namespace br | ... | ... |
openbr/plugins/likely.cpp renamed to openbr/plugins/core/likely.cpp
| 1 | -#include <likely.h> | |
| 2 | -#include <likely/opencv.hpp> | |
| 3 | - | |
| 4 | -#include "openbr/core/opencvutils.h" | |
| 5 | -#include "openbr_internal.h" | |
| 1 | +#include <openbr/plugins/openbr_internal.h> | |
| 6 | 2 | |
| 7 | 3 | namespace br |
| 8 | 4 | { |
| ... | ... | @@ -57,68 +53,6 @@ public: |
| 57 | 53 | |
| 58 | 54 | BR_REGISTER(Transform, LikelyTransform) |
| 59 | 55 | |
| 60 | -/*! | |
| 61 | - * \ingroup formats | |
| 62 | - * \brief Likely matrix format | |
| 63 | - * | |
| 64 | - * www.liblikely.org | |
| 65 | - * \author Josh Klontz \cite jklontz | |
| 66 | - */ | |
| 67 | -class lmatFormat : public Format | |
| 68 | -{ | |
| 69 | - Q_OBJECT | |
| 70 | - | |
| 71 | - Template read() const | |
| 72 | - { | |
| 73 | - const likely_const_mat m = likely_read(qPrintable(file.name), likely_file_guess); | |
| 74 | - const Template result(likelyToOpenCVMat(m)); | |
| 75 | - likely_release_mat(m); | |
| 76 | - return result; | |
| 77 | - } | |
| 78 | - | |
| 79 | - void write(const Template &t) const | |
| 80 | - { | |
| 81 | - const likely_const_mat m = likelyFromOpenCVMat(t); | |
| 82 | - likely_write(m, qPrintable(file.name)); | |
| 83 | - likely_release_mat(m); | |
| 84 | - } | |
| 85 | -}; | |
| 86 | - | |
| 87 | -BR_REGISTER(Format, lmatFormat) | |
| 88 | - | |
| 89 | -/*! | |
| 90 | - * \ingroup formats | |
| 91 | - * \brief Likely matrix format | |
| 92 | - * | |
| 93 | - * www.liblikely.org | |
| 94 | - * \author Josh Klontz \cite jklontz | |
| 95 | - */ | |
| 96 | -class lmatGallery : public Gallery | |
| 97 | -{ | |
| 98 | - Q_OBJECT | |
| 99 | - QList<cv::Mat> mats; | |
| 100 | - | |
| 101 | - ~lmatGallery() | |
| 102 | - { | |
| 103 | - const likely_const_mat m = likelyFromOpenCVMat(OpenCVUtils::toMatByRow(mats)); | |
| 104 | - likely_write(m, qPrintable(file.name)); | |
| 105 | - likely_release_mat(m); | |
| 106 | - } | |
| 107 | - | |
| 108 | - TemplateList readBlock(bool *done) | |
| 109 | - { | |
| 110 | - *done = true; | |
| 111 | - qFatal("Not supported."); | |
| 112 | - } | |
| 113 | - | |
| 114 | - void write(const Template &t) | |
| 115 | - { | |
| 116 | - mats.append(t); | |
| 117 | - } | |
| 118 | -}; | |
| 119 | - | |
| 120 | -BR_REGISTER(Gallery, lmatGallery) | |
| 121 | - | |
| 122 | 56 | } // namespace br |
| 123 | 57 | |
| 124 | -#include "likely.moc" | |
| 58 | +#include "core/likely.moc" | ... | ... |
openbr/plugins/core/loadstore.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/qtutils.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup transforms | |
| 25 | + * \brief Caches transform training. | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class LoadStoreTransform : public MetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + Q_PROPERTY(QString transformString READ get_transformString WRITE set_transformString RESET reset_transformString STORED false) | |
| 32 | + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) | |
| 33 | + BR_PROPERTY(QString, transformString, "Identity") | |
| 34 | + BR_PROPERTY(QString, fileName, QString()) | |
| 35 | + | |
| 36 | +public: | |
| 37 | + Transform *transform; | |
| 38 | + | |
| 39 | + LoadStoreTransform() : transform(NULL) {} | |
| 40 | + | |
| 41 | + QString description(bool expanded = false) const | |
| 42 | + { | |
| 43 | + if (expanded) { | |
| 44 | + QString res = transform->description(expanded); | |
| 45 | + return res; | |
| 46 | + } | |
| 47 | + return br::Object::description(expanded); | |
| 48 | + } | |
| 49 | + | |
| 50 | + Transform *simplify(bool &newTForm) | |
| 51 | + { | |
| 52 | + Transform *res = transform->simplify(newTForm); | |
| 53 | + return res; | |
| 54 | + } | |
| 55 | + | |
| 56 | + QList<Object *> getChildren() const | |
| 57 | + { | |
| 58 | + QList<Object *> rval; | |
| 59 | + rval.append(transform); | |
| 60 | + return rval; | |
| 61 | + } | |
| 62 | +private: | |
| 63 | + | |
| 64 | + void init() | |
| 65 | + { | |
| 66 | + if (transform != NULL) return; | |
| 67 | + if (fileName.isEmpty()) fileName = QRegExp("^[_a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString); | |
| 68 | + | |
| 69 | + if (!tryLoad()) | |
| 70 | + transform = make(transformString); | |
| 71 | + else | |
| 72 | + trainable = false; | |
| 73 | + } | |
| 74 | + | |
| 75 | + bool timeVarying() const | |
| 76 | + { | |
| 77 | + return transform->timeVarying(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + void train(const QList<TemplateList> &data) | |
| 81 | + { | |
| 82 | + if (QFileInfo(getFileName()).exists()) | |
| 83 | + return; | |
| 84 | + | |
| 85 | + transform->train(data); | |
| 86 | + | |
| 87 | + qDebug("Storing %s", qPrintable(fileName)); | |
| 88 | + QtUtils::BlockCompression compressedOut; | |
| 89 | + QFile fout(fileName); | |
| 90 | + QtUtils::touchDir(fout); | |
| 91 | + compressedOut.setBasis(&fout); | |
| 92 | + | |
| 93 | + QDataStream stream(&compressedOut); | |
| 94 | + QString desc = transform->description(); | |
| 95 | + | |
| 96 | + if (!compressedOut.open(QFile::WriteOnly)) | |
| 97 | + qFatal("Failed to open %s for writing.", qPrintable(file)); | |
| 98 | + | |
| 99 | + stream << desc; | |
| 100 | + transform->store(stream); | |
| 101 | + compressedOut.close(); | |
| 102 | + } | |
| 103 | + | |
| 104 | + void project(const Template &src, Template &dst) const | |
| 105 | + { | |
| 106 | + transform->project(src, dst); | |
| 107 | + } | |
| 108 | + | |
| 109 | + void project(const TemplateList &src, TemplateList &dst) const | |
| 110 | + { | |
| 111 | + transform->project(src, dst); | |
| 112 | + } | |
| 113 | + | |
| 114 | + void projectUpdate(const Template &src, Template &dst) | |
| 115 | + { | |
| 116 | + transform->projectUpdate(src, dst); | |
| 117 | + } | |
| 118 | + | |
| 119 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 120 | + { | |
| 121 | + transform->projectUpdate(src, dst); | |
| 122 | + } | |
| 123 | + | |
| 124 | + void finalize(TemplateList &output) | |
| 125 | + { | |
| 126 | + transform->finalize(output); | |
| 127 | + } | |
| 128 | + | |
| 129 | + QString getFileName() const | |
| 130 | + { | |
| 131 | + if (QFileInfo(fileName).exists()) return fileName; | |
| 132 | + | |
| 133 | + foreach(const QString &path, Globals->modelSearch) { | |
| 134 | + const QString file = path + "/" + fileName; | |
| 135 | + if (QFileInfo(file).exists()) | |
| 136 | + return file; | |
| 137 | + } | |
| 138 | + return QString(); | |
| 139 | + } | |
| 140 | + | |
| 141 | + bool tryLoad() | |
| 142 | + { | |
| 143 | + const QString file = getFileName(); | |
| 144 | + if (file.isEmpty()) return false; | |
| 145 | + | |
| 146 | + qDebug("Loading %s", qPrintable(file)); | |
| 147 | + QFile fin(file); | |
| 148 | + QtUtils::BlockCompression reader(&fin); | |
| 149 | + if (!reader.open(QIODevice::ReadOnly)) { | |
| 150 | + if (QFileInfo(file).exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file)); | |
| 151 | + else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file)); | |
| 152 | + } | |
| 153 | + | |
| 154 | + QDataStream stream(&reader); | |
| 155 | + stream >> transformString; | |
| 156 | + | |
| 157 | + transform = Transform::make(transformString); | |
| 158 | + transform->load(stream); | |
| 159 | + | |
| 160 | + return true; | |
| 161 | + } | |
| 162 | +}; | |
| 163 | + | |
| 164 | +BR_REGISTER(Transform, LoadStoreTransform) | |
| 165 | + | |
| 166 | +} // namespace br | |
| 167 | + | |
| 168 | +#include "core/loadstore.moc" | ... | ... |
openbr/plugins/core/pipe.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup Transforms | |
| 26 | + * \brief Transforms in series. | |
| 27 | + * \author Josh Klontz \cite jklontz | |
| 28 | + * | |
| 29 | + * The source br::Template is given to the first transform and the resulting br::Template is passed to the next transform, etc. | |
| 30 | + * | |
| 31 | + * \see ExpandTransform | |
| 32 | + * \see ForkTransform | |
| 33 | + */ | |
| 34 | +class PipeTransform : public CompositeTransform | |
| 35 | +{ | |
| 36 | + Q_OBJECT | |
| 37 | + | |
| 38 | + void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex) | |
| 39 | + { | |
| 40 | + TemplateList ftes; | |
| 41 | + for (int i=startIndex; i<stopIndex; i++) { | |
| 42 | + TemplateList res; | |
| 43 | + transforms[i]->project(*srcdst, res); | |
| 44 | + | |
| 45 | + splitFTEs(res, ftes); | |
| 46 | + *srcdst = res; | |
| 47 | + } | |
| 48 | + } | |
| 49 | + | |
| 50 | + void train(const QList<TemplateList> &data) | |
| 51 | + { | |
| 52 | + if (!trainable) return; | |
| 53 | + | |
| 54 | + QList<TemplateList> dataLines(data); | |
| 55 | + | |
| 56 | + int i = 0; | |
| 57 | + while (i < transforms.size()) { | |
| 58 | + // Conditional statement covers likely case that first transform is untrainable | |
| 59 | + if (transforms[i]->trainable) { | |
| 60 | + qDebug() << "Training " << transforms[i]->description() << "\n..."; | |
| 61 | + transforms[i]->train(dataLines); | |
| 62 | + } | |
| 63 | + | |
| 64 | + // if the transform is time varying, we can't project it in parallel | |
| 65 | + if (transforms[i]->timeVarying()) { | |
| 66 | + qDebug() << "Projecting " << transforms[i]->description() << "\n..."; | |
| 67 | + for (int j=0; j < dataLines.size();j++) { | |
| 68 | + TemplateList junk; | |
| 69 | + splitFTEs(dataLines[j], junk); | |
| 70 | + | |
| 71 | + transforms[i]->projectUpdate(dataLines[j], dataLines[j]); | |
| 72 | + } | |
| 73 | + | |
| 74 | + // advance i since we already projected for this stage. | |
| 75 | + i++; | |
| 76 | + | |
| 77 | + // the next stage might be trainable, so continue to evaluate it. | |
| 78 | + continue; | |
| 79 | + } | |
| 80 | + | |
| 81 | + // We project through any subsequent untrainable transforms at once | |
| 82 | + // as a memory optimization in case any of these intermediate | |
| 83 | + // transforms allocate a lot of memory (like OpenTransform) | |
| 84 | + // then we don't want all the training templates to be processed | |
| 85 | + // by that transform at once if we can avoid it. | |
| 86 | + int nextTrainableTransform = i+1; | |
| 87 | + while ((nextTrainableTransform < transforms.size()) && | |
| 88 | + !transforms[nextTrainableTransform]->trainable && | |
| 89 | + !transforms[nextTrainableTransform]->timeVarying()) | |
| 90 | + nextTrainableTransform++; | |
| 91 | + | |
| 92 | + // No more trainable transforms? Don't need any more projects then | |
| 93 | + if (nextTrainableTransform == transforms.size()) | |
| 94 | + break; | |
| 95 | + | |
| 96 | + fprintf(stderr, "Projecting %s", qPrintable(transforms[i]->description())); | |
| 97 | + for (int j=i+1; j < nextTrainableTransform; j++) | |
| 98 | + fprintf(stderr,"+%s", qPrintable(transforms[j]->description())); | |
| 99 | + fprintf(stderr, "\n...\n"); | |
| 100 | + fflush(stderr); | |
| 101 | + | |
| 102 | + QFutureSynchronizer<void> futures; | |
| 103 | + for (int j=0; j < dataLines.size(); j++) | |
| 104 | + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &dataLines[j], i, nextTrainableTransform)); | |
| 105 | + futures.waitForFinished(); | |
| 106 | + | |
| 107 | + i = nextTrainableTransform; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + | |
| 111 | + void projectUpdate(const Template &src, Template &dst) | |
| 112 | + { | |
| 113 | + dst = src; | |
| 114 | + foreach (Transform *f, transforms) { | |
| 115 | + try { | |
| 116 | + f->projectUpdate(dst); | |
| 117 | + if (dst.file.fte) | |
| 118 | + break; | |
| 119 | + } catch (...) { | |
| 120 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | |
| 121 | + dst = Template(src.file); | |
| 122 | + dst.file.fte = true; | |
| 123 | + break; | |
| 124 | + } | |
| 125 | + } | |
| 126 | + } | |
| 127 | + | |
| 128 | + // For time varying transforms, parallel execution over individual templates | |
| 129 | + // won't work. | |
| 130 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 131 | + { | |
| 132 | + TemplateList ftes; | |
| 133 | + dst = src; | |
| 134 | + foreach (Transform *f, transforms) { | |
| 135 | + TemplateList res; | |
| 136 | + f->projectUpdate(dst, res); | |
| 137 | + splitFTEs(res, ftes); | |
| 138 | + dst = res; | |
| 139 | + } | |
| 140 | + dst.append(ftes); | |
| 141 | + } | |
| 142 | + | |
| 143 | + virtual void finalize(TemplateList &output) | |
| 144 | + { | |
| 145 | + output.clear(); | |
| 146 | + // For each transform, | |
| 147 | + for (int i = 0; i < transforms.size(); i++) | |
| 148 | + { | |
| 149 | + | |
| 150 | + // Collect any final templates | |
| 151 | + TemplateList last_set; | |
| 152 | + transforms[i]->finalize(last_set); | |
| 153 | + if (last_set.empty()) | |
| 154 | + continue; | |
| 155 | + // Push any templates received through the remaining transforms in the sequence | |
| 156 | + for (int j = (i+1); j < transforms.size();j++) | |
| 157 | + { | |
| 158 | + transforms[j]->projectUpdate(last_set); | |
| 159 | + } | |
| 160 | + // append the result to the output set | |
| 161 | + output.append(last_set); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + void init() | |
| 166 | + { | |
| 167 | + QList<Transform *> flattened; | |
| 168 | + for (int i=0;i < transforms.size(); i++) | |
| 169 | + { | |
| 170 | + PipeTransform *probe = dynamic_cast<PipeTransform *> (transforms[i]); | |
| 171 | + if (!probe) { | |
| 172 | + flattened.append(transforms[i]); | |
| 173 | + continue; | |
| 174 | + } | |
| 175 | + for (int j=0; j < probe->transforms.size(); j++) | |
| 176 | + flattened.append(probe->transforms[j]); | |
| 177 | + } | |
| 178 | + transforms = flattened; | |
| 179 | + | |
| 180 | + CompositeTransform::init(); | |
| 181 | + } | |
| 182 | + | |
| 183 | +protected: | |
| 184 | + // Template list project -- process templates in parallel through Transform::project | |
| 185 | + // or if parallelism is disabled, handle them sequentially | |
| 186 | + void _project(const TemplateList &src, TemplateList &dst) const | |
| 187 | + { | |
| 188 | + TemplateList ftes; | |
| 189 | + dst = src; | |
| 190 | + foreach (const Transform *f, transforms) { | |
| 191 | + TemplateList res; | |
| 192 | + f->project(dst, res); | |
| 193 | + splitFTEs(res, ftes); | |
| 194 | + dst = res; | |
| 195 | + } | |
| 196 | + dst.append(ftes); | |
| 197 | + } | |
| 198 | + | |
| 199 | + // Single template const project, pass the template through each sub-transform, one after the other | |
| 200 | + virtual void _project(const Template &src, Template &dst) const | |
| 201 | + { | |
| 202 | + dst = src; | |
| 203 | + foreach (const Transform *f, transforms) { | |
| 204 | + try { | |
| 205 | + dst >> *f; | |
| 206 | + if (dst.file.fte) | |
| 207 | + break; | |
| 208 | + } catch (...) { | |
| 209 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | |
| 210 | + dst = Template(src.file); | |
| 211 | + dst.file.fte = true; | |
| 212 | + } | |
| 213 | + } | |
| 214 | + } | |
| 215 | +}; | |
| 216 | + | |
| 217 | +BR_REGISTER(Transform, PipeTransform) | |
| 218 | + | |
| 219 | +} // namespace br | |
| 220 | + | |
| 221 | +#include "core/pipe.moc" | ... | ... |
openbr/plugins/process.cpp renamed to openbr/plugins/core/processwrapper.cpp
| 1 | - | |
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 2 | 16 | |
| 3 | 17 | #include <QBuffer> |
| 4 | 18 | #include <QCoreApplication> |
| ... | ... | @@ -9,8 +23,8 @@ |
| 9 | 23 | #include <QUuid> |
| 10 | 24 | #include <QWaitCondition> |
| 11 | 25 | |
| 12 | -#include "openbr_internal.h" | |
| 13 | -#include "openbr/core/opencvutils.h" | |
| 26 | +#include <openbr/plugins/openbr_internal.h> | |
| 27 | +#include <openbr/core/opencvutils.h> | |
| 14 | 28 | |
| 15 | 29 | using namespace cv; |
| 16 | 30 | |
| ... | ... | @@ -658,4 +672,4 @@ BR_REGISTER(Transform, ProcessWrapperTransform) |
| 658 | 672 | |
| 659 | 673 | } |
| 660 | 674 | |
| 661 | -#include "process.moc" | |
| 675 | +#include "core/processwrapper.moc" | ... | ... |
openbr/plugins/core/progresscounter.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QElapsedTimer> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/qtutils.h> | |
| 21 | + | |
| 22 | +namespace br | |
| 23 | +{ | |
| 24 | + | |
| 25 | +class ProgressCounterTransform : public TimeVaryingTransform | |
| 26 | +{ | |
| 27 | + Q_OBJECT | |
| 28 | + | |
| 29 | + Q_PROPERTY(qint64 totalProgress READ get_totalProgress WRITE set_totalProgress RESET reset_totalProgress STORED false) | |
| 30 | + BR_PROPERTY(qint64, totalProgress, 1) | |
| 31 | + | |
| 32 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 33 | + { | |
| 34 | + dst = src; | |
| 35 | + | |
| 36 | + qint64 elapsed = timer.elapsed(); | |
| 37 | + int last_frame = -2; | |
| 38 | + if (!dst.empty()) { | |
| 39 | + for (int i=0;i < dst.size();i++) { | |
| 40 | + int frame = dst[i].file.get<int>("FrameNumber", -1); | |
| 41 | + if (frame == last_frame && frame != -1) | |
| 42 | + continue; | |
| 43 | + | |
| 44 | + // Use 1 as the starting index for progress output | |
| 45 | + Globals->currentProgress = dst[i].file.get<qint64>("progress",0)+1; | |
| 46 | + dst[i].file.remove("progress"); | |
| 47 | + last_frame = frame; | |
| 48 | + | |
| 49 | + Globals->currentStep++; | |
| 50 | + } | |
| 51 | + } | |
| 52 | + | |
| 53 | + // updated every second | |
| 54 | + if (elapsed > 1000) { | |
| 55 | + Globals->printStatus(); | |
| 56 | + timer.start(); | |
| 57 | + } | |
| 58 | + | |
| 59 | + return; | |
| 60 | + } | |
| 61 | + | |
| 62 | + void train(const TemplateList& data) | |
| 63 | + { | |
| 64 | + (void) data; | |
| 65 | + } | |
| 66 | + | |
| 67 | + void finalize(TemplateList &data) | |
| 68 | + { | |
| 69 | + (void) data; | |
| 70 | + float p = br_progress(); | |
| 71 | + qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep); | |
| 72 | + timer.start(); | |
| 73 | + Globals->startTime.start(); | |
| 74 | + Globals->currentStep = 0; | |
| 75 | + Globals->currentProgress = 0; | |
| 76 | + Globals->totalSteps = totalProgress; | |
| 77 | + } | |
| 78 | + | |
| 79 | + void init() | |
| 80 | + { | |
| 81 | + timer.start(); | |
| 82 | + Globals->startTime.start(); | |
| 83 | + Globals->currentProgress = 0; | |
| 84 | + Globals->currentStep = 0; | |
| 85 | + Globals->totalSteps = totalProgress; | |
| 86 | + } | |
| 87 | + | |
| 88 | +public: | |
| 89 | + ProgressCounterTransform() : TimeVaryingTransform(false,false) {} | |
| 90 | + QElapsedTimer timer; | |
| 91 | +}; | |
| 92 | + | |
| 93 | +BR_REGISTER(Transform, ProgressCounterTransform) | |
| 94 | + | |
| 95 | +} // namespace br | |
| 96 | + | |
| 97 | +#include "core/progresscounter.moc" | ... | ... |
openbr/plugins/core/propagate.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | |
| 2 | + | |
| 3 | +namespace br | |
| 4 | +{ | |
| 5 | + | |
| 6 | +/*! | |
| 7 | + * \ingroup transforms | |
| 8 | + * \brief Ensures that a template will be propogated. | |
| 9 | + * \author Scott Klum \cite sklum | |
| 10 | + */ | |
| 11 | +class PropagateTransform : public UntrainableMetaTransform | |
| 12 | +{ | |
| 13 | + Q_OBJECT | |
| 14 | + | |
| 15 | + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED true) | |
| 16 | + BR_PROPERTY(br::Transform *, transform, NULL) | |
| 17 | + | |
| 18 | + void project(const Template &src, Template &dst) const | |
| 19 | + { | |
| 20 | + transform->project(src,dst); | |
| 21 | + if (dst.isEmpty()) | |
| 22 | + dst = src; | |
| 23 | + } | |
| 24 | +}; | |
| 25 | + | |
| 26 | +BR_REGISTER(Transform, PropagateTransform) | |
| 27 | + | |
| 28 | +} // namespace br | |
| 29 | + | |
| 30 | +#include "core/propagate.moc" | ... | ... |
openbr/plugins/core/registrar.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup initializers | |
| 24 | + * \brief Register custom objects with Qt meta object system. | |
| 25 | + * \author Charles Otto \cite caotto | |
| 26 | + */ | |
| 27 | +class Registrar : public Initializer | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + void initialize() const | |
| 32 | + { | |
| 33 | + qRegisterMetaType<br::Neighbors>(); | |
| 34 | + } | |
| 35 | +}; | |
| 36 | + | |
| 37 | +BR_REGISTER(Initializer, Registrar) | |
| 38 | + | |
| 39 | +} // namespace br | |
| 40 | + | |
| 41 | +#include "core/registrar.moc" | ... | ... |
openbr/plugins/core/remove.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Removes the matrix from the template at the specified index. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + * \see IdentityTransform DiscardTransform FirstTransform RestTransform | |
| 27 | + */ | |
| 28 | +//! [example_transform] | |
| 29 | +class RemoveTransform : public UntrainableMetaTransform | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + Q_PROPERTY(int index READ get_index WRITE set_index RESET reset_index STORED false) | |
| 33 | + BR_PROPERTY(int, index, 0) | |
| 34 | + | |
| 35 | + void project(const Template &src, Template &dst) const | |
| 36 | + { | |
| 37 | + dst = src; | |
| 38 | + dst.removeAt(index); | |
| 39 | + } | |
| 40 | +}; | |
| 41 | + | |
| 42 | +BR_REGISTER(Transform, RemoveTransform) | |
| 43 | +//! [example_transform] | |
| 44 | + | |
| 45 | +} // namespace br | |
| 46 | + | |
| 47 | +#include "core/remove.moc" | ... | ... |
openbr/plugins/core/rest.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Removes the first matrix from the template. | |
| 25 | + * \see IdentityTransform DiscardTransform FirstTransform RemoveTransform | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class RestTransform : public UntrainableMetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + void project(const Template &src, Template &dst) const | |
| 33 | + { | |
| 34 | + dst = src; | |
| 35 | + dst.removeFirst(); | |
| 36 | + } | |
| 37 | +}; | |
| 38 | + | |
| 39 | +BR_REGISTER(Transform, RestTransform) | |
| 40 | + | |
| 41 | +} // namespace br | |
| 42 | + | |
| 43 | +#include "core/rest.moc" | ... | ... |
openbr/plugins/core/schrodinger.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief Generates two templates, one of which is passed through a transform and the other | |
| 25 | + * is not. No cats were harmed in the making of this transform. | |
| 26 | + * \author Scott Klum \cite sklum | |
| 27 | + */ | |
| 28 | +class SchrodingerTransform : public MetaTransform | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | |
| 32 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 33 | + | |
| 34 | +public: | |
| 35 | + void train(const TemplateList &data) | |
| 36 | + { | |
| 37 | + transform->train(data); | |
| 38 | + } | |
| 39 | + | |
| 40 | + void project(const TemplateList &src, TemplateList &dst) const | |
| 41 | + { | |
| 42 | + foreach(const Template &t, src) { | |
| 43 | + dst.append(t); | |
| 44 | + Template u; | |
| 45 | + transform->project(t,u); | |
| 46 | + dst.append(u); | |
| 47 | + } | |
| 48 | + } | |
| 49 | + | |
| 50 | + void project(const Template &src, Template &dst) const { | |
| 51 | + TemplateList temp; | |
| 52 | + project(TemplateList() << src, temp); | |
| 53 | + if (!temp.isEmpty()) dst = temp.first(); | |
| 54 | + } | |
| 55 | + | |
| 56 | +}; | |
| 57 | +BR_REGISTER(Transform, SchrodingerTransform) | |
| 58 | + | |
| 59 | +} // namespace br | |
| 60 | + | |
| 61 | +#include "core/schrodinger.moc" | ... | ... |
openbr/plugins/core/singleton.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup transforms | |
| 24 | + * \brief A globally shared transform. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class SingletonTransform : public MetaTransform | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | |
| 31 | + BR_PROPERTY(QString, description, "Identity") | |
| 32 | + | |
| 33 | + static QMutex mutex; | |
| 34 | + static QHash<QString,Transform*> transforms; | |
| 35 | + static QHash<QString,int> trainingReferenceCounts; | |
| 36 | + static QHash<QString,TemplateList> trainingData; | |
| 37 | + | |
| 38 | + Transform *transform; | |
| 39 | + | |
| 40 | + void init() | |
| 41 | + { | |
| 42 | + QMutexLocker locker(&mutex); | |
| 43 | + if (!transforms.contains(description)) { | |
| 44 | + transforms.insert(description, make(description)); | |
| 45 | + trainingReferenceCounts.insert(description, 0); | |
| 46 | + } | |
| 47 | + | |
| 48 | + transform = transforms[description]; | |
| 49 | + trainingReferenceCounts[description]++; | |
| 50 | + } | |
| 51 | + | |
| 52 | + void train(const TemplateList &data) | |
| 53 | + { | |
| 54 | + QMutexLocker locker(&mutex); | |
| 55 | + trainingData[description].append(data); | |
| 56 | + trainingReferenceCounts[description]--; | |
| 57 | + if (trainingReferenceCounts[description] > 0) return; | |
| 58 | + transform->train(trainingData[description]); | |
| 59 | + trainingData[description].clear(); | |
| 60 | + } | |
| 61 | + | |
| 62 | + void project(const Template &src, Template &dst) const | |
| 63 | + { | |
| 64 | + transform->project(src, dst); | |
| 65 | + } | |
| 66 | + | |
| 67 | + void store(QDataStream &stream) const | |
| 68 | + { | |
| 69 | + if (transform->parent() == this) | |
| 70 | + transform->store(stream); | |
| 71 | + } | |
| 72 | + | |
| 73 | + void load(QDataStream &stream) | |
| 74 | + { | |
| 75 | + if (transform->parent() == this) | |
| 76 | + transform->load(stream); | |
| 77 | + } | |
| 78 | +}; | |
| 79 | + | |
| 80 | +QMutex SingletonTransform::mutex; | |
| 81 | +QHash<QString,Transform*> SingletonTransform::transforms; | |
| 82 | +QHash<QString,int> SingletonTransform::trainingReferenceCounts; | |
| 83 | +QHash<QString,TemplateList> SingletonTransform::trainingData; | |
| 84 | + | |
| 85 | +BR_REGISTER(Transform, SingletonTransform) | |
| 86 | + | |
| 87 | +} // namespace br | |
| 88 | + | |
| 89 | +#include "core/singleton.moc" | ... | ... |
openbr/plugins/stream.cpp renamed to openbr/plugins/core/stream.cpp
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 1 | 17 | #include <fstream> |
| 2 | 18 | #include <QReadWriteLock> |
| 3 | 19 | #include <QWaitCondition> |
| ... | ... | @@ -8,10 +24,11 @@ |
| 8 | 24 | #include <QtConcurrent> |
| 9 | 25 | #include <opencv/highgui.h> |
| 10 | 26 | #include <opencv2/highgui/highgui.hpp> |
| 11 | -#include "openbr_internal.h" | |
| 12 | -#include "openbr/core/common.h" | |
| 13 | -#include "openbr/core/opencvutils.h" | |
| 14 | -#include "openbr/core/qtutils.h" | |
| 27 | + | |
| 28 | +#include <openbr/plugins/openbr_internal.h> | |
| 29 | +#include <openbr/core/common.h> | |
| 30 | +#include <openbr/core/opencvutils.h> | |
| 31 | +#include <openbr/core/qtutils.h> | |
| 15 | 32 | |
| 16 | 33 | using namespace cv; |
| 17 | 34 | using namespace std; |
| ... | ... | @@ -1360,5 +1377,5 @@ BR_REGISTER(Transform, StreamTransform) |
| 1360 | 1377 | |
| 1361 | 1378 | } // namespace br |
| 1362 | 1379 | |
| 1363 | -#include "stream.moc" | |
| 1380 | +#include "core/stream.moc" | |
| 1364 | 1381 | ... | ... |
openbr/plugins/crop.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | - * Copyright 2012 The MITRE Corporation * | |
| 3 | - * * | |
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | - * you may not use this file except in compliance with the License. * | |
| 6 | - * You may obtain a copy of the License at * | |
| 7 | - * * | |
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | - * * | |
| 10 | - * Unless required by applicable law or agreed to in writing, software * | |
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | - * See the License for the specific language governing permissions and * | |
| 14 | - * limitations under the License. * | |
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | - | |
| 17 | -#include <opencv2/imgproc/imgproc.hpp> | |
| 18 | -#include "openbr_internal.h" | |
| 19 | - | |
| 20 | -#include "openbr/core/opencvutils.h" | |
| 21 | - | |
| 22 | -using namespace cv; | |
| 23 | - | |
| 24 | -namespace br | |
| 25 | -{ | |
| 26 | - | |
| 27 | -/*! | |
| 28 | - * \ingroup transforms | |
| 29 | - * \brief Crops about the specified region of interest. | |
| 30 | - * \author Josh Klontz \cite jklontz | |
| 31 | - */ | |
| 32 | -class CropTransform : public UntrainableTransform | |
| 33 | -{ | |
| 34 | - Q_OBJECT | |
| 35 | - Q_PROPERTY(int x READ get_x WRITE set_x RESET reset_x STORED false) | |
| 36 | - Q_PROPERTY(int y READ get_y WRITE set_y RESET reset_y STORED false) | |
| 37 | - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | |
| 38 | - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | |
| 39 | - BR_PROPERTY(int, x, 0) | |
| 40 | - BR_PROPERTY(int, y, 0) | |
| 41 | - BR_PROPERTY(int, width, -1) | |
| 42 | - BR_PROPERTY(int, height, -1) | |
| 43 | - | |
| 44 | - void project(const Template &src, Template &dst) const | |
| 45 | - { | |
| 46 | - dst = Mat(src, Rect(x, y, width < 1 ? src.m().cols-x-abs(width) : width, height < 1 ? src.m().rows-y-abs(height) : height)); | |
| 47 | - } | |
| 48 | -}; | |
| 49 | - | |
| 50 | -BR_REGISTER(Transform, CropTransform) | |
| 51 | - | |
| 52 | -/*! | |
| 53 | - * \ingroup transforms | |
| 54 | - * \brief Crops the rectangular regions of interest. | |
| 55 | - * \author Josh Klontz \cite jklontz | |
| 56 | - */ | |
| 57 | -class ROITransform : public UntrainableTransform | |
| 58 | -{ | |
| 59 | - Q_OBJECT | |
| 60 | - Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | |
| 61 | - BR_PROPERTY(QString, propName, "") | |
| 62 | - | |
| 63 | - void project(const Template &src, Template &dst) const | |
| 64 | - { | |
| 65 | - if (!propName.isEmpty()) { | |
| 66 | - QRectF rect = src.file.get<QRectF>(propName); | |
| 67 | - dst += src.m()(OpenCVUtils::toRect(rect)); | |
| 68 | - } else if (!src.file.rects().empty()) { | |
| 69 | - foreach (const QRectF &rect, src.file.rects()) | |
| 70 | - dst += src.m()(OpenCVUtils::toRect(rect)); | |
| 71 | - } else if (src.file.contains(QStringList() << "X" << "Y" << "Width" << "Height")) { | |
| 72 | - dst += src.m()(Rect(src.file.get<int>("X"), | |
| 73 | - src.file.get<int>("Y"), | |
| 74 | - src.file.get<int>("Width"), | |
| 75 | - src.file.get<int>("Height"))); | |
| 76 | - } else { | |
| 77 | - dst = src; | |
| 78 | - if (Globals->verbose) | |
| 79 | - qWarning("No rects present in file."); | |
| 80 | - } | |
| 81 | - } | |
| 82 | -}; | |
| 83 | - | |
| 84 | -BR_REGISTER(Transform, ROITransform) | |
| 85 | - | |
| 86 | -/*! | |
| 87 | - * \ingroup transforms | |
| 88 | - * \brief Crops the rectangular regions of interest from given points and sizes. | |
| 89 | - * \author Austin Blanton \cite imaus10 | |
| 90 | - */ | |
| 91 | -class ROIFromPtsTransform : public UntrainableTransform | |
| 92 | -{ | |
| 93 | - Q_OBJECT | |
| 94 | - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | |
| 95 | - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | |
| 96 | - BR_PROPERTY(int, width, 1) | |
| 97 | - BR_PROPERTY(int, height, 1) | |
| 98 | - | |
| 99 | - void project(const Template &src, Template &dst) const | |
| 100 | - { | |
| 101 | - foreach (const QPointF &pt, src.file.points()) { | |
| 102 | - int x = pt.x() - (width/2); | |
| 103 | - int y = pt.y() - (height/2); | |
| 104 | - dst += src.m()(Rect(x, y, width, height)); | |
| 105 | - } | |
| 106 | - } | |
| 107 | -}; | |
| 108 | - | |
| 109 | -BR_REGISTER(Transform, ROIFromPtsTransform) | |
| 110 | - | |
| 111 | -/*! | |
| 112 | - * \ingroup transforms | |
| 113 | - * \brief Resize the template | |
| 114 | - * \author Josh Klontz \cite jklontz | |
| 115 | - * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement. | |
| 116 | - * \param preserveAspect If true, the image will be sized per specification, but | |
| 117 | - * a border will be applied to preserve aspect ratio. | |
| 118 | - */ | |
| 119 | -class ResizeTransform : public UntrainableTransform | |
| 120 | -{ | |
| 121 | - Q_OBJECT | |
| 122 | - Q_ENUMS(Method) | |
| 123 | - | |
| 124 | -public: | |
| 125 | - /*!< */ | |
| 126 | - enum Method { Near = INTER_NEAREST, | |
| 127 | - Area = INTER_AREA, | |
| 128 | - Bilin = INTER_LINEAR, | |
| 129 | - Cubic = INTER_CUBIC, | |
| 130 | - Lanczo = INTER_LANCZOS4}; | |
| 131 | - | |
| 132 | -private: | |
| 133 | - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | |
| 134 | - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | |
| 135 | - Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | |
| 136 | - Q_PROPERTY(bool preserveAspect READ get_preserveAspect WRITE set_preserveAspect RESET reset_preserveAspect STORED false) | |
| 137 | - BR_PROPERTY(int, rows, -1) | |
| 138 | - BR_PROPERTY(int, columns, -1) | |
| 139 | - BR_PROPERTY(Method, method, Bilin) | |
| 140 | - BR_PROPERTY(bool, preserveAspect, false) | |
| 141 | - | |
| 142 | - void project(const Template &src, Template &dst) const | |
| 143 | - { | |
| 144 | - if (!preserveAspect) | |
| 145 | - resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method); | |
| 146 | - else { | |
| 147 | - float inRatio = (float) src.m().rows / src.m().cols; | |
| 148 | - float outRatio = (float) rows / columns; | |
| 149 | - dst = Mat::zeros(rows, columns, src.m().type()); | |
| 150 | - if (outRatio > inRatio) { | |
| 151 | - float heightAR = src.m().rows * inRatio / outRatio; | |
| 152 | - Mat buffer; | |
| 153 | - resize(src, buffer, Size(columns, heightAR), 0, 0, method); | |
| 154 | - buffer.copyTo(dst.m()(Rect(0, (rows - heightAR) / 2, columns, heightAR))); | |
| 155 | - } else { | |
| 156 | - float widthAR = src.m().cols / inRatio * outRatio; | |
| 157 | - Mat buffer; | |
| 158 | - resize(src, buffer, Size(widthAR, rows), 0, 0, method); | |
| 159 | - buffer.copyTo(dst.m()(Rect((columns - widthAR) / 2, 0, widthAR, rows))); | |
| 160 | - } | |
| 161 | - } | |
| 162 | - } | |
| 163 | -}; | |
| 164 | - | |
| 165 | -BR_REGISTER(Transform, ResizeTransform) | |
| 166 | - | |
| 167 | -/*! | |
| 168 | - * \ingroup transforms | |
| 169 | - * \brief Limit the size of the template | |
| 170 | - * \author Josh Klontz \cite jklontz | |
| 171 | - */ | |
| 172 | -class LimitSizeTransform : public UntrainableTransform | |
| 173 | -{ | |
| 174 | - Q_OBJECT | |
| 175 | - Q_PROPERTY(int max READ get_max WRITE set_max RESET reset_max STORED false) | |
| 176 | - BR_PROPERTY(int, max, -1) | |
| 177 | - | |
| 178 | - void project(const Template &src, Template &dst) const | |
| 179 | - { | |
| 180 | - const Mat &m = src; | |
| 181 | - if (m.rows > m.cols) | |
| 182 | - if (m.rows > max) resize(m, dst, Size(std::max(1, m.cols * max / m.rows), max)); | |
| 183 | - else dst = m; | |
| 184 | - else | |
| 185 | - if (m.cols > max) resize(m, dst, Size(max, std::max(1, m.rows * max / m.cols))); | |
| 186 | - else dst = m; | |
| 187 | - } | |
| 188 | -}; | |
| 189 | - | |
| 190 | -BR_REGISTER(Transform, LimitSizeTransform) | |
| 191 | - | |
| 192 | -/*! | |
| 193 | - * \ingroup transforms | |
| 194 | - * \brief Enforce a multiple of \em n columns. | |
| 195 | - * \author Josh Klontz \cite jklontz | |
| 196 | - */ | |
| 197 | -class DivTransform : public UntrainableTransform | |
| 198 | -{ | |
| 199 | - Q_OBJECT | |
| 200 | - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | |
| 201 | - BR_PROPERTY(int, n, 1) | |
| 202 | - | |
| 203 | - void project(const Template &src, Template &dst) const | |
| 204 | - { | |
| 205 | - dst = Mat(src, Rect(0,0,n*(src.m().cols/n),src.m().rows)); | |
| 206 | - } | |
| 207 | -}; | |
| 208 | - | |
| 209 | -BR_REGISTER(Transform, DivTransform) | |
| 210 | - | |
| 211 | -/*! | |
| 212 | - * \ingroup transforms | |
| 213 | - * \brief Crop out black borders | |
| 214 | - * \author Josh Klontz \cite jklontz | |
| 215 | - */ | |
| 216 | -class CropBlackTransform : public UntrainableTransform | |
| 217 | -{ | |
| 218 | - Q_OBJECT | |
| 219 | - | |
| 220 | - void project(const Template &src, Template &dst) const | |
| 221 | - { | |
| 222 | - Mat gray; | |
| 223 | - OpenCVUtils::cvtGray(src, gray); | |
| 224 | - | |
| 225 | - int xStart = 0; | |
| 226 | - while (xStart < gray.cols) { | |
| 227 | - if (mean(gray.col(xStart))[0] >= 1) break; | |
| 228 | - xStart++; | |
| 229 | - } | |
| 230 | - | |
| 231 | - int xEnd = gray.cols - 1; | |
| 232 | - while (xEnd >= 0) { | |
| 233 | - if (mean(gray.col(xEnd))[0] >= 1) break; | |
| 234 | - xEnd--; | |
| 235 | - } | |
| 236 | - | |
| 237 | - int yStart = 0; | |
| 238 | - while (yStart < gray.rows) { | |
| 239 | - if (mean(gray.col(yStart))[0] >= 1) break; | |
| 240 | - yStart++; | |
| 241 | - } | |
| 242 | - | |
| 243 | - int yEnd = gray.rows - 1; | |
| 244 | - while (yEnd >= 0) { | |
| 245 | - if (mean(gray.col(yEnd))[0] >= 1) break; | |
| 246 | - yEnd--; | |
| 247 | - } | |
| 248 | - | |
| 249 | - dst = src.m()(Rect(xStart, yStart, xEnd-xStart, yEnd-yStart)); | |
| 250 | - } | |
| 251 | -}; | |
| 252 | - | |
| 253 | -BR_REGISTER(Transform, CropBlackTransform) | |
| 254 | - | |
| 255 | -/*! | |
| 256 | - * \ingroup transforms | |
| 257 | - * \brief Divide the matrix into 4 smaller matricies of equal size. | |
| 258 | - * \author Josh Klontz \cite jklontz | |
| 259 | - */ | |
| 260 | -class SubdivideTransform : public UntrainableTransform | |
| 261 | -{ | |
| 262 | - Q_OBJECT | |
| 263 | - | |
| 264 | - void project(const Template &src, Template &dst) const | |
| 265 | - { | |
| 266 | - const Mat &m = src; | |
| 267 | - const int subrows = m.rows/2; | |
| 268 | - const int subcolumns = m.cols/2; | |
| 269 | - dst.append(Mat(m,Rect(0, 0, subcolumns, subrows)).clone()); | |
| 270 | - dst.append(Mat(m,Rect(subcolumns, 0, subcolumns, subrows)).clone()); | |
| 271 | - dst.append(Mat(m,Rect(0, subrows, subcolumns, subrows)).clone()); | |
| 272 | - dst.append(Mat(m,Rect(subcolumns, subrows, subcolumns, subrows)).clone()); | |
| 273 | - } | |
| 274 | -}; | |
| 275 | - | |
| 276 | -BR_REGISTER(Transform, SubdivideTransform) | |
| 277 | - | |
| 278 | -/*! | |
| 279 | - * \ingroup transforms | |
| 280 | - * \brief Trim the image so the width and the height are the same size. | |
| 281 | - * \author Josh Klontz \cite jklontz | |
| 282 | - */ | |
| 283 | -class CropSquareTransform : public UntrainableTransform | |
| 284 | -{ | |
| 285 | - Q_OBJECT | |
| 286 | - | |
| 287 | - void project(const Template &src, Template &dst) const | |
| 288 | - { | |
| 289 | - const Mat &m = src; | |
| 290 | - const int newSize = min(m.rows, m.cols); | |
| 291 | - dst = Mat(m, Rect((m.cols-newSize)/2, (m.rows-newSize)/2, newSize, newSize)); | |
| 292 | - } | |
| 293 | -}; | |
| 294 | - | |
| 295 | -BR_REGISTER(Transform, CropSquareTransform) | |
| 296 | - | |
| 297 | -} // namespace br | |
| 298 | - | |
| 299 | -#include "crop.moc" |
openbr/plugins/cvt.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | - * Copyright 2012 The MITRE Corporation * | |
| 3 | - * * | |
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | - * you may not use this file except in compliance with the License. * | |
| 6 | - * You may obtain a copy of the License at * | |
| 7 | - * * | |
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | - * * | |
| 10 | - * Unless required by applicable law or agreed to in writing, software * | |
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | - * See the License for the specific language governing permissions and * | |
| 14 | - * limitations under the License. * | |
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | - | |
| 17 | -#include <opencv2/imgproc/imgproc_c.h> | |
| 18 | -#include <opencv2/imgproc/imgproc.hpp> | |
| 19 | -#include "openbr_internal.h" | |
| 20 | -#include "openbr/core/opencvutils.h" | |
| 21 | - | |
| 22 | -using namespace cv; | |
| 23 | - | |
| 24 | -namespace br | |
| 25 | -{ | |
| 26 | - | |
| 27 | -/*! | |
| 28 | - * \ingroup transforms | |
| 29 | - * \brief Colorspace conversion. | |
| 30 | - * \author Josh Klontz \cite jklontz | |
| 31 | - */ | |
| 32 | -class CvtTransform : public UntrainableTransform | |
| 33 | -{ | |
| 34 | - Q_OBJECT | |
| 35 | - Q_ENUMS(ColorSpace) | |
| 36 | - Q_PROPERTY(ColorSpace colorSpace READ get_colorSpace WRITE set_colorSpace RESET reset_colorSpace STORED false) | |
| 37 | - Q_PROPERTY(int channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | |
| 38 | - | |
| 39 | -public: | |
| 40 | - enum ColorSpace { Gray = CV_BGR2GRAY, | |
| 41 | - RGBGray = CV_RGB2GRAY, | |
| 42 | - HLS = CV_BGR2HLS, | |
| 43 | - HSV = CV_BGR2HSV, | |
| 44 | - Lab = CV_BGR2Lab, | |
| 45 | - Luv = CV_BGR2Luv, | |
| 46 | - RGB = CV_BGR2RGB, | |
| 47 | - XYZ = CV_BGR2XYZ, | |
| 48 | - YCrCb = CV_BGR2YCrCb, | |
| 49 | - Color = CV_GRAY2BGR }; | |
| 50 | - | |
| 51 | -private: | |
| 52 | - BR_PROPERTY(ColorSpace, colorSpace, Gray) | |
| 53 | - BR_PROPERTY(int, channel, -1) | |
| 54 | - | |
| 55 | - void project(const Template &src, Template &dst) const | |
| 56 | - { | |
| 57 | - if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace); | |
| 58 | - else dst = src; | |
| 59 | - | |
| 60 | - if (channel != -1) { | |
| 61 | - std::vector<Mat> mv; | |
| 62 | - split(dst, mv); | |
| 63 | - dst = mv[channel % (int)mv.size()]; | |
| 64 | - } | |
| 65 | - } | |
| 66 | -}; | |
| 67 | - | |
| 68 | -BR_REGISTER(Transform, CvtTransform) | |
| 69 | - | |
| 70 | -/*! | |
| 71 | - * \ingroup transforms | |
| 72 | - * \brief Convert to floating point format. | |
| 73 | - * \author Josh Klontz \cite jklontz | |
| 74 | - */ | |
| 75 | -class CvtFloatTransform : public UntrainableTransform | |
| 76 | -{ | |
| 77 | - Q_OBJECT | |
| 78 | - | |
| 79 | - void project(const Template &src, Template &dst) const | |
| 80 | - { | |
| 81 | - src.m().convertTo(dst, CV_32F); | |
| 82 | - } | |
| 83 | -}; | |
| 84 | - | |
| 85 | -BR_REGISTER(Transform, CvtFloatTransform) | |
| 86 | - | |
| 87 | -/*! | |
| 88 | - * \ingroup transforms | |
| 89 | - * \brief Convert to uchar format | |
| 90 | - * \author Josh Klontz \cite jklontz | |
| 91 | - */ | |
| 92 | -class CvtUCharTransform : public UntrainableTransform | |
| 93 | -{ | |
| 94 | - Q_OBJECT | |
| 95 | - | |
| 96 | - void project(const Template &src, Template &dst) const | |
| 97 | - { | |
| 98 | - OpenCVUtils::cvtUChar(src, dst); | |
| 99 | - } | |
| 100 | -}; | |
| 101 | - | |
| 102 | -BR_REGISTER(Transform, CvtUCharTransform) | |
| 103 | - | |
| 104 | -/*! | |
| 105 | - * \ingroup transforms | |
| 106 | - * \brief Scales using the given factor | |
| 107 | - * \author Scott Klum \cite sklum | |
| 108 | - */ | |
| 109 | -class ScaleTransform : public UntrainableTransform | |
| 110 | -{ | |
| 111 | - Q_OBJECT | |
| 112 | - | |
| 113 | - Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) | |
| 114 | - BR_PROPERTY(float, scaleFactor, 1.) | |
| 115 | - | |
| 116 | - void project(const Template &src, Template &dst) const | |
| 117 | - { | |
| 118 | - resize(src, dst, Size(src.m().cols*scaleFactor,src.m().rows*scaleFactor)); | |
| 119 | - | |
| 120 | - QList<QRectF> rects = src.file.rects(); | |
| 121 | - for (int i=0; i<rects.size(); i++) | |
| 122 | - rects[i] = QRectF(rects[i].topLeft()*scaleFactor,rects[i].bottomRight()*scaleFactor); | |
| 123 | - dst.file.setRects(rects); | |
| 124 | - | |
| 125 | - QList<QPointF> points = src.file.points(); | |
| 126 | - for (int i=0; i<points.size(); i++) | |
| 127 | - points[i] = points[i] * scaleFactor; | |
| 128 | - dst.file.setPoints(points); | |
| 129 | - | |
| 130 | - } | |
| 131 | -}; | |
| 132 | - | |
| 133 | -BR_REGISTER(Transform, ScaleTransform) | |
| 134 | - | |
| 135 | -/*! | |
| 136 | - * \ingroup transforms | |
| 137 | - * \brief Split a multi-channel matrix into several single-channel matrices. | |
| 138 | - * \author Josh Klontz \cite jklontz | |
| 139 | - */ | |
| 140 | -class SplitChannelsTransform : public UntrainableTransform | |
| 141 | -{ | |
| 142 | - Q_OBJECT | |
| 143 | - | |
| 144 | - void project(const Template &src, Template &dst) const | |
| 145 | - { | |
| 146 | - std::vector<Mat> mv; | |
| 147 | - split(src, mv); | |
| 148 | - foreach (const Mat &m, mv) | |
| 149 | - dst += m; | |
| 150 | - } | |
| 151 | -}; | |
| 152 | - | |
| 153 | -BR_REGISTER(Transform, SplitChannelsTransform) | |
| 154 | - | |
| 155 | -/*! | |
| 156 | - * \ingroup transforms | |
| 157 | - * \brief Enforce the matrix has a certain number of channels by adding or removing channels. | |
| 158 | - * \author Josh Klontz \cite jklontz | |
| 159 | - */ | |
| 160 | -class EnsureChannelsTransform : public UntrainableTransform | |
| 161 | -{ | |
| 162 | - Q_OBJECT | |
| 163 | - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | |
| 164 | - BR_PROPERTY(int, n, 1) | |
| 165 | - | |
| 166 | - void project(const Template &src, Template &dst) const | |
| 167 | - { | |
| 168 | - if (src.m().channels() == n) { | |
| 169 | - dst = src; | |
| 170 | - } else { | |
| 171 | - std::vector<Mat> mv; | |
| 172 | - split(src, mv); | |
| 173 | - | |
| 174 | - // Add extra channels | |
| 175 | - while ((int)mv.size() < n) { | |
| 176 | - for (int i=0; i<src.m().channels(); i++) { | |
| 177 | - mv.push_back(mv[i]); | |
| 178 | - if ((int)mv.size() == n) | |
| 179 | - break; | |
| 180 | - } | |
| 181 | - } | |
| 182 | - | |
| 183 | - // Remove extra channels | |
| 184 | - while ((int)mv.size() > n) | |
| 185 | - mv.pop_back(); | |
| 186 | - | |
| 187 | - merge(mv, dst); | |
| 188 | - } | |
| 189 | - } | |
| 190 | -}; | |
| 191 | - | |
| 192 | -BR_REGISTER(Transform, EnsureChannelsTransform) | |
| 193 | - | |
| 194 | -/*! | |
| 195 | - * \ingroup transforms | |
| 196 | - * \brief Drop the alpha channel (if exists). | |
| 197 | - * \author Austin Blanton \cite imaus10 | |
| 198 | - */ | |
| 199 | -class DiscardAlphaTransform : public UntrainableTransform | |
| 200 | -{ | |
| 201 | - Q_OBJECT | |
| 202 | - | |
| 203 | - void project(const Template &src, Template &dst) const | |
| 204 | - { | |
| 205 | - if (src.m().channels() > 4 || src.m().channels() == 2) { | |
| 206 | - dst.file.fte = true; | |
| 207 | - return; | |
| 208 | - } | |
| 209 | - | |
| 210 | - dst = src; | |
| 211 | - if (src.m().channels() == 4) { | |
| 212 | - std::vector<Mat> mv; | |
| 213 | - split(src, mv); | |
| 214 | - mv.pop_back(); | |
| 215 | - merge(mv, dst); | |
| 216 | - } | |
| 217 | - } | |
| 218 | -}; | |
| 219 | - | |
| 220 | -BR_REGISTER(Transform, DiscardAlphaTransform) | |
| 221 | - | |
| 222 | -/*! | |
| 223 | - * \ingroup transforms | |
| 224 | - * \brief Normalized RG color space. | |
| 225 | - * \author Josh Klontz \cite jklontz | |
| 226 | - */ | |
| 227 | -class RGTransform : public UntrainableTransform | |
| 228 | -{ | |
| 229 | - Q_OBJECT | |
| 230 | - | |
| 231 | - void project(const Template &src, Template &dst) const | |
| 232 | - { | |
| 233 | - if (src.m().type() != CV_8UC3) | |
| 234 | - qFatal("Expected CV_8UC3 images."); | |
| 235 | - | |
| 236 | - const Mat &m = src.m(); | |
| 237 | - Mat R(m.size(), CV_8UC1); // R / (R+G+B) | |
| 238 | - Mat G(m.size(), CV_8UC1); // G / (R+G+B) | |
| 239 | - | |
| 240 | - for (int i=0; i<m.rows; i++) | |
| 241 | - for (int j=0; j<m.cols; j++) { | |
| 242 | - Vec3b v = m.at<Vec3b>(i,j); | |
| 243 | - const int b = v[0]; | |
| 244 | - const int g = v[1]; | |
| 245 | - const int r = v[2]; | |
| 246 | - const int sum = b + g + r; | |
| 247 | - if (sum > 0) { | |
| 248 | - R.at<uchar>(i, j) = saturate_cast<uchar>(255.0*r/(r+g+b)); | |
| 249 | - G.at<uchar>(i, j) = saturate_cast<uchar>(255.0*g/(r+g+b)); | |
| 250 | - } else { | |
| 251 | - R.at<uchar>(i, j) = 0; | |
| 252 | - G.at<uchar>(i, j) = 0; | |
| 253 | - } | |
| 254 | - } | |
| 255 | - | |
| 256 | - dst.append(R); | |
| 257 | - dst.append(G); | |
| 258 | - } | |
| 259 | -}; | |
| 260 | - | |
| 261 | -BR_REGISTER(Transform, RGTransform) | |
| 262 | - | |
| 263 | -/*! | |
| 264 | - * \ingroup transforms | |
| 265 | - * \brief dst = a*src+b | |
| 266 | - * \author Josh Klontz \cite jklontz | |
| 267 | - */ | |
| 268 | -class MAddTransform : public UntrainableTransform | |
| 269 | -{ | |
| 270 | - Q_OBJECT | |
| 271 | - Q_PROPERTY(double a READ get_a WRITE set_a RESET reset_a STORED false) | |
| 272 | - Q_PROPERTY(double b READ get_b WRITE set_b RESET reset_b STORED false) | |
| 273 | - BR_PROPERTY(double, a, 1) | |
| 274 | - BR_PROPERTY(double, b, 0) | |
| 275 | - | |
| 276 | - void project(const Template &src, Template &dst) const | |
| 277 | - { | |
| 278 | - src.m().convertTo(dst.m(), src.m().depth(), a, b); | |
| 279 | - } | |
| 280 | -}; | |
| 281 | - | |
| 282 | -BR_REGISTER(Transform, MAddTransform) | |
| 283 | - | |
| 284 | -/*! | |
| 285 | - * \ingroup transforms | |
| 286 | - * \brief Computes the absolute value of each element. | |
| 287 | - * \author Josh Klontz \cite jklontz | |
| 288 | - */ | |
| 289 | -class AbsTransform : public UntrainableTransform | |
| 290 | -{ | |
| 291 | - Q_OBJECT | |
| 292 | - | |
| 293 | - void project(const Template &src, Template &dst) const | |
| 294 | - { | |
| 295 | - dst = abs(src); | |
| 296 | - } | |
| 297 | -}; | |
| 298 | - | |
| 299 | -BR_REGISTER(Transform, AbsTransform) | |
| 300 | - | |
| 301 | -} // namespace br | |
| 302 | - | |
| 303 | -#include "cvt.moc" |
openbr/plugins/distance.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | - * Copyright 2012 The MITRE Corporation * | |
| 3 | - * * | |
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | - * you may not use this file except in compliance with the License. * | |
| 6 | - * You may obtain a copy of the License at * | |
| 7 | - * * | |
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | - * * | |
| 10 | - * Unless required by applicable law or agreed to in writing, software * | |
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | - * See the License for the specific language governing permissions and * | |
| 14 | - * limitations under the License. * | |
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | - | |
| 17 | -#include <QFutureSynchronizer> | |
| 18 | -#include <QtConcurrentRun> | |
| 19 | -#include <numeric> | |
| 20 | -#include <opencv2/imgproc/imgproc.hpp> | |
| 21 | -#include <opencv2/imgproc/imgproc_c.h> | |
| 22 | -#include "openbr_internal.h" | |
| 23 | - | |
| 24 | -#include "openbr/core/distance_sse.h" | |
| 25 | -#include "openbr/core/qtutils.h" | |
| 26 | -#include "openbr/core/opencvutils.h" | |
| 27 | - | |
| 28 | -using namespace cv; | |
| 29 | - | |
| 30 | -namespace br | |
| 31 | -{ | |
| 32 | - | |
| 33 | -/*! | |
| 34 | - * \ingroup distances | |
| 35 | - * \brief Standard distance metrics | |
| 36 | - * \author Josh Klontz \cite jklontz | |
| 37 | - */ | |
| 38 | -class DistDistance : public UntrainableDistance | |
| 39 | -{ | |
| 40 | - Q_OBJECT | |
| 41 | - Q_ENUMS(Metric) | |
| 42 | - Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) | |
| 43 | - Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false) | |
| 44 | - | |
| 45 | -public: | |
| 46 | - /*!< */ | |
| 47 | - enum Metric { Correlation, | |
| 48 | - ChiSquared, | |
| 49 | - Intersection, | |
| 50 | - Bhattacharyya, | |
| 51 | - INF, | |
| 52 | - L1, | |
| 53 | - L2, | |
| 54 | - Cosine, | |
| 55 | - Dot}; | |
| 56 | - | |
| 57 | -private: | |
| 58 | - BR_PROPERTY(Metric, metric, L2) | |
| 59 | - BR_PROPERTY(bool, negLogPlusOne, true) | |
| 60 | - | |
| 61 | - float compare(const Mat &a, const Mat &b) const | |
| 62 | - { | |
| 63 | - if ((a.size != b.size) || | |
| 64 | - (a.type() != b.type())) | |
| 65 | - return -std::numeric_limits<float>::max(); | |
| 66 | - | |
| 67 | -// TODO: this max value is never returned based on the switch / default | |
| 68 | - float result = std::numeric_limits<float>::max(); | |
| 69 | - switch (metric) { | |
| 70 | - case Correlation: | |
| 71 | - return compareHist(a, b, CV_COMP_CORREL); | |
| 72 | - case ChiSquared: | |
| 73 | - result = compareHist(a, b, CV_COMP_CHISQR); | |
| 74 | - break; | |
| 75 | - case Intersection: | |
| 76 | - result = compareHist(a, b, CV_COMP_INTERSECT); | |
| 77 | - break; | |
| 78 | - case Bhattacharyya: | |
| 79 | - result = compareHist(a, b, CV_COMP_BHATTACHARYYA); | |
| 80 | - break; | |
| 81 | - case INF: | |
| 82 | - result = norm(a, b, NORM_INF); | |
| 83 | - break; | |
| 84 | - case L1: | |
| 85 | - result = norm(a, b, NORM_L1); | |
| 86 | - break; | |
| 87 | - case L2: | |
| 88 | - result = norm(a, b, NORM_L2); | |
| 89 | - break; | |
| 90 | - case Cosine: | |
| 91 | - return cosine(a, b); | |
| 92 | - case Dot: | |
| 93 | - return a.dot(b); | |
| 94 | - default: | |
| 95 | - qFatal("Invalid metric"); | |
| 96 | - } | |
| 97 | - | |
| 98 | - if (result != result) | |
| 99 | - qFatal("NaN result."); | |
| 100 | - | |
| 101 | - return negLogPlusOne ? -log(result+1) : result; | |
| 102 | - } | |
| 103 | - | |
| 104 | - static float cosine(const Mat &a, const Mat &b) | |
| 105 | - { | |
| 106 | - float dot = 0; | |
| 107 | - float magA = 0; | |
| 108 | - float magB = 0; | |
| 109 | - | |
| 110 | - for (int row=0; row<a.rows; row++) { | |
| 111 | - for (int col=0; col<a.cols; col++) { | |
| 112 | - const float target = a.at<float>(row,col); | |
| 113 | - const float query = b.at<float>(row,col); | |
| 114 | - dot += target * query; | |
| 115 | - magA += target * target; | |
| 116 | - magB += query * query; | |
| 117 | - } | |
| 118 | - } | |
| 119 | - | |
| 120 | - return dot / (sqrt(magA)*sqrt(magB)); | |
| 121 | - } | |
| 122 | -}; | |
| 123 | - | |
| 124 | -BR_REGISTER(Distance, DistDistance) | |
| 125 | - | |
| 126 | -/*! | |
| 127 | - * \ingroup distances | |
| 128 | - * \brief DistDistance wrapper. | |
| 129 | - * \author Josh Klontz \cite jklontz | |
| 130 | - */ | |
| 131 | -class DefaultDistance : public UntrainableDistance | |
| 132 | -{ | |
| 133 | - Q_OBJECT | |
| 134 | - Distance *distance; | |
| 135 | - | |
| 136 | - void init() | |
| 137 | - { | |
| 138 | - distance = Distance::make("Dist("+file.suffix()+")"); | |
| 139 | - } | |
| 140 | - | |
| 141 | - float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 142 | - { | |
| 143 | - return distance->compare(a, b); | |
| 144 | - } | |
| 145 | -}; | |
| 146 | - | |
| 147 | -BR_REGISTER(Distance, DefaultDistance) | |
| 148 | - | |
| 149 | -/*! | |
| 150 | - * \ingroup distances | |
| 151 | - * \brief Distances in series. | |
| 152 | - * \author Josh Klontz \cite jklontz | |
| 153 | - * | |
| 154 | - * The templates are compared using each br::Distance in order. | |
| 155 | - * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early. | |
| 156 | - * Otherwise the returned result is the value of comparing the templates using the last br::Distance. | |
| 157 | - */ | |
| 158 | -class PipeDistance : public Distance | |
| 159 | -{ | |
| 160 | - Q_OBJECT | |
| 161 | - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | |
| 162 | - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | |
| 163 | - | |
| 164 | - void train(const TemplateList &data) | |
| 165 | - { | |
| 166 | - QFutureSynchronizer<void> futures; | |
| 167 | - foreach (br::Distance *distance, distances) | |
| 168 | - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 169 | - futures.waitForFinished(); | |
| 170 | - } | |
| 171 | - | |
| 172 | - float compare(const Template &a, const Template &b) const | |
| 173 | - { | |
| 174 | - float result = -std::numeric_limits<float>::max(); | |
| 175 | - foreach (br::Distance *distance, distances) { | |
| 176 | - result = distance->compare(a, b); | |
| 177 | - if (result == -std::numeric_limits<float>::max()) | |
| 178 | - return result; | |
| 179 | - } | |
| 180 | - return result; | |
| 181 | - } | |
| 182 | -}; | |
| 183 | - | |
| 184 | -BR_REGISTER(Distance, PipeDistance) | |
| 185 | - | |
| 186 | -/*! | |
| 187 | - * \ingroup distances | |
| 188 | - * \brief Fuses similarity scores across multiple matrices of compared templates | |
| 189 | - * \author Scott Klum \cite sklum | |
| 190 | - * \note Operation: Mean, sum, min, max are supported. | |
| 191 | - */ | |
| 192 | -class FuseDistance : public Distance | |
| 193 | -{ | |
| 194 | - Q_OBJECT | |
| 195 | - Q_ENUMS(Operation) | |
| 196 | - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | |
| 197 | - Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) | |
| 198 | - Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | |
| 199 | - | |
| 200 | - QList<br::Distance*> distances; | |
| 201 | - | |
| 202 | -public: | |
| 203 | - /*!< */ | |
| 204 | - enum Operation {Mean, Sum, Max, Min}; | |
| 205 | - | |
| 206 | -private: | |
| 207 | - BR_PROPERTY(QString, description, "L2") | |
| 208 | - BR_PROPERTY(Operation, operation, Mean) | |
| 209 | - BR_PROPERTY(QList<float>, weights, QList<float>()) | |
| 210 | - | |
| 211 | - void train(const TemplateList &src) | |
| 212 | - { | |
| 213 | - // Partition the templates by matrix | |
| 214 | - QList<int> split; | |
| 215 | - for (int i=0; i<src.at(0).size(); i++) split.append(1); | |
| 216 | - | |
| 217 | - QList<TemplateList> partitionedSrc = src.partition(split); | |
| 218 | - | |
| 219 | - while (distances.size() < partitionedSrc.size()) | |
| 220 | - distances.append(make(description)); | |
| 221 | - | |
| 222 | - // Train on each of the partitions | |
| 223 | - for (int i=0; i<distances.size(); i++) | |
| 224 | - distances[i]->train(partitionedSrc[i]); | |
| 225 | - } | |
| 226 | - | |
| 227 | - float compare(const Template &a, const Template &b) const | |
| 228 | - { | |
| 229 | - if (a.size() != b.size()) qFatal("Comparison size mismatch"); | |
| 230 | - | |
| 231 | - QList<float> scores; | |
| 232 | - for (int i=0; i<distances.size(); i++) { | |
| 233 | - float weight; | |
| 234 | - weights.isEmpty() ? weight = 1. : weight = weights[i]; | |
| 235 | - scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i]))); | |
| 236 | - } | |
| 237 | - | |
| 238 | - switch (operation) { | |
| 239 | - case Mean: | |
| 240 | - return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size(); | |
| 241 | - break; | |
| 242 | - case Sum: | |
| 243 | - return std::accumulate(scores.begin(),scores.end(),0.0); | |
| 244 | - break; | |
| 245 | - case Min: | |
| 246 | - return *std::min_element(scores.begin(),scores.end()); | |
| 247 | - break; | |
| 248 | - case Max: | |
| 249 | - return *std::max_element(scores.begin(),scores.end()); | |
| 250 | - break; | |
| 251 | - default: | |
| 252 | - qFatal("Invalid operation."); | |
| 253 | - } | |
| 254 | - return 0; | |
| 255 | - } | |
| 256 | - | |
| 257 | - void store(QDataStream &stream) const | |
| 258 | - { | |
| 259 | - stream << distances.size(); | |
| 260 | - foreach (Distance *distance, distances) | |
| 261 | - distance->store(stream); | |
| 262 | - } | |
| 263 | - | |
| 264 | - void load(QDataStream &stream) | |
| 265 | - { | |
| 266 | - int numDistances; | |
| 267 | - stream >> numDistances; | |
| 268 | - while (distances.size() < numDistances) | |
| 269 | - distances.append(make(description)); | |
| 270 | - foreach (Distance *distance, distances) | |
| 271 | - distance->load(stream); | |
| 272 | - } | |
| 273 | -}; | |
| 274 | - | |
| 275 | -BR_REGISTER(Distance, FuseDistance) | |
| 276 | - | |
| 277 | -/*! | |
| 278 | - * \ingroup distances | |
| 279 | - * \brief Fast 8-bit L1 distance | |
| 280 | - * \author Josh Klontz \cite jklontz | |
| 281 | - */ | |
| 282 | -class ByteL1Distance : public UntrainableDistance | |
| 283 | -{ | |
| 284 | - Q_OBJECT | |
| 285 | - | |
| 286 | - float compare(const unsigned char *a, const unsigned char *b, size_t size) const | |
| 287 | - { | |
| 288 | - return l1(a, b, size); | |
| 289 | - } | |
| 290 | -}; | |
| 291 | - | |
| 292 | -BR_REGISTER(Distance, ByteL1Distance) | |
| 293 | - | |
| 294 | -/*! | |
| 295 | - * \ingroup distances | |
| 296 | - * \brief Fast 4-bit L1 distance | |
| 297 | - * \author Josh Klontz \cite jklontz | |
| 298 | - */ | |
| 299 | -class HalfByteL1Distance : public UntrainableDistance | |
| 300 | -{ | |
| 301 | - Q_OBJECT | |
| 302 | - | |
| 303 | - float compare(const Mat &a, const Mat &b) const | |
| 304 | - { | |
| 305 | - return packed_l1(a.data, b.data, a.total()); | |
| 306 | - } | |
| 307 | -}; | |
| 308 | - | |
| 309 | -BR_REGISTER(Distance, HalfByteL1Distance) | |
| 310 | - | |
| 311 | -/*! | |
| 312 | - * \ingroup distances | |
| 313 | - * \brief Returns -log(distance(a,b)+1) | |
| 314 | - * \author Josh Klontz \cite jklontz | |
| 315 | - */ | |
| 316 | -class NegativeLogPlusOneDistance : public UntrainableDistance | |
| 317 | -{ | |
| 318 | - Q_OBJECT | |
| 319 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 320 | - BR_PROPERTY(br::Distance*, distance, NULL) | |
| 321 | - | |
| 322 | - void train(const TemplateList &src) | |
| 323 | - { | |
| 324 | - distance->train(src); | |
| 325 | - } | |
| 326 | - | |
| 327 | - float compare(const Template &a, const Template &b) const | |
| 328 | - { | |
| 329 | - return -log(distance->compare(a,b)+1); | |
| 330 | - } | |
| 331 | - | |
| 332 | - void store(QDataStream &stream) const | |
| 333 | - { | |
| 334 | - distance->store(stream); | |
| 335 | - } | |
| 336 | - | |
| 337 | - void load(QDataStream &stream) | |
| 338 | - { | |
| 339 | - distance->load(stream); | |
| 340 | - } | |
| 341 | -}; | |
| 342 | - | |
| 343 | -BR_REGISTER(Distance, NegativeLogPlusOneDistance) | |
| 344 | - | |
| 345 | -/*! | |
| 346 | - * \ingroup distances | |
| 347 | - * \brief Returns \c true if the templates are identical, \c false otherwise. | |
| 348 | - * \author Josh Klontz \cite jklontz | |
| 349 | - */ | |
| 350 | -class IdenticalDistance : public UntrainableDistance | |
| 351 | -{ | |
| 352 | - Q_OBJECT | |
| 353 | - | |
| 354 | - float compare(const Mat &a, const Mat &b) const | |
| 355 | - { | |
| 356 | - const size_t size = a.total() * a.elemSize(); | |
| 357 | - if (size != b.total() * b.elemSize()) return 0; | |
| 358 | - for (size_t i=0; i<size; i++) | |
| 359 | - if (a.data[i] != b.data[i]) return 0; | |
| 360 | - return 1; | |
| 361 | - } | |
| 362 | -}; | |
| 363 | - | |
| 364 | -BR_REGISTER(Distance, IdenticalDistance) | |
| 365 | - | |
| 366 | -/*! | |
| 367 | - * \ingroup distances | |
| 368 | - * \brief Online distance metric to attenuate match scores across multiple frames | |
| 369 | - * \author Brendan klare \cite bklare | |
| 370 | - */ | |
| 371 | -class OnlineDistance : public UntrainableDistance | |
| 372 | -{ | |
| 373 | - Q_OBJECT | |
| 374 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 375 | - Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | |
| 376 | - BR_PROPERTY(br::Distance*, distance, NULL) | |
| 377 | - BR_PROPERTY(float, alpha, 0.1f) | |
| 378 | - | |
| 379 | - mutable QHash<QString,float> scoreHash; | |
| 380 | - mutable QMutex mutex; | |
| 381 | - | |
| 382 | - float compare(const Template &target, const Template &query) const | |
| 383 | - { | |
| 384 | - float currentScore = distance->compare(target, query); | |
| 385 | - | |
| 386 | - QMutexLocker mutexLocker(&mutex); | |
| 387 | - return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore; | |
| 388 | - } | |
| 389 | -}; | |
| 390 | - | |
| 391 | -BR_REGISTER(Distance, OnlineDistance) | |
| 392 | - | |
| 393 | -/*! | |
| 394 | - * \ingroup distances | |
| 395 | - * \brief Attenuation function based distance from attributes | |
| 396 | - * \author Scott Klum \cite sklum | |
| 397 | - */ | |
| 398 | -class AttributeDistance : public UntrainableDistance | |
| 399 | -{ | |
| 400 | - Q_OBJECT | |
| 401 | - Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | |
| 402 | - BR_PROPERTY(QString, attribute, QString()) | |
| 403 | - | |
| 404 | - float compare(const Template &target, const Template &query) const | |
| 405 | - { | |
| 406 | - float queryValue = query.file.get<float>(attribute); | |
| 407 | - float targetValue = target.file.get<float>(attribute); | |
| 408 | - | |
| 409 | - // TODO: Set this magic number to something meaningful | |
| 410 | - float stddev = 1; | |
| 411 | - | |
| 412 | - if (queryValue == targetValue) return 1; | |
| 413 | - else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | |
| 414 | - } | |
| 415 | -}; | |
| 416 | - | |
| 417 | -BR_REGISTER(Distance, AttributeDistance) | |
| 418 | - | |
| 419 | -/*! | |
| 420 | - * \ingroup distances | |
| 421 | - * \brief Sum match scores across multiple distances | |
| 422 | - * \author Scott Klum \cite sklum | |
| 423 | - */ | |
| 424 | -class SumDistance : public UntrainableDistance | |
| 425 | -{ | |
| 426 | - Q_OBJECT | |
| 427 | - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | |
| 428 | - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | |
| 429 | - | |
| 430 | - void train(const TemplateList &data) | |
| 431 | - { | |
| 432 | - QFutureSynchronizer<void> futures; | |
| 433 | - foreach (br::Distance *distance, distances) | |
| 434 | - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 435 | - futures.waitForFinished(); | |
| 436 | - } | |
| 437 | - | |
| 438 | - float compare(const Template &target, const Template &query) const | |
| 439 | - { | |
| 440 | - float result = 0; | |
| 441 | - | |
| 442 | - foreach (br::Distance *distance, distances) { | |
| 443 | - result += distance->compare(target, query); | |
| 444 | - | |
| 445 | - if (result == -std::numeric_limits<float>::max()) | |
| 446 | - return result; | |
| 447 | - } | |
| 448 | - | |
| 449 | - return result; | |
| 450 | - } | |
| 451 | -}; | |
| 452 | - | |
| 453 | -BR_REGISTER(Distance, SumDistance) | |
| 454 | - | |
| 455 | -/*! | |
| 456 | - * \ingroup transforms | |
| 457 | - * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance. | |
| 458 | - * dst will contain a 1 by n vector of scores. | |
| 459 | - * \author Charles Otto \cite caotto | |
| 460 | - */ | |
| 461 | -class GalleryCompareTransform : public Transform | |
| 462 | -{ | |
| 463 | - Q_OBJECT | |
| 464 | - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true) | |
| 465 | - Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) | |
| 466 | - BR_PROPERTY(br::Distance*, distance, NULL) | |
| 467 | - BR_PROPERTY(QString, galleryName, "") | |
| 468 | - | |
| 469 | - TemplateList gallery; | |
| 470 | - | |
| 471 | - void project(const Template &src, Template &dst) const | |
| 472 | - { | |
| 473 | - dst = src; | |
| 474 | - if (gallery.isEmpty()) | |
| 475 | - return; | |
| 476 | - | |
| 477 | - QList<float> line = distance->compare(gallery, src); | |
| 478 | - dst.m() = OpenCVUtils::toMat(line, 1); | |
| 479 | - } | |
| 480 | - | |
| 481 | - void init() | |
| 482 | - { | |
| 483 | - if (!galleryName.isEmpty()) | |
| 484 | - gallery = TemplateList::fromGallery(galleryName); | |
| 485 | - } | |
| 486 | - | |
| 487 | - void train(const TemplateList &data) | |
| 488 | - { | |
| 489 | - gallery = data; | |
| 490 | - } | |
| 491 | - | |
| 492 | - void store(QDataStream &stream) const | |
| 493 | - { | |
| 494 | - br::Object::store(stream); | |
| 495 | - stream << gallery; | |
| 496 | - } | |
| 497 | - | |
| 498 | - void load(QDataStream &stream) | |
| 499 | - { | |
| 500 | - br::Object::load(stream); | |
| 501 | - stream >> gallery; | |
| 502 | - } | |
| 503 | - | |
| 504 | -public: | |
| 505 | - GalleryCompareTransform() : Transform(false, true) {} | |
| 506 | -}; | |
| 507 | - | |
| 508 | -BR_REGISTER(Transform, GalleryCompareTransform) | |
| 509 | - | |
| 510 | - | |
| 511 | -} // namespace br | |
| 512 | -#include "distance.moc" |
openbr/plugins/distance/L1.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <Eigen/Dense> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief L1 distance computed using eigen. | |
| 27 | + * \author Josh Klontz \cite jklontz | |
| 28 | + */ | |
| 29 | +class L1Distance : public UntrainableDistance | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + | |
| 33 | + float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 34 | + { | |
| 35 | + const int size = a.rows * a.cols; | |
| 36 | + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | |
| 37 | + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | |
| 38 | + return (aMap-bMap).cwiseAbs().sum(); | |
| 39 | + } | |
| 40 | +}; | |
| 41 | + | |
| 42 | +BR_REGISTER(Distance, L1Distance) | |
| 43 | + | |
| 44 | +} // namespace br | |
| 45 | + | |
| 46 | +#include "distance/L1.moc" | ... | ... |
openbr/plugins/distance/L2.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <Eigen/Dense> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief L2 distance computed using eigen. | |
| 27 | + * \author Josh Klontz \cite jklontz | |
| 28 | + */ | |
| 29 | +class L2Distance : public UntrainableDistance | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + | |
| 33 | + float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 34 | + { | |
| 35 | + const int size = a.rows * a.cols; | |
| 36 | + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | |
| 37 | + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | |
| 38 | + return (aMap-bMap).squaredNorm(); | |
| 39 | + } | |
| 40 | +}; | |
| 41 | + | |
| 42 | +BR_REGISTER(Distance, L2Distance) | |
| 43 | + | |
| 44 | +} // namespace br | |
| 45 | + | |
| 46 | +#include "distance/L2.moc" | ... | ... |
openbr/plugins/distance/attribute.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Attenuation function based distance from attributes | |
| 25 | + * \author Scott Klum \cite sklum | |
| 26 | + */ | |
| 27 | +class AttributeDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | |
| 31 | + BR_PROPERTY(QString, attribute, QString()) | |
| 32 | + | |
| 33 | + float compare(const Template &target, const Template &query) const | |
| 34 | + { | |
| 35 | + float queryValue = query.file.get<float>(attribute); | |
| 36 | + float targetValue = target.file.get<float>(attribute); | |
| 37 | + | |
| 38 | + // TODO: Set this magic number to something meaningful | |
| 39 | + float stddev = 1; | |
| 40 | + | |
| 41 | + if (queryValue == targetValue) return 1; | |
| 42 | + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | |
| 43 | + } | |
| 44 | +}; | |
| 45 | + | |
| 46 | +BR_REGISTER(Distance, AttributeDistance) | |
| 47 | + | |
| 48 | +} // namespace br | |
| 49 | + | |
| 50 | +#include "distance/attribute.moc" | ... | ... |
openbr/plugins/distance/bayesianquantization.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/opencvutils.h> | |
| 21 | + | |
| 22 | +using namespace cv; | |
| 23 | + | |
| 24 | +namespace br | |
| 25 | +{ | |
| 26 | + | |
| 27 | +/*! | |
| 28 | + * \ingroup distances | |
| 29 | + * \brief Bayesian quantization distance | |
| 30 | + * \author Josh Klontz \cite jklontz | |
| 31 | + */ | |
| 32 | +class BayesianQuantizationDistance : public Distance | |
| 33 | +{ | |
| 34 | + Q_OBJECT | |
| 35 | + | |
| 36 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 37 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 38 | + | |
| 39 | + QVector<float> loglikelihoods; | |
| 40 | + | |
| 41 | + static void computeLogLikelihood(const Mat &data, const QList<int> &labels, float *loglikelihood) | |
| 42 | + { | |
| 43 | + const QList<uchar> vals = OpenCVUtils::matrixToVector<uchar>(data); | |
| 44 | + if (vals.size() != labels.size()) | |
| 45 | + qFatal("Logic error."); | |
| 46 | + | |
| 47 | + QVector<quint64> genuines(256, 0), impostors(256,0); | |
| 48 | + for (int i=0; i<vals.size(); i++) | |
| 49 | + for (int j=i+1; j<vals.size(); j++) | |
| 50 | + if (labels[i] == labels[j]) genuines[abs(vals[i]-vals[j])]++; | |
| 51 | + else impostors[abs(vals[i]-vals[j])]++; | |
| 52 | + | |
| 53 | + quint64 totalGenuines(0), totalImpostors(0); | |
| 54 | + for (int i=0; i<256; i++) { | |
| 55 | + totalGenuines += genuines[i]; | |
| 56 | + totalImpostors += impostors[i]; | |
| 57 | + } | |
| 58 | + | |
| 59 | + for (int i=0; i<256; i++) | |
| 60 | + loglikelihood[i] = log((float(genuines[i]+1)/totalGenuines)/(float(impostors[i]+1)/totalImpostors)); | |
| 61 | + } | |
| 62 | + | |
| 63 | + void train(const TemplateList &src) | |
| 64 | + { | |
| 65 | + if ((src.first().size() > 1) || (src.first().m().type() != CV_8UC1)) | |
| 66 | + qFatal("Expected sigle matrix templates of type CV_8UC1!"); | |
| 67 | + | |
| 68 | + const Mat data = OpenCVUtils::toMat(src.data()); | |
| 69 | + const QList<int> templateLabels = src.indexProperty(inputVariable); | |
| 70 | + loglikelihoods = QVector<float>(data.cols*256, 0); | |
| 71 | + | |
| 72 | + QFutureSynchronizer<void> futures; | |
| 73 | + for (int i=0; i<data.cols; i++) | |
| 74 | + futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256])); | |
| 75 | + futures.waitForFinished(); | |
| 76 | + } | |
| 77 | + | |
| 78 | + float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 79 | + { | |
| 80 | + const uchar *aData = a.data; | |
| 81 | + const uchar *bData = b.data; | |
| 82 | + const int size = a.rows * a.cols; | |
| 83 | + float likelihood = 0; | |
| 84 | + for (int i=0; i<size; i++) | |
| 85 | + likelihood += loglikelihoods[i*256+abs(aData[i]-bData[i])]; | |
| 86 | + return likelihood; | |
| 87 | + } | |
| 88 | + | |
| 89 | + void store(QDataStream &stream) const | |
| 90 | + { | |
| 91 | + stream << loglikelihoods; | |
| 92 | + } | |
| 93 | + | |
| 94 | + void load(QDataStream &stream) | |
| 95 | + { | |
| 96 | + stream >> loglikelihoods; | |
| 97 | + } | |
| 98 | +}; | |
| 99 | + | |
| 100 | +BR_REGISTER(Distance, BayesianQuantizationDistance) | |
| 101 | + | |
| 102 | +} // namespace br | |
| 103 | + | |
| 104 | +#include "distance/bayesianquantization.moc" | ... | ... |
openbr/plugins/distance/byteL1.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/distance_sse.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup distances | |
| 25 | + * \brief Fast 8-bit L1 distance | |
| 26 | + * \author Josh Klontz \cite jklontz | |
| 27 | + */ | |
| 28 | +class ByteL1Distance : public UntrainableDistance | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + float compare(const unsigned char *a, const unsigned char *b, size_t size) const | |
| 33 | + { | |
| 34 | + return l1(a, b, size); | |
| 35 | + } | |
| 36 | +}; | |
| 37 | + | |
| 38 | +BR_REGISTER(Distance, ByteL1Distance) | |
| 39 | + | |
| 40 | +} // namespace br | |
| 41 | + | |
| 42 | +#include "distance/byteL1.moc" | ... | ... |
openbr/plugins/distance/crossvalidate.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Cross validate a distance metric. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class CrossValidateDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + float compare(const Template &a, const Template &b) const | |
| 32 | + { | |
| 33 | + static const QString key("Partition"); // More efficient to preallocate this | |
| 34 | + const int partitionA = a.file.get<int>(key, 0); | |
| 35 | + const int partitionB = b.file.get<int>(key, 0); | |
| 36 | + return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0; | |
| 37 | + } | |
| 38 | +}; | |
| 39 | + | |
| 40 | +BR_REGISTER(Distance, CrossValidateDistance) | |
| 41 | + | |
| 42 | +} // namespace br | |
| 43 | + | |
| 44 | +#include "distance/crossvalidate.moc" | ... | ... |
openbr/plugins/distance/default.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief DistDistance wrapper. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class DefaultDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Distance *distance; | |
| 31 | + | |
| 32 | + void init() | |
| 33 | + { | |
| 34 | + distance = Distance::make("Dist("+file.suffix()+")"); | |
| 35 | + } | |
| 36 | + | |
| 37 | + float compare(const cv::Mat &a, const cv::Mat &b) const | |
| 38 | + { | |
| 39 | + return distance->compare(a, b); | |
| 40 | + } | |
| 41 | +}; | |
| 42 | + | |
| 43 | +BR_REGISTER(Distance, DefaultDistance) | |
| 44 | + | |
| 45 | +} // namespace br | |
| 46 | + | |
| 47 | +#include "distance/default.moc" | ... | ... |
openbr/plugins/distance/dist.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <opencv2/imgproc/imgproc.hpp> | |
| 18 | +#include <openbr/plugins/openbr_internal.h> | |
| 19 | + | |
| 20 | +using namespace cv; | |
| 21 | + | |
| 22 | +namespace br | |
| 23 | +{ | |
| 24 | + | |
| 25 | +/*! | |
| 26 | + * \ingroup distances | |
| 27 | + * \brief Standard distance metrics | |
| 28 | + * \author Josh Klontz \cite jklontz | |
| 29 | + */ | |
| 30 | +class DistDistance : public UntrainableDistance | |
| 31 | +{ | |
| 32 | + Q_OBJECT | |
| 33 | + Q_ENUMS(Metric) | |
| 34 | + Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) | |
| 35 | + Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false) | |
| 36 | + | |
| 37 | +public: | |
| 38 | + /*!< */ | |
| 39 | + enum Metric { Correlation, | |
| 40 | + ChiSquared, | |
| 41 | + Intersection, | |
| 42 | + Bhattacharyya, | |
| 43 | + INF, | |
| 44 | + L1, | |
| 45 | + L2, | |
| 46 | + Cosine, | |
| 47 | + Dot}; | |
| 48 | + | |
| 49 | +private: | |
| 50 | + BR_PROPERTY(Metric, metric, L2) | |
| 51 | + BR_PROPERTY(bool, negLogPlusOne, true) | |
| 52 | + | |
| 53 | + float compare(const Mat &a, const Mat &b) const | |
| 54 | + { | |
| 55 | + if ((a.size != b.size) || | |
| 56 | + (a.type() != b.type())) | |
| 57 | + return -std::numeric_limits<float>::max(); | |
| 58 | + | |
| 59 | +// TODO: this max value is never returned based on the switch / default | |
| 60 | + float result = std::numeric_limits<float>::max(); | |
| 61 | + switch (metric) { | |
| 62 | + case Correlation: | |
| 63 | + return compareHist(a, b, CV_COMP_CORREL); | |
| 64 | + case ChiSquared: | |
| 65 | + result = compareHist(a, b, CV_COMP_CHISQR); | |
| 66 | + break; | |
| 67 | + case Intersection: | |
| 68 | + result = compareHist(a, b, CV_COMP_INTERSECT); | |
| 69 | + break; | |
| 70 | + case Bhattacharyya: | |
| 71 | + result = compareHist(a, b, CV_COMP_BHATTACHARYYA); | |
| 72 | + break; | |
| 73 | + case INF: | |
| 74 | + result = norm(a, b, NORM_INF); | |
| 75 | + break; | |
| 76 | + case L1: | |
| 77 | + result = norm(a, b, NORM_L1); | |
| 78 | + break; | |
| 79 | + case L2: | |
| 80 | + result = norm(a, b, NORM_L2); | |
| 81 | + break; | |
| 82 | + case Cosine: | |
| 83 | + return cosine(a, b); | |
| 84 | + case Dot: | |
| 85 | + return a.dot(b); | |
| 86 | + default: | |
| 87 | + qFatal("Invalid metric"); | |
| 88 | + } | |
| 89 | + | |
| 90 | + if (result != result) | |
| 91 | + qFatal("NaN result."); | |
| 92 | + | |
| 93 | + return negLogPlusOne ? -log(result+1) : result; | |
| 94 | + } | |
| 95 | + | |
| 96 | + static float cosine(const Mat &a, const Mat &b) | |
| 97 | + { | |
| 98 | + float dot = 0; | |
| 99 | + float magA = 0; | |
| 100 | + float magB = 0; | |
| 101 | + | |
| 102 | + for (int row=0; row<a.rows; row++) { | |
| 103 | + for (int col=0; col<a.cols; col++) { | |
| 104 | + const float target = a.at<float>(row,col); | |
| 105 | + const float query = b.at<float>(row,col); | |
| 106 | + dot += target * query; | |
| 107 | + magA += target * target; | |
| 108 | + magB += query * query; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + return dot / (sqrt(magA)*sqrt(magB)); | |
| 113 | + } | |
| 114 | +}; | |
| 115 | + | |
| 116 | +BR_REGISTER(Distance, DistDistance) | |
| 117 | + | |
| 118 | +} // namespace br | |
| 119 | + | |
| 120 | +#include "distance/dist.moc" | ... | ... |
openbr/plugins/distance/filter.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Checks target metadata against filters. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class FilterDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + float compare(const Template &a, const Template &b) const | |
| 32 | + { | |
| 33 | + (void) b; // Query template isn't checked | |
| 34 | + foreach (const QString &key, Globals->filters.keys()) { | |
| 35 | + bool keep = false; | |
| 36 | + const QString metadata = a.file.get<QString>(key, ""); | |
| 37 | + if (Globals->filters[key].isEmpty()) continue; | |
| 38 | + if (metadata.isEmpty()) return -std::numeric_limits<float>::max(); | |
| 39 | + foreach (const QString &value, Globals->filters[key]) { | |
| 40 | + if (metadata == value) { | |
| 41 | + keep = true; | |
| 42 | + break; | |
| 43 | + } | |
| 44 | + } | |
| 45 | + if (!keep) return -std::numeric_limits<float>::max(); | |
| 46 | + } | |
| 47 | + return 0; | |
| 48 | + } | |
| 49 | +}; | |
| 50 | + | |
| 51 | +BR_REGISTER(Distance, FilterDistance) | |
| 52 | + | |
| 53 | +} // namespace br | |
| 54 | + | |
| 55 | +#include "distance/filter.moc" | ... | ... |
openbr/plugins/distance/fuse.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <numeric> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief Fuses similarity scores across multiple matrices of compared templates | |
| 27 | + * \author Scott Klum \cite sklum | |
| 28 | + * \note Operation: Mean, sum, min, max are supported. | |
| 29 | + */ | |
| 30 | +class FuseDistance : public Distance | |
| 31 | +{ | |
| 32 | + Q_OBJECT | |
| 33 | + Q_ENUMS(Operation) | |
| 34 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | |
| 35 | + Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) | |
| 36 | + Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | |
| 37 | + | |
| 38 | + QList<br::Distance*> distances; | |
| 39 | + | |
| 40 | +public: | |
| 41 | + /*!< */ | |
| 42 | + enum Operation {Mean, Sum, Max, Min}; | |
| 43 | + | |
| 44 | +private: | |
| 45 | + BR_PROPERTY(QString, description, "L2") | |
| 46 | + BR_PROPERTY(Operation, operation, Mean) | |
| 47 | + BR_PROPERTY(QList<float>, weights, QList<float>()) | |
| 48 | + | |
| 49 | + void train(const TemplateList &src) | |
| 50 | + { | |
| 51 | + // Partition the templates by matrix | |
| 52 | + QList<int> split; | |
| 53 | + for (int i=0; i<src.at(0).size(); i++) split.append(1); | |
| 54 | + | |
| 55 | + QList<TemplateList> partitionedSrc = src.partition(split); | |
| 56 | + | |
| 57 | + while (distances.size() < partitionedSrc.size()) | |
| 58 | + distances.append(make(description)); | |
| 59 | + | |
| 60 | + // Train on each of the partitions | |
| 61 | + for (int i=0; i<distances.size(); i++) | |
| 62 | + distances[i]->train(partitionedSrc[i]); | |
| 63 | + } | |
| 64 | + | |
| 65 | + float compare(const Template &a, const Template &b) const | |
| 66 | + { | |
| 67 | + if (a.size() != b.size()) qFatal("Comparison size mismatch"); | |
| 68 | + | |
| 69 | + QList<float> scores; | |
| 70 | + for (int i=0; i<distances.size(); i++) { | |
| 71 | + float weight; | |
| 72 | + weights.isEmpty() ? weight = 1. : weight = weights[i]; | |
| 73 | + scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i]))); | |
| 74 | + } | |
| 75 | + | |
| 76 | + switch (operation) { | |
| 77 | + case Mean: | |
| 78 | + return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size(); | |
| 79 | + break; | |
| 80 | + case Sum: | |
| 81 | + return std::accumulate(scores.begin(),scores.end(),0.0); | |
| 82 | + break; | |
| 83 | + case Min: | |
| 84 | + return *std::min_element(scores.begin(),scores.end()); | |
| 85 | + break; | |
| 86 | + case Max: | |
| 87 | + return *std::max_element(scores.begin(),scores.end()); | |
| 88 | + break; | |
| 89 | + default: | |
| 90 | + qFatal("Invalid operation."); | |
| 91 | + } | |
| 92 | + return 0; | |
| 93 | + } | |
| 94 | + | |
| 95 | + void store(QDataStream &stream) const | |
| 96 | + { | |
| 97 | + stream << distances.size(); | |
| 98 | + foreach (Distance *distance, distances) | |
| 99 | + distance->store(stream); | |
| 100 | + } | |
| 101 | + | |
| 102 | + void load(QDataStream &stream) | |
| 103 | + { | |
| 104 | + int numDistances; | |
| 105 | + stream >> numDistances; | |
| 106 | + while (distances.size() < numDistances) | |
| 107 | + distances.append(make(description)); | |
| 108 | + foreach (Distance *distance, distances) | |
| 109 | + distance->load(stream); | |
| 110 | + } | |
| 111 | +}; | |
| 112 | + | |
| 113 | +BR_REGISTER(Distance, FuseDistance) | |
| 114 | + | |
| 115 | +} // namespace br | |
| 116 | + | |
| 117 | +#include "distance/fuse.moc" | ... | ... |
openbr/plugins/distance/halfbyteL1.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/distance_sse.h> | |
| 19 | + | |
| 20 | +using namespace cv; | |
| 21 | + | |
| 22 | +namespace br | |
| 23 | +{ | |
| 24 | + | |
| 25 | +/*! | |
| 26 | + * \ingroup distances | |
| 27 | + * \brief Fast 4-bit L1 distance | |
| 28 | + * \author Josh Klontz \cite jklontz | |
| 29 | + */ | |
| 30 | +class HalfByteL1Distance : public UntrainableDistance | |
| 31 | +{ | |
| 32 | + Q_OBJECT | |
| 33 | + | |
| 34 | + float compare(const Mat &a, const Mat &b) const | |
| 35 | + { | |
| 36 | + return packed_l1(a.data, b.data, a.total()); | |
| 37 | + } | |
| 38 | +}; | |
| 39 | + | |
| 40 | +BR_REGISTER(Distance, HalfByteL1Distance) | |
| 41 | + | |
| 42 | + | |
| 43 | +} // namespace br | |
| 44 | + | |
| 45 | +#include "distance/halfbyteL1.moc" | ... | ... |
openbr/plugins/distance/heatmap.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief 1v1 heat map comparison | |
| 25 | + * \author Scott Klum \cite sklum | |
| 26 | + */ | |
| 27 | +class HeatMapDistance : public Distance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | |
| 31 | + Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false) | |
| 32 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 33 | + BR_PROPERTY(QString, description, "IdenticalDistance") | |
| 34 | + BR_PROPERTY(int, step, 1) | |
| 35 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 36 | + | |
| 37 | + QList<br::Distance*> distances; | |
| 38 | + | |
| 39 | + void train(const TemplateList &src) | |
| 40 | + { | |
| 41 | + QList<TemplateList> patches; | |
| 42 | + | |
| 43 | + // Split src into list of TemplateLists of corresponding patches across all Templates | |
| 44 | + for (int i=0; i<step; i++) { | |
| 45 | + TemplateList patchBuffer; | |
| 46 | + for (int j=0; j<src.size(); j++) | |
| 47 | + patchBuffer.append(Template(src[j].file, src[j][i])); | |
| 48 | + patches.append(patchBuffer); | |
| 49 | + patchBuffer.clear(); | |
| 50 | + } | |
| 51 | + | |
| 52 | + while (distances.size() < patches.size()) | |
| 53 | + distances.append(make(description)); | |
| 54 | + | |
| 55 | + // Train on a distance for each patch | |
| 56 | + for (int i=0; i<distances.size(); i++) | |
| 57 | + distances[i]->train(patches[i]); | |
| 58 | + } | |
| 59 | + | |
| 60 | + float compare(const cv::Mat &target, const cv::Mat &query) const | |
| 61 | + { | |
| 62 | + (void) target; | |
| 63 | + (void) query; | |
| 64 | + qFatal("Heatmap Distance not compatible with Template to Template comparison."); | |
| 65 | + | |
| 66 | + return 0; | |
| 67 | + } | |
| 68 | + | |
| 69 | + void compare(const TemplateList &target, const TemplateList &query, Output *output) const | |
| 70 | + { | |
| 71 | + for (int i=0; i<target.size(); i++) { | |
| 72 | + if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches."); | |
| 73 | + for (int j=0; j<step; j++) | |
| 74 | + output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + void store(QDataStream &stream) const | |
| 79 | + { | |
| 80 | + stream << distances.size(); | |
| 81 | + foreach (Distance *distance, distances) | |
| 82 | + distance->store(stream); | |
| 83 | + } | |
| 84 | + | |
| 85 | + void load(QDataStream &stream) | |
| 86 | + { | |
| 87 | + int numDistances; | |
| 88 | + stream >> numDistances; | |
| 89 | + while (distances.size() < numDistances) | |
| 90 | + distances.append(make(description)); | |
| 91 | + foreach (Distance *distance, distances) | |
| 92 | + distance->load(stream); | |
| 93 | + } | |
| 94 | +}; | |
| 95 | + | |
| 96 | +BR_REGISTER(Distance, HeatMapDistance) | |
| 97 | + | |
| 98 | +} // namespace br | |
| 99 | + | |
| 100 | +#include "distance/heatmap.moc" | ... | ... |
openbr/plugins/distance/identical.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +using namespace cv; | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief Returns \c true if the templates are identical, \c false otherwise. | |
| 27 | + * \author Josh Klontz \cite jklontz | |
| 28 | + */ | |
| 29 | +class IdenticalDistance : public UntrainableDistance | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + | |
| 33 | + float compare(const Mat &a, const Mat &b) const | |
| 34 | + { | |
| 35 | + const size_t size = a.total() * a.elemSize(); | |
| 36 | + if (size != b.total() * b.elemSize()) return 0; | |
| 37 | + for (size_t i=0; i<size; i++) | |
| 38 | + if (a.data[i] != b.data[i]) return 0; | |
| 39 | + return 1; | |
| 40 | + } | |
| 41 | +}; | |
| 42 | + | |
| 43 | +BR_REGISTER(Distance, IdenticalDistance) | |
| 44 | + | |
| 45 | +} // namespace br | |
| 46 | + | |
| 47 | +#include "distance/identical.moc" | ... | ... |
openbr/plugins/distance/keypointmatcher.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <opencv2/features2d/features2d.hpp> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +using namespace cv; | |
| 22 | + | |
| 23 | +namespace br | |
| 24 | +{ | |
| 25 | + | |
| 26 | +/*! | |
| 27 | + * \ingroup transforms | |
| 28 | + * \brief Wraps OpenCV Key Point Matcher | |
| 29 | + * \author Josh Klontz \cite jklontz | |
| 30 | + */ | |
| 31 | +class KeyPointMatcherDistance : public UntrainableDistance | |
| 32 | +{ | |
| 33 | + Q_OBJECT | |
| 34 | + Q_PROPERTY(QString matcher READ get_matcher WRITE set_matcher RESET reset_matcher STORED false) | |
| 35 | + Q_PROPERTY(float maxRatio READ get_maxRatio WRITE set_maxRatio RESET reset_maxRatio STORED false) | |
| 36 | + BR_PROPERTY(QString, matcher, "BruteForce") | |
| 37 | + BR_PROPERTY(float, maxRatio, 0.8) | |
| 38 | + | |
| 39 | + Ptr<DescriptorMatcher> descriptorMatcher; | |
| 40 | + | |
| 41 | + void init() | |
| 42 | + { | |
| 43 | + descriptorMatcher = DescriptorMatcher::create(matcher.toStdString()); | |
| 44 | + if (descriptorMatcher.empty()) | |
| 45 | + qFatal("Failed to create DescriptorMatcher: %s", qPrintable(matcher)); | |
| 46 | + } | |
| 47 | + | |
| 48 | + float compare(const Mat &a, const Mat &b) const | |
| 49 | + { | |
| 50 | + if ((a.rows < 2) || (b.rows < 2)) return 0; | |
| 51 | + | |
| 52 | + std::vector< std::vector<DMatch> > matches; | |
| 53 | + if (a.rows < b.rows) descriptorMatcher->knnMatch(a, b, matches, 2); | |
| 54 | + else descriptorMatcher->knnMatch(b, a, matches, 2); | |
| 55 | + | |
| 56 | + QList<float> distances; | |
| 57 | + foreach (const std::vector<DMatch> &match, matches) { | |
| 58 | + if (match[0].distance / match[1].distance > maxRatio) continue; | |
| 59 | + distances.append(match[0].distance); | |
| 60 | + } | |
| 61 | + qSort(distances); | |
| 62 | + | |
| 63 | + float similarity = 0; | |
| 64 | + for (int i=0; i<distances.size(); i++) | |
| 65 | + similarity += 1.f/(1+distances[i])/(i+1); | |
| 66 | + return similarity; | |
| 67 | + } | |
| 68 | +}; | |
| 69 | + | |
| 70 | +BR_REGISTER(Distance, KeyPointMatcherDistance) | |
| 71 | + | |
| 72 | +} // namespace br | |
| 73 | + | |
| 74 | +#include "distance/keypointmatcher.moc" | ... | ... |
openbr/plugins/distance/matchprobability.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | +#include <openbr/core/common.h> | |
| 21 | + | |
| 22 | +namespace br | |
| 23 | +{ | |
| 24 | + | |
| 25 | +float KDEPointer(const QList<float> *scores, double x, double h) | |
| 26 | +{ | |
| 27 | + return Common::KernelDensityEstimation(*scores, x, h); | |
| 28 | +} | |
| 29 | + | |
| 30 | +/* Kernel Density Estimator */ | |
| 31 | +struct KDE | |
| 32 | +{ | |
| 33 | + float min, max; | |
| 34 | + double mean, stddev; | |
| 35 | + QList<float> bins; | |
| 36 | + | |
| 37 | + KDE() : min(0), max(1), mean(0), stddev(1) {} | |
| 38 | + | |
| 39 | + KDE(const QList<float> &scores, bool trainKDE) | |
| 40 | + { | |
| 41 | + Common::MinMax(scores, &min, &max); | |
| 42 | + Common::MeanStdDev(scores, &mean, &stddev); | |
| 43 | + | |
| 44 | + if (!trainKDE) | |
| 45 | + return; | |
| 46 | + | |
| 47 | + double h = Common::KernelDensityBandwidth(scores); | |
| 48 | + const int size = 255; | |
| 49 | + bins.reserve(size); | |
| 50 | + | |
| 51 | + QFutureSynchronizer<float> futures; | |
| 52 | + | |
| 53 | + for (int i=0; i < size; i++) | |
| 54 | + futures.addFuture(QtConcurrent::run(KDEPointer, &scores, min + (max-min)*i/(size-1), h)); | |
| 55 | + futures.waitForFinished(); | |
| 56 | + | |
| 57 | + foreach(const QFuture<float> & future, futures.futures()) | |
| 58 | + bins.append(future.result()); | |
| 59 | + } | |
| 60 | + | |
| 61 | + float operator()(float score, bool gaussian = true) const | |
| 62 | + { | |
| 63 | + if (gaussian) return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((score-mean)/stddev, 2)); | |
| 64 | + if (bins.empty()) | |
| 65 | + return -std::numeric_limits<float>::max(); | |
| 66 | + | |
| 67 | + if (score <= min) return bins.first(); | |
| 68 | + if (score >= max) return bins.last(); | |
| 69 | + const float x = (score-min)/(max-min)*bins.size(); | |
| 70 | + const float y1 = bins[floor(x)]; | |
| 71 | + const float y2 = bins[ceil(x)]; | |
| 72 | + return y1 + (y2-y1)*(x-floor(x)); | |
| 73 | + } | |
| 74 | +}; | |
| 75 | + | |
| 76 | +QDataStream &operator<<(QDataStream &stream, const KDE &kde) | |
| 77 | +{ | |
| 78 | + return stream << kde.min << kde.max << kde.mean << kde.stddev << kde.bins; | |
| 79 | +} | |
| 80 | + | |
| 81 | +QDataStream &operator>>(QDataStream &stream, KDE &kde) | |
| 82 | +{ | |
| 83 | + return stream >> kde.min >> kde.max >> kde.mean >> kde.stddev >> kde.bins; | |
| 84 | +} | |
| 85 | + | |
| 86 | +/* Match Probability */ | |
| 87 | +struct MP | |
| 88 | +{ | |
| 89 | + KDE genuine, impostor; | |
| 90 | + MP() {} | |
| 91 | + MP(const QList<float> &genuineScores, const QList<float> &impostorScores, bool trainKDE) | |
| 92 | + : genuine(genuineScores, trainKDE), impostor(impostorScores, trainKDE) {} | |
| 93 | + float operator()(float score, bool gaussian = true) const | |
| 94 | + { | |
| 95 | + const float g = genuine(score, gaussian); | |
| 96 | + const float s = g / (impostor(score, gaussian) + g); | |
| 97 | + return s; | |
| 98 | + } | |
| 99 | +}; | |
| 100 | + | |
| 101 | +QDataStream &operator<<(QDataStream &stream, const MP &nmp) | |
| 102 | +{ | |
| 103 | + return stream << nmp.genuine << nmp.impostor; | |
| 104 | +} | |
| 105 | + | |
| 106 | +QDataStream &operator>>(QDataStream &stream, MP &nmp) | |
| 107 | +{ | |
| 108 | + return stream >> nmp.genuine >> nmp.impostor; | |
| 109 | +} | |
| 110 | + | |
| 111 | +/*! | |
| 112 | + * \ingroup distances | |
| 113 | + * \brief Match Probability \cite klare12 | |
| 114 | + * \author Josh Klontz \cite jklontz | |
| 115 | + */ | |
| 116 | +class MatchProbabilityDistance : public Distance | |
| 117 | +{ | |
| 118 | + Q_OBJECT | |
| 119 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 120 | + Q_PROPERTY(bool gaussian READ get_gaussian WRITE set_gaussian RESET reset_gaussian STORED false) | |
| 121 | + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false) | |
| 122 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 123 | + | |
| 124 | + MP mp; | |
| 125 | + | |
| 126 | + void train(const TemplateList &src) | |
| 127 | + { | |
| 128 | + distance->train(src); | |
| 129 | + | |
| 130 | + const QList<int> labels = src.indexProperty(inputVariable); | |
| 131 | + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size()))); | |
| 132 | + distance->compare(src, src, matrixOutput.data()); | |
| 133 | + | |
| 134 | + QList<float> genuineScores, impostorScores; | |
| 135 | + genuineScores.reserve(labels.size()); | |
| 136 | + impostorScores.reserve(labels.size()*labels.size()); | |
| 137 | + for (int i=0; i<src.size(); i++) { | |
| 138 | + for (int j=0; j<i; j++) { | |
| 139 | + const float score = matrixOutput.data()->data.at<float>(i, j); | |
| 140 | + if (score == -std::numeric_limits<float>::max()) continue; | |
| 141 | + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue; | |
| 142 | + if (labels[i] == labels[j]) genuineScores.append(score); | |
| 143 | + else impostorScores.append(score); | |
| 144 | + } | |
| 145 | + } | |
| 146 | + | |
| 147 | + mp = MP(genuineScores, impostorScores, !gaussian); | |
| 148 | + } | |
| 149 | + | |
| 150 | + float compare(const Template &target, const Template &query) const | |
| 151 | + { | |
| 152 | + return normalize(distance->compare(target, query)); | |
| 153 | + } | |
| 154 | + | |
| 155 | + float compare(const cv::Mat &target, const cv::Mat &query) const | |
| 156 | + { | |
| 157 | + return normalize(distance->compare(target, query)); | |
| 158 | + } | |
| 159 | + | |
| 160 | + float compare(const uchar *a, const uchar *b, size_t size) const | |
| 161 | + { | |
| 162 | + return normalize(distance->compare(a, b, size)); | |
| 163 | + } | |
| 164 | + | |
| 165 | + float normalize(float score) const | |
| 166 | + { | |
| 167 | + if (score == -std::numeric_limits<float>::max()) return score; | |
| 168 | + if (!Globals->scoreNormalization) return -log(score+1); | |
| 169 | + return mp(score, gaussian); | |
| 170 | + } | |
| 171 | + | |
| 172 | + void store(QDataStream &stream) const | |
| 173 | + { | |
| 174 | + distance->store(stream); | |
| 175 | + stream << mp; | |
| 176 | + } | |
| 177 | + | |
| 178 | + void load(QDataStream &stream) | |
| 179 | + { | |
| 180 | + distance->load(stream); | |
| 181 | + stream >> mp; | |
| 182 | + } | |
| 183 | + | |
| 184 | +protected: | |
| 185 | + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | |
| 186 | + BR_PROPERTY(bool, gaussian, true) | |
| 187 | + BR_PROPERTY(bool, crossModality, false) | |
| 188 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 189 | +}; | |
| 190 | + | |
| 191 | +BR_REGISTER(Distance, MatchProbabilityDistance) | |
| 192 | + | |
| 193 | +} // namespace br | |
| 194 | + | |
| 195 | +#include "distance/matchprobability.moc" | ... | ... |
openbr/plugins/distance/metadata.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/qtutils.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup distances | |
| 25 | + * \brief Checks target metadata against query metadata. | |
| 26 | + * \author Scott Klum \cite sklum | |
| 27 | + */ | |
| 28 | +class MetadataDistance : public UntrainableDistance | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + | |
| 32 | + Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false) | |
| 33 | + BR_PROPERTY(QStringList, filters, QStringList()) | |
| 34 | + | |
| 35 | + float compare(const Template &a, const Template &b) const | |
| 36 | + { | |
| 37 | + foreach (const QString &key, filters) { | |
| 38 | + QString aValue = a.file.get<QString>(key, QString()); | |
| 39 | + QString bValue = b.file.get<QString>(key, QString()); | |
| 40 | + | |
| 41 | + // The query value may be a range. Let's check. | |
| 42 | + if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF())); | |
| 43 | + | |
| 44 | + if (aValue.isEmpty() || bValue.isEmpty()) continue; | |
| 45 | + | |
| 46 | + bool keep = false; | |
| 47 | + bool ok; | |
| 48 | + | |
| 49 | + QPointF range = QtUtils::toPoint(bValue,&ok); | |
| 50 | + | |
| 51 | + if (ok) /* Range */ { | |
| 52 | + int value = range.x(); | |
| 53 | + int upperBound = range.y(); | |
| 54 | + | |
| 55 | + while (value <= upperBound) { | |
| 56 | + if (aValue == QString::number(value)) { | |
| 57 | + keep = true; | |
| 58 | + break; | |
| 59 | + } | |
| 60 | + value++; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + else if (aValue == bValue) keep = true; | |
| 64 | + | |
| 65 | + if (!keep) return -std::numeric_limits<float>::max(); | |
| 66 | + } | |
| 67 | + return 0; | |
| 68 | + } | |
| 69 | +}; | |
| 70 | + | |
| 71 | + | |
| 72 | +BR_REGISTER(Distance, MetadataDistance) | |
| 73 | + | |
| 74 | +} // namespace br | |
| 75 | + | |
| 76 | +#include "distance/metadata.moc" | ... | ... |
openbr/plugins/distance/neglogplusone.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Returns -log(distance(a,b)+1) | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class NegativeLogPlusOneDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 31 | + BR_PROPERTY(br::Distance*, distance, NULL) | |
| 32 | + | |
| 33 | + void train(const TemplateList &src) | |
| 34 | + { | |
| 35 | + distance->train(src); | |
| 36 | + } | |
| 37 | + | |
| 38 | + float compare(const Template &a, const Template &b) const | |
| 39 | + { | |
| 40 | + return -log(distance->compare(a,b)+1); | |
| 41 | + } | |
| 42 | + | |
| 43 | + void store(QDataStream &stream) const | |
| 44 | + { | |
| 45 | + distance->store(stream); | |
| 46 | + } | |
| 47 | + | |
| 48 | + void load(QDataStream &stream) | |
| 49 | + { | |
| 50 | + distance->load(stream); | |
| 51 | + } | |
| 52 | +}; | |
| 53 | + | |
| 54 | +BR_REGISTER(Distance, NegativeLogPlusOneDistance) | |
| 55 | + | |
| 56 | +} // namespace br | |
| 57 | + | |
| 58 | +#include "distance/neglogplusone.moc" | ... | ... |
openbr/plugins/distance/online.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Online distance metric to attenuate match scores across multiple frames | |
| 25 | + * \author Brendan klare \cite bklare | |
| 26 | + */ | |
| 27 | +class OnlineDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 31 | + Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | |
| 32 | + BR_PROPERTY(br::Distance*, distance, NULL) | |
| 33 | + BR_PROPERTY(float, alpha, 0.1f) | |
| 34 | + | |
| 35 | + mutable QHash<QString,float> scoreHash; | |
| 36 | + mutable QMutex mutex; | |
| 37 | + | |
| 38 | + float compare(const Template &target, const Template &query) const | |
| 39 | + { | |
| 40 | + float currentScore = distance->compare(target, query); | |
| 41 | + | |
| 42 | + QMutexLocker mutexLocker(&mutex); | |
| 43 | + return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore; | |
| 44 | + } | |
| 45 | +}; | |
| 46 | + | |
| 47 | +BR_REGISTER(Distance, OnlineDistance) | |
| 48 | + | |
| 49 | +} // namespace br | |
| 50 | + | |
| 51 | +#include "distance/online.moc" | ... | ... |
openbr/plugins/distance/pipe.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief Distances in series. | |
| 27 | + * \author Josh Klontz \cite jklontz | |
| 28 | + * | |
| 29 | + * The templates are compared using each br::Distance in order. | |
| 30 | + * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early. | |
| 31 | + * Otherwise the returned result is the value of comparing the templates using the last br::Distance. | |
| 32 | + */ | |
| 33 | +class PipeDistance : public Distance | |
| 34 | +{ | |
| 35 | + Q_OBJECT | |
| 36 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | |
| 37 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | |
| 38 | + | |
| 39 | + void train(const TemplateList &data) | |
| 40 | + { | |
| 41 | + QFutureSynchronizer<void> futures; | |
| 42 | + foreach (br::Distance *distance, distances) | |
| 43 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 44 | + futures.waitForFinished(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + float compare(const Template &a, const Template &b) const | |
| 48 | + { | |
| 49 | + float result = -std::numeric_limits<float>::max(); | |
| 50 | + foreach (br::Distance *distance, distances) { | |
| 51 | + result = distance->compare(a, b); | |
| 52 | + if (result == -std::numeric_limits<float>::max()) | |
| 53 | + return result; | |
| 54 | + } | |
| 55 | + return result; | |
| 56 | + } | |
| 57 | +}; | |
| 58 | + | |
| 59 | +BR_REGISTER(Distance, PipeDistance) | |
| 60 | + | |
| 61 | +} // namespace br | |
| 62 | + | |
| 63 | +#include "distance/pipe.moc" | ... | ... |
openbr/plugins/distance/reject.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key. | |
| 25 | + * \author Scott Klum \cite sklum | |
| 26 | + */ | |
| 27 | +class RejectDistance : public UntrainableDistance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + | |
| 31 | + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) | |
| 32 | + BR_PROPERTY(QStringList, keys, QStringList()) | |
| 33 | + Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false) | |
| 34 | + BR_PROPERTY(bool, rejectIfContains, false) | |
| 35 | + | |
| 36 | + float compare(const Template &a, const Template &b) const | |
| 37 | + { | |
| 38 | + // We don't look at the query | |
| 39 | + (void) b; | |
| 40 | + | |
| 41 | + foreach (const QString &key, keys) | |
| 42 | + if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key))) | |
| 43 | + return -std::numeric_limits<float>::max(); | |
| 44 | + | |
| 45 | + return 0; | |
| 46 | + } | |
| 47 | +}; | |
| 48 | + | |
| 49 | + | |
| 50 | +BR_REGISTER(Distance, RejectDistance) | |
| 51 | + | |
| 52 | +} // namespace br | |
| 53 | + | |
| 54 | +#include "distance/reject.moc" | ... | ... |
openbr/plugins/distance/sum.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <QtConcurrent> | |
| 18 | + | |
| 19 | +#include <openbr/plugins/openbr_internal.h> | |
| 20 | + | |
| 21 | +namespace br | |
| 22 | +{ | |
| 23 | + | |
| 24 | +/*! | |
| 25 | + * \ingroup distances | |
| 26 | + * \brief Sum match scores across multiple distances | |
| 27 | + * \author Scott Klum \cite sklum | |
| 28 | + */ | |
| 29 | +class SumDistance : public UntrainableDistance | |
| 30 | +{ | |
| 31 | + Q_OBJECT | |
| 32 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | |
| 33 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | |
| 34 | + | |
| 35 | + void train(const TemplateList &data) | |
| 36 | + { | |
| 37 | + QFutureSynchronizer<void> futures; | |
| 38 | + foreach (br::Distance *distance, distances) | |
| 39 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 40 | + futures.waitForFinished(); | |
| 41 | + } | |
| 42 | + | |
| 43 | + float compare(const Template &target, const Template &query) const | |
| 44 | + { | |
| 45 | + float result = 0; | |
| 46 | + | |
| 47 | + foreach (br::Distance *distance, distances) { | |
| 48 | + result += distance->compare(target, query); | |
| 49 | + | |
| 50 | + if (result == -std::numeric_limits<float>::max()) | |
| 51 | + return result; | |
| 52 | + } | |
| 53 | + | |
| 54 | + return result; | |
| 55 | + } | |
| 56 | +}; | |
| 57 | + | |
| 58 | +BR_REGISTER(Distance, SumDistance) | |
| 59 | + | |
| 60 | +} // namespace br | |
| 61 | + | |
| 62 | +#include "distance/sum.moc" | ... | ... |
openbr/plugins/distance/turk.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/opencvutils.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +/*! | |
| 24 | + * \ingroup distances | |
| 25 | + * \brief Unmaps Turk HITs to be compared against query mats | |
| 26 | + * \author Scott Klum \cite sklum | |
| 27 | + */ | |
| 28 | +class TurkDistance : public UntrainableDistance | |
| 29 | +{ | |
| 30 | + Q_OBJECT | |
| 31 | + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key) | |
| 32 | + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false) | |
| 33 | + BR_PROPERTY(QString, key, QString()) | |
| 34 | + BR_PROPERTY(QStringList, values, QStringList()) | |
| 35 | + | |
| 36 | + bool targetHuman; | |
| 37 | + bool queryMachine; | |
| 38 | + | |
| 39 | + void init() | |
| 40 | + { | |
| 41 | + targetHuman = Globals->property("TurkTargetHuman").toBool(); | |
| 42 | + queryMachine = Globals->property("TurkQueryMachine").toBool(); | |
| 43 | + } | |
| 44 | + | |
| 45 | + cv::Mat getValues(const Template &t) const | |
| 46 | + { | |
| 47 | + QList<float> result; | |
| 48 | + foreach (const QString &value, values) | |
| 49 | + result.append(t.file.get<float>(key + "_" + value)); | |
| 50 | + return OpenCVUtils::toMat(result, 1); | |
| 51 | + } | |
| 52 | + | |
| 53 | + float compare(const Template &target, const Template &query) const | |
| 54 | + { | |
| 55 | + const cv::Mat a = targetHuman ? getValues(target) : target.m(); | |
| 56 | + const cv::Mat b = queryMachine ? query.m() : getValues(query); | |
| 57 | + return -norm(a, b, cv::NORM_L1); | |
| 58 | + } | |
| 59 | +}; | |
| 60 | + | |
| 61 | +BR_REGISTER(Distance, TurkDistance) | |
| 62 | + | |
| 63 | +} // namespace br | |
| 64 | + | |
| 65 | +#include "distance/turk.moc" | ... | ... |
openbr/plugins/distance/unit.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | + | |
| 19 | +namespace br | |
| 20 | +{ | |
| 21 | + | |
| 22 | +/*! | |
| 23 | + * \ingroup distances | |
| 24 | + * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1. | |
| 25 | + * \author Josh Klontz \cite jklontz | |
| 26 | + */ | |
| 27 | +class UnitDistance : public Distance | |
| 28 | +{ | |
| 29 | + Q_OBJECT | |
| 30 | + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance) | |
| 31 | + Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a) | |
| 32 | + Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b) | |
| 33 | + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | |
| 34 | + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | |
| 35 | + BR_PROPERTY(float, a, 1) | |
| 36 | + BR_PROPERTY(float, b, 0) | |
| 37 | + BR_PROPERTY(QString, inputVariable, "Label") | |
| 38 | + | |
| 39 | + void train(const TemplateList &templates) | |
| 40 | + { | |
| 41 | + const TemplateList samples = templates.mid(0, 2000); | |
| 42 | + const QList<int> sampleLabels = samples.indexProperty(inputVariable); | |
| 43 | + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(samples.size()), FileList(samples.size()))); | |
| 44 | + Distance::compare(samples, samples, matrixOutput.data()); | |
| 45 | + | |
| 46 | + double genuineAccumulator, impostorAccumulator; | |
| 47 | + int genuineCount, impostorCount; | |
| 48 | + genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0; | |
| 49 | + | |
| 50 | + for (int i=0; i<samples.size(); i++) { | |
| 51 | + for (int j=0; j<i; j++) { | |
| 52 | + const float val = matrixOutput.data()->data.at<float>(i, j); | |
| 53 | + if (sampleLabels[i] == sampleLabels[j]) { | |
| 54 | + genuineAccumulator += val; | |
| 55 | + genuineCount++; | |
| 56 | + } else { | |
| 57 | + impostorAccumulator += val; | |
| 58 | + impostorCount++; | |
| 59 | + } | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + if (genuineCount == 0) { qWarning("No genuine matches."); return; } | |
| 64 | + if (impostorCount == 0) { qWarning("No impostor matches."); return; } | |
| 65 | + | |
| 66 | + double genuineMean = genuineAccumulator / genuineCount; | |
| 67 | + double impostorMean = impostorAccumulator / impostorCount; | |
| 68 | + | |
| 69 | + if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; } | |
| 70 | + | |
| 71 | + a = 1.0/(genuineMean-impostorMean); | |
| 72 | + b = impostorMean; | |
| 73 | + | |
| 74 | + qDebug("a = %f, b = %f", a, b); | |
| 75 | + } | |
| 76 | + | |
| 77 | + float compare(const Template &target, const Template &query) const | |
| 78 | + { | |
| 79 | + return a * (distance->compare(target, query) - b); | |
| 80 | + } | |
| 81 | +}; | |
| 82 | + | |
| 83 | +BR_REGISTER(Distance, UnitDistance) | |
| 84 | + | |
| 85 | +} // namespace br | |
| 86 | + | |
| 87 | +#include "distance/unit.moc" | ... | ... |
openbr/plugins/distance/zscore.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | + * Copyright 2012 The MITRE Corporation * | |
| 3 | + * * | |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | + * you may not use this file except in compliance with the License. * | |
| 6 | + * You may obtain a copy of the License at * | |
| 7 | + * * | |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | + * * | |
| 10 | + * Unless required by applicable law or agreed to in writing, software * | |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | + * See the License for the specific language governing permissions and * | |
| 14 | + * limitations under the License. * | |
| 15 | + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | + | |
| 17 | +#include <openbr/plugins/openbr_internal.h> | |
| 18 | +#include <openbr/core/common.h> | |
| 19 | + | |
| 20 | +namespace br | |
| 21 | +{ | |
| 22 | + | |
| 23 | +class ZScoreDistance : public Distance | |
| 24 | +{ | |
| 25 | + Q_OBJECT | |
| 26 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | |
| 27 | + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false) | |
| 28 | + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | |
| 29 | + BR_PROPERTY(bool, crossModality, false) | |
| 30 | + | |
| 31 | + float min, max; | |
| 32 | + double mean, stddev; | |
| 33 | + | |
| 34 | + void train(const TemplateList &src) | |
| 35 | + { | |
| 36 | + distance->train(src); | |
| 37 | + | |
| 38 | + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size()))); | |
| 39 | + distance->compare(src, src, matrixOutput.data()); | |
| 40 | + | |
| 41 | + QList<float> scores; | |
| 42 | + scores.reserve(src.size()*src.size()); | |
| 43 | + for (int i=0; i<src.size(); i++) { | |
| 44 | + for (int j=0; j<i; j++) { | |
| 45 | + const float score = matrixOutput.data()->data.at<float>(i, j); | |
| 46 | + if (score == -std::numeric_limits<float>::max()) continue; | |
| 47 | + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue; | |
| 48 | + scores.append(score); | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 52 | + Common::MinMax(scores, &min, &max); | |
| 53 | + Common::MeanStdDev(scores, &mean, &stddev); | |
| 54 | + | |
| 55 | + if (stddev == 0) qFatal("Stddev is 0."); | |
| 56 | + } | |
| 57 | + | |
| 58 | + float compare(const Template &target, const Template &query) const | |
| 59 | + { | |
| 60 | + float score = distance->compare(target,query); | |
| 61 | + if (score == -std::numeric_limits<float>::max()) score = (min - mean) / stddev; | |
| 62 | + else if (score == std::numeric_limits<float>::max()) score = (max - mean) / stddev; | |
| 63 | + else score = (score - mean) / stddev; | |
| 64 | + return score; | |
| 65 | + } | |
| 66 | + | |
| 67 | + void store(QDataStream &stream) const | |
| 68 | + { | |
| 69 | + distance->store(stream); | |
| 70 | + stream << min << max << mean << stddev; | |
| 71 | + } | |
| 72 | + | |
| 73 | + void load(QDataStream &stream) | |
| 74 | + { | |
| 75 | + distance->load(stream); | |
| 76 | + stream >> min >> max >> mean >> stddev; | |
| 77 | + } | |
| 78 | +}; | |
| 79 | + | |
| 80 | +BR_REGISTER(Distance, ZScoreDistance) | |
| 81 | + | |
| 82 | +} // namespace br | |
| 83 | + | |
| 84 | +#include "distance/zscore.moc" | ... | ... |