Commit 2ca8d5156d59890ca49d427238ed3ce118a28bd5
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
14 changed files
with
308 additions
and
139 deletions
sdk/core/bee.cpp
| ... | ... | @@ -47,6 +47,9 @@ FileList BEE::readSigset(QString sigset, bool ignoreMetadata) |
| 47 | 47 | file.close(); |
| 48 | 48 | |
| 49 | 49 | QDomElement docElem = doc.documentElement(); |
| 50 | + if (docElem.nodeName() != "biometric-signature-set") | |
| 51 | + return fileList; | |
| 52 | + | |
| 50 | 53 | QDomNode subject = docElem.firstChild(); |
| 51 | 54 | while (!subject.isNull()) { |
| 52 | 55 | // Looping through subjects | ... | ... |
sdk/core/plot.cpp
| ... | ... | @@ -431,7 +431,7 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) |
| 431 | 431 | p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") + |
| 432 | 432 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 433 | 433 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + |
| 434 | - QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_bw()") + | |
| 434 | + QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") + | |
| 435 | 435 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 436 | 436 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 437 | 437 | QString(" + scale_x_continuous(trans=\"log10\") + scale_y_continuous(trans=\"log10\")") + |
| ... | ... | @@ -440,7 +440,7 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) |
| 440 | 440 | p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\"") + |
| 441 | 441 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 442 | 442 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + |
| 443 | - QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_bw()") + | |
| 443 | + QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + | |
| 444 | 444 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 445 | 445 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 446 | 446 | QString(" + scale_x_continuous(trans=\"log10\") + scale_y_continuous(labels=percent)") + |
| ... | ... | @@ -449,15 +449,15 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) |
| 449 | 449 | p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + |
| 450 | 450 | QString(", xlab=\"Score%1\"").arg((p.flip ? p.majorSize : p.minorSize) > 1 ? " / " + (p.flip ? p.majorHeader : p.minorHeader) : QString()) + |
| 451 | 451 | QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + |
| 452 | - QString(") + scale_fill_manual(\"Ground Truth\", values=c(\"blue\", \"red\")) + theme_bw() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + opts(axis.text.y=theme_blank(), axis.ticks=theme_blank(), axis.text.x=theme_text(angle=-90, hjust=0))") + | |
| 452 | + QString(") + scale_fill_manual(\"Ground Truth\", values=c(\"blue\", \"red\")) + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0))") + | |
| 453 | 453 | (p.majorSize > 1 ? (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg((p.flip ? p.majorHeader : p.minorHeader), (p.flip ? p.minorHeader : p.majorHeader)) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.majorHeader)) : QString()) + |
| 454 | - QString(" + opts(aspect.ratio=1)") + | |
| 454 | + QString(" + theme(aspect.ratio=1)") + | |
| 455 | 455 | QString("\nggsave(\"%1\")\n").arg(p.subfile("SD")))); |
| 456 | 456 | |
| 457 | 457 | p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"line\", xlab=\"Rank\", ylab=\"Retrieval Rate\"") + |
| 458 | 458 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 459 | 459 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + |
| 460 | - QString(") + theme_bw() + scale_x_continuous(limits = c(1,25), breaks = c(1,5,10,25))") + | |
| 460 | + QString(") + theme_minimal() + scale_x_continuous(limits = c(1,25), breaks = c(1,5,10,25))") + | |
| 461 | 461 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 462 | 462 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 463 | 463 | QString(" + scale_y_continuous(labels=percent)") + |
| ... | ... | @@ -466,28 +466,28 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) |
| 466 | 466 | p.file.write(qPrintable(QString("qplot(factor(%1), data=BC, geom=\"bar\", position=\"dodge\", weight=Y").arg(p.majorHeader) + |
| 467 | 467 | (p.majorSize > 1 ? QString(", fill=factor(%1)").arg(p.majorHeader) : QString()) + |
| 468 | 468 | QString(", xlab=\"%1False Accept Rate\"").arg(p.majorSize > 1 ? p.majorHeader + " / " : QString()) + |
| 469 | - QString(", ylab=\"True Accept Rate%1\") + theme_bw()").arg(p.minorSize > 1 ? " / " + p.minorHeader : QString()) + | |
| 469 | + QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minorSize > 1 ? " / " + p.minorHeader : QString()) + | |
| 470 | 470 | (p.majorSize > 1 ? getScale("fill", p.majorHeader, p.majorSize) : QString()) + |
| 471 | 471 | (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minorHeader) : QString(" + facet_wrap(~ X)")) + |
| 472 | - QString(" + opts(legend.position=\"none\", axis.text.x=theme_text(angle=-90, hjust=0)) + geom_text(data=BC, aes(label=Y, y=0.05))") + | |
| 472 | + QString(" + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0)) + geom_text(data=BC, aes(label=Y, y=0.05))") + | |
| 473 | 473 | QString("\nggsave(\"%1\")\n").arg(p.subfile("BC")))); |
| 474 | 474 | |
| 475 | 475 | p.file.write(qPrintable(QString("qplot(X, Y, data=FAR, geom=\"line\"") + |
| 476 | 476 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) + |
| 477 | - QString(", xlab=\"Score%1\", ylab=\"False Accept Rate\") + theme_bw()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + | |
| 477 | + QString(", xlab=\"Score%1\", ylab=\"False Accept Rate\") + theme_minimal()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + | |
| 478 | 478 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + |
| 479 | 479 | QString(" + scale_y_continuous(trans=\"log10\")") + |
| 480 | 480 | ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) + |
| 481 | - QString(" + opts(aspect.ratio=1)") + | |
| 481 | + QString(" + theme(aspect.ratio=1)") + | |
| 482 | 482 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FAR")))); |
| 483 | 483 | |
| 484 | 484 | p.file.write(qPrintable(QString("qplot(X, Y, data=FRR, geom=\"line\"") + |
| 485 | 485 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) + |
| 486 | - QString(", xlab=\"Score%1\", ylab=\"False Reject Rate\") + theme_bw()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + | |
| 486 | + QString(", xlab=\"Score%1\", ylab=\"False Reject Rate\") + theme_minimal()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + | |
| 487 | 487 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + |
| 488 | 488 | QString(" + scale_y_continuous(trans=\"log10\")") + |
| 489 | 489 | ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) + |
| 490 | - QString(" + opts(aspect.ratio=1)") + | |
| 490 | + QString(" + theme(aspect.ratio=1)") + | |
| 491 | 491 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FRR")))); |
| 492 | 492 | |
| 493 | 493 | return p.finalize(show); |
| ... | ... | @@ -499,6 +499,6 @@ bool br::PlotMetadata(const QStringList &files, const QString &columns, bool sho |
| 499 | 499 | |
| 500 | 500 | RPlot p(files, "PlotMetadata", false); |
| 501 | 501 | foreach (const QString &column, columns.split(";")) |
| 502 | - p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_bw()\nggsave(\"%2.pdf\")\n").arg(p.majorHeader, column))); | |
| 502 | + p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_minimal()\nggsave(\"%2.pdf\")\n").arg(p.majorHeader, column))); | |
| 503 | 503 | return p.finalize(show); |
| 504 | 504 | } | ... | ... |
sdk/openbr_plugin.cpp
| ... | ... | @@ -112,13 +112,12 @@ float File::label() const |
| 112 | 112 | const QVariant variant = value("Label"); |
| 113 | 113 | if (variant.isNull()) return -1; |
| 114 | 114 | |
| 115 | - if (variant.canConvert(QVariant::Double)) { | |
| 116 | - bool ok; | |
| 117 | - float val = variant.toFloat(&ok); | |
| 118 | - if (ok) return val; | |
| 119 | - } | |
| 115 | + if (Globals->classes.contains(variant.toString())) | |
| 116 | + return Globals->classes.value(variant.toString()); | |
| 120 | 117 | |
| 121 | - return Globals->classes.value(variant.toString(), -1); | |
| 118 | + bool ok; | |
| 119 | + const float val = variant.toFloat(&ok); | |
| 120 | + return ok ? val : -1; | |
| 122 | 121 | } |
| 123 | 122 | |
| 124 | 123 | void File::remove(const QString &key) |
| ... | ... | @@ -130,10 +129,17 @@ void File::set(const QString &key, const QVariant &value) |
| 130 | 129 | { |
| 131 | 130 | if (key == "Label") { |
| 132 | 131 | bool ok = false; |
| 133 | - if (value.canConvert(QVariant::Double)) | |
| 132 | + const QString valueString = value.toString(); | |
| 133 | + | |
| 134 | + /* We assume that if the value starts with '0' | |
| 135 | + then it was probably intended to to be a string UID | |
| 136 | + and that it's numerical value is not relevant. */ | |
| 137 | + if (value.canConvert(QVariant::Double) && | |
| 138 | + (!valueString.startsWith('0') || (valueString == "0"))) | |
| 134 | 139 | value.toFloat(&ok); |
| 135 | - if (!ok && !Globals->classes.contains(value.toString())) | |
| 136 | - Globals->classes.insert(value.toString(), Globals->classes.size()); | |
| 140 | + | |
| 141 | + if (!ok && !Globals->classes.contains(valueString)) | |
| 142 | + Globals->classes.insert(valueString, Globals->classes.size()); | |
| 137 | 143 | } |
| 138 | 144 | |
| 139 | 145 | m_metadata.insert(key, value); |
| ... | ... | @@ -377,6 +383,10 @@ TemplateList TemplateList::fromInput(const br::File &input) |
| 377 | 383 | QScopedPointer<Gallery> i(Gallery::make(file)); |
| 378 | 384 | TemplateList newTemplates = i->read(); |
| 379 | 385 | |
| 386 | + // If input is a Format not a Gallery | |
| 387 | + if (newTemplates.isEmpty()) | |
| 388 | + newTemplates.append(input); | |
| 389 | + | |
| 380 | 390 | // Propogate metadata |
| 381 | 391 | for (int i=0; i<newTemplates.size(); i++) { |
| 382 | 392 | newTemplates[i].file.append(input.localMetadata()); |
| ... | ... | @@ -451,6 +461,8 @@ QString Object::argument(int index) const |
| 451 | 461 | return "[" + strings.join(",") + "]"; |
| 452 | 462 | } else if (type == "br::Transform*") { |
| 453 | 463 | return variant.value<Transform*>()->description(); |
| 464 | + } else if (type == "QStringList") { | |
| 465 | + return "[" + variant.toStringList().join(",") + "]"; | |
| 454 | 466 | } |
| 455 | 467 | |
| 456 | 468 | return variant.toString(); |
| ... | ... | @@ -484,6 +496,10 @@ void Object::store(QDataStream &stream) const |
| 484 | 496 | stream << property.read(this).toFloat(); |
| 485 | 497 | } else if (type == "double") { |
| 486 | 498 | stream << property.read(this).toDouble(); |
| 499 | + } else if (type == "QString") { | |
| 500 | + stream << property.read(this).toString(); | |
| 501 | + } else if (type == "QStringList") { | |
| 502 | + stream << property.read(this).toStringList(); | |
| 487 | 503 | } else { |
| 488 | 504 | qFatal("Can't serialize value of type: %s", qPrintable(type)); |
| 489 | 505 | } |
| ... | ... | @@ -520,6 +536,14 @@ void Object::load(QDataStream &stream) |
| 520 | 536 | double value; |
| 521 | 537 | stream >> value; |
| 522 | 538 | property.write(this, value); |
| 539 | + } else if (type == "QString") { | |
| 540 | + QString value; | |
| 541 | + stream >> value; | |
| 542 | + property.write(this, value); | |
| 543 | + } else if (type == "QStringList") { | |
| 544 | + QStringList value; | |
| 545 | + stream >> value; | |
| 546 | + property.write(this, value); | |
| 523 | 547 | } else { |
| 524 | 548 | qFatal("Can't serialize value of type: %s", qPrintable(type)); |
| 525 | 549 | } |
| ... | ... | @@ -560,6 +584,8 @@ void Object::setProperty(const QString &name, const QString &value) |
| 560 | 584 | } |
| 561 | 585 | } else if (type == "br::Transform*") { |
| 562 | 586 | variant.setValue(Transform::make(value, this)); |
| 587 | + } else if (type == "QStringList") { | |
| 588 | + variant.setValue(parse(value.mid(1, value.size()-2))); | |
| 563 | 589 | } else if (type == "bool") { |
| 564 | 590 | if (value.isEmpty()) variant = true; |
| 565 | 591 | else if (value == "false") variant = false; |
| ... | ... | @@ -1218,6 +1244,29 @@ void Distance::compare(const TemplateList &target, const TemplateList &query, Ou |
| 1218 | 1244 | if (Globals->parallelism) Globals->trackFutures(futures); |
| 1219 | 1245 | } |
| 1220 | 1246 | |
| 1247 | +float Distance::compare(const Template &target, const Template &query) const | |
| 1248 | +{ | |
| 1249 | + if (!Globals->demographicFilters.isEmpty()) { | |
| 1250 | + // The if statement is a faster check then iterating over an empty list of filters | |
| 1251 | + foreach (const QString &filter, Globals->demographicFilters) { | |
| 1252 | + const QString targetMetadata = target.file.getString(filter, ""); | |
| 1253 | + const QString queryMetadata = query.file.getString(filter, ""); | |
| 1254 | + if (targetMetadata.isEmpty() || queryMetadata.isEmpty()) continue; | |
| 1255 | + if (targetMetadata != queryMetadata) return -std::numeric_limits<float>::max(); | |
| 1256 | + } | |
| 1257 | + } | |
| 1258 | + | |
| 1259 | + if (Globals->ageDelta < std::numeric_limits<float>::max()) { | |
| 1260 | + const float targetAge = target.file.getFloat("Age", -1); | |
| 1261 | + const float queryAge = target.file.getFloat("Age", -1); | |
| 1262 | + if ((targetAge != -1) && (queryAge != -1) && (abs(targetAge - queryAge) > Globals->ageDelta)) | |
| 1263 | + return -std::numeric_limits<float>::max(); | |
| 1264 | + } | |
| 1265 | + | |
| 1266 | + return a * (_compare(target, query) - b); | |
| 1267 | +} | |
| 1268 | + | |
| 1269 | +/* Distance - private methods */ | |
| 1221 | 1270 | void Distance::compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const |
| 1222 | 1271 | { |
| 1223 | 1272 | for (int i=0; i<query.size(); i++) | ... | ... |
sdk/openbr_plugin.h
| ... | ... | @@ -485,6 +485,18 @@ public: |
| 485 | 485 | Q_PROPERTY(bool enrollAll READ get_enrollAll WRITE set_enrollAll RESET reset_enrollAll) |
| 486 | 486 | BR_PROPERTY(bool, enrollAll, false) |
| 487 | 487 | |
| 488 | + /*! | |
| 489 | + * \brief Keys to use when matching templates to automatically determine non-match based on template metadata. | |
| 490 | + */ | |
| 491 | + Q_PROPERTY(QStringList demographicFilters READ get_demographicFilters WRITE set_demographicFilters RESET reset_demographicFilters) | |
| 492 | + BR_PROPERTY(QStringList, demographicFilters, QStringList()) | |
| 493 | + | |
| 494 | + /*! | |
| 495 | + * \brief Allowable age difference when matching templates. | |
| 496 | + */ | |
| 497 | + Q_PROPERTY(float ageDelta READ get_ageDelta WRITE set_ageDelta RESET reset_ageDelta) | |
| 498 | + BR_PROPERTY(float, ageDelta, std::numeric_limits<float>::max()) | |
| 499 | + | |
| 488 | 500 | QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ |
| 489 | 501 | QHash<QString,int> classes; /*!< \brief Used by classifiers to associate text class labels with unique integers IDs. */ |
| 490 | 502 | QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ |
| ... | ... | @@ -821,9 +833,9 @@ private: |
| 821 | 833 | |
| 822 | 834 | /*! |
| 823 | 835 | * \ingroup formats |
| 824 | - * \brief Plugin base class for reading matrices from disk. | |
| 836 | + * \brief Plugin base class for reading a template from disk. | |
| 825 | 837 | * |
| 826 | - * A \em format is a br::File representing a matrix (ex. jpg image) on disk. | |
| 838 | + * A \em format is a br::File representing a template (ex. jpg image) on disk. | |
| 827 | 839 | * br::File::suffix() is used to determine which plugin should handle the format. |
| 828 | 840 | */ |
| 829 | 841 | class BR_EXPORT Format : public Object |
| ... | ... | @@ -832,7 +844,7 @@ class BR_EXPORT Format : public Object |
| 832 | 844 | |
| 833 | 845 | public: |
| 834 | 846 | virtual ~Format() {} |
| 835 | - virtual QList<cv::Mat> read() const = 0; /*!< \brief Returns a list of matrices created by reading #br::Object::file. */ | |
| 847 | + virtual Template read() const = 0; /*!< \brief Returns a br::Template created by reading #br::Object::file. */ | |
| 836 | 848 | }; |
| 837 | 849 | |
| 838 | 850 | /*! |
| ... | ... | @@ -1034,7 +1046,7 @@ public: |
| 1034 | 1046 | static QSharedPointer<Distance> fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's distance. */ |
| 1035 | 1047 | virtual void train(const TemplateList &src); /*!< \brief Train the distance. */ |
| 1036 | 1048 | virtual void compare(const TemplateList &target, const TemplateList &query, Output *output) const; /*!< \brief Compare two template lists. */ |
| 1037 | - inline float compare(const Template &target, const Template &query) const { return a * (_compare(target, query) - b); } /*!< \brief Compute the normalized distance between two templates. */ | |
| 1049 | + float compare(const Template &target, const Template &query) const; /*!< \brief Compute the normalized distance between two templates. */ | |
| 1038 | 1050 | |
| 1039 | 1051 | private: |
| 1040 | 1052 | virtual void compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const; | ... | ... |
sdk/plugins/compare.cpp
| ... | ... | @@ -42,7 +42,7 @@ public: |
| 42 | 42 | INF, |
| 43 | 43 | L1, |
| 44 | 44 | L2, |
| 45 | - CosineSimilarity }; | |
| 45 | + Cosine }; | |
| 46 | 46 | |
| 47 | 47 | private: |
| 48 | 48 | BR_PROPERTY(Metric, metric, L2) |
| ... | ... | @@ -76,8 +76,8 @@ private: |
| 76 | 76 | case L2: |
| 77 | 77 | result = norm(a, b, NORM_L2); |
| 78 | 78 | break; |
| 79 | - case CosineSimilarity: | |
| 80 | - result = cosineSimilarity(a, b); | |
| 79 | + case Cosine: | |
| 80 | + result = cosine(a, b); | |
| 81 | 81 | break; |
| 82 | 82 | default: |
| 83 | 83 | qFatal("Invalid metric"); |
| ... | ... | @@ -89,33 +89,29 @@ private: |
| 89 | 89 | return -log(result+1); |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | - static float cosineSimilarity(const Mat &a, const Mat &b) | |
| 92 | + static float cosine(const Mat &a, const Mat &b) | |
| 93 | 93 | { |
| 94 | - assert((a.type() == CV_32FC1) && (b.type() == CV_32FC1)); | |
| 95 | - assert((a.rows == b.rows) && (a.cols == b.cols)); | |
| 96 | - | |
| 97 | - float denom = 0; | |
| 98 | - float tnum = 0; | |
| 99 | - float qnum = 0; | |
| 94 | + float dot = 0; | |
| 95 | + float magA = 0; | |
| 96 | + float magB = 0; | |
| 100 | 97 | |
| 101 | 98 | for (int row=0; row<a.rows; row++) { |
| 102 | 99 | for (int col=0; col<a.cols; col++) { |
| 103 | - float target = a.at<float>(row,col); | |
| 104 | - float query = b.at<float>(row,col); | |
| 100 | + const float target = a.at<float>(row,col); | |
| 101 | + const float query = b.at<float>(row,col); | |
| 105 | 102 | |
| 106 | - denom += target * query; | |
| 107 | - tnum += target * target; | |
| 108 | - qnum += query * query; | |
| 103 | + dot += target * query; | |
| 104 | + magA += target * target; | |
| 105 | + magB += query * query; | |
| 109 | 106 | } |
| 110 | 107 | } |
| 111 | 108 | |
| 112 | - return denom / (sqrt(tnum)*sqrt(qnum)); | |
| 109 | + return dot / (sqrt(magA)*sqrt(magB)); | |
| 113 | 110 | } |
| 114 | 111 | }; |
| 115 | 112 | |
| 116 | 113 | BR_REGISTER(Distance, Dist) |
| 117 | 114 | |
| 118 | - | |
| 119 | 115 | /*! |
| 120 | 116 | * \ingroup distances |
| 121 | 117 | * \brief Fast 8-bit L1 distance | ... | ... |
sdk/plugins/eigen3.cpp
| ... | ... | @@ -276,10 +276,10 @@ class LDA : public Transform |
| 276 | 276 | |
| 277 | 277 | int dimsIn = ldaTrainingSet.first().m().rows * ldaTrainingSet.first().m().cols; |
| 278 | 278 | |
| 279 | - // MM ensures that classes values range from 0 to numClasses-1. | |
| 280 | - QList<float> classes = trainingSet.labels<float>(); // PCA doesn't project metadata | |
| 279 | + // OpenBR ensures that class values range from 0 to numClasses-1. | |
| 280 | + QList<int> classes = trainingSet.labels<int>(); | |
| 281 | 281 | QMap<int, int> classCounts = trainingSet.labelCounts(); |
| 282 | - int numClasses = classCounts.size(); | |
| 282 | + const int numClasses = classCounts.size(); | |
| 283 | 283 | |
| 284 | 284 | // Map Eigen into OpenCV |
| 285 | 285 | Eigen::MatrixXd data = Eigen::MatrixXd(dimsIn, instances); | ... | ... |
sdk/plugins/filter.cpp
sdk/plugins/format.cpp
| ... | ... | @@ -14,9 +14,11 @@ |
| 14 | 14 | * limitations under the License. * |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | +#include <QDate> | |
| 17 | 18 | #ifndef BR_EMBEDDED |
| 18 | 19 | #include <QNetworkAccessManager> |
| 19 | 20 | #include <QNetworkReply> |
| 21 | +#include <QtXml> | |
| 20 | 22 | #endif // BR_EMBEDDED |
| 21 | 23 | #include <opencv2/highgui/highgui.hpp> |
| 22 | 24 | #include <openbr_plugin.h> |
| ... | ... | @@ -33,7 +35,7 @@ class csvFormat : public Format |
| 33 | 35 | { |
| 34 | 36 | Q_OBJECT |
| 35 | 37 | |
| 36 | - QList<Mat> read() const | |
| 38 | + Template read() const | |
| 37 | 39 | { |
| 38 | 40 | QFile f(file.name); |
| 39 | 41 | f.open(QFile::ReadOnly); |
| ... | ... | @@ -59,9 +61,7 @@ class csvFormat : public Format |
| 59 | 61 | } |
| 60 | 62 | } |
| 61 | 63 | |
| 62 | - QList<Mat> mats; | |
| 63 | - mats.append(m); | |
| 64 | - return mats; | |
| 64 | + return Template(m); | |
| 65 | 65 | } |
| 66 | 66 | }; |
| 67 | 67 | |
| ... | ... | @@ -76,9 +76,9 @@ class DefaultFormat : public Format |
| 76 | 76 | { |
| 77 | 77 | Q_OBJECT |
| 78 | 78 | |
| 79 | - QList<Mat> read() const | |
| 79 | + Template read() const | |
| 80 | 80 | { |
| 81 | - QList<Mat> mats; | |
| 81 | + Template t; | |
| 82 | 82 | |
| 83 | 83 | if (file.name.startsWith("http://") || file.name.startsWith("www.")) { |
| 84 | 84 | #ifndef BR_EMBEDDED |
| ... | ... | @@ -94,16 +94,16 @@ class DefaultFormat : public Format |
| 94 | 94 | delete reply; |
| 95 | 95 | |
| 96 | 96 | Mat m = imdecode(Mat(1, data.size(), CV_8UC1, data.data()), 1); |
| 97 | - if (m.data) mats.append(m); | |
| 97 | + if (m.data) t.append(m); | |
| 98 | 98 | #endif // BR_EMBEDDED |
| 99 | 99 | } else { |
| 100 | 100 | QString prefix = ""; |
| 101 | 101 | if (!QFileInfo(file.name).exists()) prefix = file.getString("path") + "/"; |
| 102 | 102 | Mat m = imread((prefix+file.name).toStdString()); |
| 103 | - if (m.data) mats.append(m); | |
| 103 | + if (m.data) t.append(m); | |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | - return mats; | |
| 106 | + return t; | |
| 107 | 107 | } |
| 108 | 108 | }; |
| 109 | 109 | |
| ... | ... | @@ -118,7 +118,7 @@ class webcamFormat : public Format |
| 118 | 118 | { |
| 119 | 119 | Q_OBJECT |
| 120 | 120 | |
| 121 | - QList<Mat> read() const | |
| 121 | + Template read() const | |
| 122 | 122 | { |
| 123 | 123 | static QScopedPointer<VideoCapture> videoCapture; |
| 124 | 124 | |
| ... | ... | @@ -127,11 +127,73 @@ class webcamFormat : public Format |
| 127 | 127 | |
| 128 | 128 | Mat m; |
| 129 | 129 | videoCapture->read(m); |
| 130 | - | |
| 131 | - return QList<Mat>() << m; | |
| 130 | + return Template(m); | |
| 132 | 131 | } |
| 133 | 132 | }; |
| 134 | 133 | |
| 135 | 134 | BR_REGISTER(Format, webcamFormat) |
| 136 | 135 | |
| 136 | +#ifndef BR_EMBEDDED | |
| 137 | +/*! | |
| 138 | + * \ingroup formats | |
| 139 | + * \brief Decodes images from Base64 xml | |
| 140 | + * \author Scott Klum \cite sklum | |
| 141 | + * \author Josh Klontz \cite jklontz | |
| 142 | + */ | |
| 143 | +class xmlFormat : public Format | |
| 144 | +{ | |
| 145 | + Q_OBJECT | |
| 146 | + | |
| 147 | + Template read() const | |
| 148 | + { | |
| 149 | + QDomDocument doc(file); | |
| 150 | + QFile f(file); | |
| 151 | + if (!f.open(QIODevice::ReadOnly)) qFatal("xmlFormat::read unable to open %s for reading.", qPrintable(file.flat())); | |
| 152 | + if (!doc.setContent(&f)) qFatal("xmlFormat::read unable to parse %s.", qPrintable(file.flat())); | |
| 153 | + f.close(); | |
| 154 | + | |
| 155 | + Template t; | |
| 156 | + QDomElement docElem = doc.documentElement(); | |
| 157 | + QDomNode subject = docElem.firstChild(); | |
| 158 | + while (!subject.isNull()) { | |
| 159 | + QDomNode fileNode = subject.firstChild(); | |
| 160 | + | |
| 161 | + while (!fileNode.isNull()) { | |
| 162 | + QDomElement e = fileNode.toElement(); | |
| 163 | + | |
| 164 | + if (e.tagName() == "FORMAL_IMG") { | |
| 165 | + QByteArray byteArray = QByteArray::fromBase64(qPrintable(e.text())); | |
| 166 | + Mat m = imdecode(Mat(1, byteArray.size(), CV_8UC1, byteArray.data()), CV_LOAD_IMAGE_ANYDEPTH); | |
| 167 | + if (!m.data) qWarning("xmlFormat::read failed to decode image data."); | |
| 168 | + t.append(m); | |
| 169 | + } else if ((e.tagName() == "RELEASE_IMG") || | |
| 170 | + (e.tagName() == "PREBOOK_IMG") || | |
| 171 | + (e.tagName() == "LPROFILE") || | |
| 172 | + (e.tagName() == "RPROFILE")) { | |
| 173 | + // Ignore these other image fields for now | |
| 174 | + } else { | |
| 175 | + t.file.insert(e.tagName(), e.text()); | |
| 176 | + } | |
| 177 | + | |
| 178 | + fileNode = fileNode.nextSibling(); | |
| 179 | + } | |
| 180 | + subject = subject.nextSibling(); | |
| 181 | + } | |
| 182 | + | |
| 183 | + // Calculate age | |
| 184 | + if (t.file.contains("DOB")) { | |
| 185 | + const QDate dob = QDate::fromString(t.file.getString("DOB").left(10), "yyyy-MM-dd"); | |
| 186 | + const QDate current = QDate::currentDate(); | |
| 187 | + int age = current.year() - dob.year(); | |
| 188 | + if (current.month() < dob.month()) age--; | |
| 189 | + t.file.insert("Age", age); | |
| 190 | + } | |
| 191 | + | |
| 192 | + return t; | |
| 193 | + } | |
| 194 | +}; | |
| 195 | + | |
| 196 | +BR_REGISTER(Format, xmlFormat) | |
| 197 | +#endif // BR_EMBEDDED | |
| 198 | + | |
| 137 | 199 | #include "format.moc" | ... | ... |
sdk/plugins/llvm.cpp
| ... | ... | @@ -65,6 +65,22 @@ static Matrix MatrixFromMat(const cv::Mat &mat) |
| 65 | 65 | return m; |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | +static Mat MatFromMatrix(const Matrix &m) | |
| 69 | +{ | |
| 70 | + int depth = -1; | |
| 71 | + switch (m.type()) { | |
| 72 | + case Matrix::u8: depth = CV_8U; break; | |
| 73 | + case Matrix::s8: depth = CV_8S; break; | |
| 74 | + case Matrix::u16: depth = CV_16U; break; | |
| 75 | + case Matrix::s16: depth = CV_16S; break; | |
| 76 | + case Matrix::s32: depth = CV_32S; break; | |
| 77 | + case Matrix::f32: depth = CV_32F; break; | |
| 78 | + case Matrix::f64: depth = CV_64F; break; | |
| 79 | + default: qFatal("Unrecognized matrix depth."); | |
| 80 | + } | |
| 81 | + return Mat(m.rows, m.columns, CV_MAKETYPE(depth, m.channels), m.data).clone(); | |
| 82 | +} | |
| 83 | + | |
| 68 | 84 | static void AllocateMatrixFromMat(Matrix &m, cv::Mat &mat) |
| 69 | 85 | { |
| 70 | 86 | int cvType = -1; |
| ... | ... | @@ -230,26 +246,29 @@ struct MatrixBuilder : public Matrix |
| 230 | 246 | Value *compareLT(Value *i, Value *j) const { return isFloating() ? b->CreateFCmpOLT(i, j) : (isSigned() ? b->CreateICmpSLT(i, j) : b->CreateICmpULT(i, j)); } |
| 231 | 247 | Value *compareGT(Value *i, Value *j) const { return isFloating() ? b->CreateFCmpOGT(i, j) : (isSigned() ? b->CreateICmpSGT(i, j) : b->CreateICmpUGT(i, j)); } |
| 232 | 248 | |
| 233 | - static PHINode *beginLoop(IRBuilder<> &builder, Function *function, BasicBlock *parent, BasicBlock **current, const Twine &name = "") { | |
| 234 | - *current = BasicBlock::Create(getGlobalContext(), "loop_"+name, function); | |
| 235 | - builder.CreateBr(*current); | |
| 236 | - builder.SetInsertPoint(*current); | |
| 237 | - PHINode *j = builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), 2, name); | |
| 238 | - j->addIncoming(MatrixBuilder::zero(), parent); | |
| 239 | - return j; | |
| 240 | - } | |
| 241 | - PHINode *beginLoop(BasicBlock *parent, BasicBlock **current, const Twine &name = "") const { return beginLoop(*b, f, parent, current, name); } | |
| 242 | - static void endLoop(IRBuilder<> &builder, Function *function, BasicBlock *current, PHINode *j, Value *end, const Twine &name = "") { | |
| 243 | - BasicBlock *loop = BasicBlock::Create(getGlobalContext(), "loop_"+name+"_end", function); | |
| 249 | + static PHINode *beginLoop(IRBuilder<> &builder, Function *function, BasicBlock *entry, BasicBlock *&loop, BasicBlock *&exit, Value *stop, const Twine &name = "") { | |
| 250 | + loop = BasicBlock::Create(getGlobalContext(), "loop_"+name, function); | |
| 244 | 251 | builder.CreateBr(loop); |
| 245 | 252 | builder.SetInsertPoint(loop); |
| 246 | - Value *increment = builder.CreateAdd(j, MatrixBuilder::one(), "increment_"+name); | |
| 247 | - j->addIncoming(increment, loop); | |
| 248 | - BasicBlock *exit = BasicBlock::Create(getGlobalContext(), "loop_"+name+"_exit", function); | |
| 249 | - builder.CreateCondBr(builder.CreateICmpNE(increment, end, "loop_"+name+"_test"), current, exit); | |
| 253 | + | |
| 254 | + PHINode *i = builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), 2, name); | |
| 255 | + i->addIncoming(MatrixBuilder::zero(), entry); | |
| 256 | + Value *increment = builder.CreateAdd(i, MatrixBuilder::one(), "increment_"+name); | |
| 257 | + BasicBlock *body = BasicBlock::Create(getGlobalContext(), "loop_"+name+"_body", function); | |
| 258 | + i->addIncoming(increment, body); | |
| 259 | + | |
| 260 | + exit = BasicBlock::Create(getGlobalContext(), "loop_"+name+"_exit", function); | |
| 261 | + builder.CreateCondBr(builder.CreateICmpEQ(i, stop, "loop_"+name+"_test"), exit, body); | |
| 262 | + builder.SetInsertPoint(body); | |
| 263 | + return i; | |
| 264 | + } | |
| 265 | + PHINode *beginLoop(BasicBlock *entry, BasicBlock *&loop, BasicBlock *&exit, Value *stop, const Twine &name = "") const { return beginLoop(*b, f, entry, loop, exit, stop, name); } | |
| 266 | + | |
| 267 | + static void endLoop(IRBuilder<> &builder, BasicBlock *loop, BasicBlock *exit) { | |
| 268 | + builder.CreateBr(loop); | |
| 250 | 269 | builder.SetInsertPoint(exit); |
| 251 | 270 | } |
| 252 | - void endLoop(BasicBlock *current, PHINode *j, Value *end, const Twine &name = "") const { endLoop(*b, f, current, j, end, name); } | |
| 271 | + void endLoop(BasicBlock *loop, BasicBlock *exit) const { endLoop(*b, loop, exit); } | |
| 253 | 272 | |
| 254 | 273 | template <typename T> |
| 255 | 274 | inline static std::vector<T> toVector(T value) { std::vector<T> vector; vector.push_back(value); return vector; } |
| ... | ... | @@ -440,14 +459,14 @@ private: |
| 440 | 459 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); |
| 441 | 460 | IRBuilder<> builder(entry); |
| 442 | 461 | |
| 443 | - BasicBlock *kernel; | |
| 444 | - PHINode *i = MatrixBuilder::beginLoop(builder, function, entry, &kernel, "i"); | |
| 462 | + BasicBlock *loop, *exit; | |
| 463 | + PHINode *i = MatrixBuilder::beginLoop(builder, function, entry, loop, exit, len, "i"); | |
| 445 | 464 | |
| 446 | 465 | Matrix n; |
| 447 | 466 | preallocate(m, n); |
| 448 | 467 | build(MatrixBuilder(m, src, &builder, function, "src"), MatrixBuilder(n, dst, &builder, function, "dst"), i); |
| 449 | 468 | |
| 450 | - MatrixBuilder::endLoop(builder, function, kernel, i, len, "i"); | |
| 469 | + MatrixBuilder::endLoop(builder, loop, exit); | |
| 451 | 470 | |
| 452 | 471 | builder.CreateRetVoid(); |
| 453 | 472 | return function; |
| ... | ... | @@ -533,14 +552,14 @@ private: |
| 533 | 552 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); |
| 534 | 553 | IRBuilder<> builder(entry); |
| 535 | 554 | |
| 536 | - BasicBlock *kernel; | |
| 537 | - PHINode *i = MatrixBuilder::beginLoop(builder, function, entry, &kernel, "i"); | |
| 555 | + BasicBlock *loop, *exit; | |
| 556 | + PHINode *i = MatrixBuilder::beginLoop(builder, function, entry, loop, exit, len, "i"); | |
| 538 | 557 | |
| 539 | 558 | Matrix o; |
| 540 | 559 | preallocate(m, n, o); |
| 541 | 560 | build(MatrixBuilder(m, srcA, &builder, function, "srcA"), MatrixBuilder(n, srcB, &builder, function, "srcB"), MatrixBuilder(o, dst, &builder, function, "dst"), i); |
| 542 | 561 | |
| 543 | - MatrixBuilder::endLoop(builder, function, kernel, i, len, "i"); | |
| 562 | + MatrixBuilder::endLoop(builder, loop, exit); | |
| 544 | 563 | |
| 545 | 564 | builder.CreateRetVoid(); |
| 546 | 565 | return function; |
| ... | ... | @@ -744,53 +763,52 @@ class sumTransform : public UnaryKernel |
| 744 | 763 | dst.deindex(i, &c, &x, &y, &t); |
| 745 | 764 | AllocaInst *sum = dst.autoAlloca(0, "sum"); |
| 746 | 765 | |
| 747 | - QList<PHINode*> loops; | |
| 748 | - QList<BasicBlock*> blocks; | |
| 749 | - blocks.push_back(i->getParent()); | |
| 766 | + QList<BasicBlock*> loops, exits; | |
| 767 | + loops.push_back(i->getParent()); | |
| 750 | 768 | Value *src_c, *src_x, *src_y, *src_t; |
| 751 | 769 | |
| 752 | 770 | if (frames && !src.singleFrame()) { |
| 753 | - BasicBlock *block; | |
| 754 | - loops.append(dst.beginLoop(blocks.last(), &block, "src_t")); | |
| 755 | - blocks.append(block); | |
| 756 | - src_t = loops.last(); | |
| 771 | + BasicBlock *loop, *exit; | |
| 772 | + src_t = dst.beginLoop(loops.last(), loop, exit, src.getFrames(), "src_t"); | |
| 773 | + loops.append(loop); | |
| 774 | + exits.append(exit); | |
| 757 | 775 | } else { |
| 758 | 776 | src_t = t; |
| 759 | 777 | } |
| 760 | 778 | |
| 761 | 779 | if (rows && !src.singleRow()) { |
| 762 | - BasicBlock *block; | |
| 763 | - loops.append(dst.beginLoop(blocks.last(), &block, "src_y")); | |
| 764 | - blocks.append(block); | |
| 765 | - src_y = loops.last(); | |
| 780 | + BasicBlock *loop, *exit; | |
| 781 | + src_y = dst.beginLoop(loops.last(), loop, exit, src.getRows(), "src_y"); | |
| 782 | + loops.append(loop); | |
| 783 | + exits.append(exit); | |
| 766 | 784 | } else { |
| 767 | 785 | src_y = y; |
| 768 | 786 | } |
| 769 | 787 | |
| 770 | 788 | if (columns && !src.singleColumn()) { |
| 771 | - BasicBlock *block; | |
| 772 | - loops.append(dst.beginLoop(blocks.last(), &block, "src_x")); | |
| 773 | - blocks.append(block); | |
| 774 | - src_x = loops.last(); | |
| 789 | + BasicBlock *loop, *exit; | |
| 790 | + src_x = dst.beginLoop(loops.last(), loop, exit, src.getColumns(), "src_x"); | |
| 791 | + loops.append(loop); | |
| 792 | + exits.append(exit); | |
| 775 | 793 | } else { |
| 776 | 794 | src_x = x; |
| 777 | 795 | } |
| 778 | 796 | |
| 779 | 797 | if (channels && !src.singleChannel()) { |
| 780 | - BasicBlock *block; | |
| 781 | - loops.append(dst.beginLoop(blocks.last(), &block, "src_c")); | |
| 782 | - blocks.append(block); | |
| 783 | - src_c = loops.last(); | |
| 798 | + BasicBlock *loop, *exit; | |
| 799 | + src_c = dst.beginLoop(loops.last(), loop, exit, src.getChannels(), "src_c"); | |
| 800 | + loops.append(loop); | |
| 801 | + exits.append(exit); | |
| 784 | 802 | } else { |
| 785 | 803 | src_c = c; |
| 786 | 804 | } |
| 787 | 805 | |
| 788 | 806 | dst.b->CreateStore(dst.add(dst.b->CreateLoad(sum), src.cast(src.load(src.aliasIndex(dst, src_c, src_x, src_y, src_t)), dst), "accumulate"), sum); |
| 789 | 807 | |
| 790 | - if (channels && !src.singleChannel()) dst.endLoop(blocks.takeLast(), loops.takeLast(), src.getChannels(), "src_c"); | |
| 791 | - if (columns && !src.singleColumn()) dst.endLoop(blocks.takeLast(), loops.takeLast(), src.getColumns(), "src_x"); | |
| 792 | - if (rows && !src.singleRow()) dst.endLoop(blocks.takeLast(), loops.takeLast(), src.getRows(), "src_y"); | |
| 793 | - if (frames && !src.singleFrame()) dst.endLoop(blocks.takeLast(), loops.takeLast(), src.getFrames(), "src_t"); | |
| 808 | + if (channels && !src.singleChannel()) dst.endLoop(loops.takeLast(), exits.takeLast()); | |
| 809 | + if (columns && !src.singleColumn()) dst.endLoop(loops.takeLast(), exits.takeLast()); | |
| 810 | + if (rows && !src.singleRow()) dst.endLoop(loops.takeLast(), exits.takeLast()); | |
| 811 | + if (frames && !src.singleFrame()) dst.endLoop(loops.takeLast(), exits.takeLast()); | |
| 794 | 812 | |
| 795 | 813 | dst.store(i, dst.b->CreateLoad(sum)); |
| 796 | 814 | } | ... | ... |
sdk/plugins/meta.cpp
| ... | ... | @@ -329,12 +329,15 @@ class LoadStoreTransform : public MetaTransform |
| 329 | 329 | { |
| 330 | 330 | Q_OBJECT |
| 331 | 331 | Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) |
| 332 | - Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) | |
| 333 | 332 | BR_PROPERTY(QString, description, "Identity") |
| 334 | - BR_PROPERTY(br::Transform*, transform, NULL) | |
| 335 | 333 | |
| 334 | + Transform *transform; | |
| 336 | 335 | QString baseName; |
| 337 | 336 | |
| 337 | +public: | |
| 338 | + LoadStoreTransform() : transform(NULL) {} | |
| 339 | + | |
| 340 | +private: | |
| 338 | 341 | void init() |
| 339 | 342 | { |
| 340 | 343 | if (transform != NULL) return; |
| ... | ... | @@ -354,7 +357,7 @@ class LoadStoreTransform : public MetaTransform |
| 354 | 357 | QDataStream stream(&byteArray, QFile::WriteOnly); |
| 355 | 358 | stream << description; |
| 356 | 359 | transform->store(stream); |
| 357 | - QtUtils::writeFile(getFileName(), byteArray); | |
| 360 | + QtUtils::writeFile(baseName, byteArray); | |
| 358 | 361 | } |
| 359 | 362 | |
| 360 | 363 | void project(const Template &src, Template &dst) const |
| ... | ... | @@ -369,6 +372,7 @@ class LoadStoreTransform : public MetaTransform |
| 369 | 372 | |
| 370 | 373 | QString getFileName() const |
| 371 | 374 | { |
| 375 | + if (QFileInfo(baseName).exists()) return baseName; | |
| 372 | 376 | const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + baseName; |
| 373 | 377 | return QFileInfo(file).exists() ? file : QString(); |
| 374 | 378 | } | ... | ... |
sdk/plugins/misc.cpp
| ... | ... | @@ -34,18 +34,15 @@ class OpenTransform : public UntrainableMetaTransform |
| 34 | 34 | void project(const Template &src, Template &dst) const |
| 35 | 35 | { |
| 36 | 36 | if (Globals->verbose) qDebug("Opening %s", qPrintable(src.file.flat())); |
| 37 | - bool fto = false; | |
| 37 | + dst.file = src.file; | |
| 38 | 38 | foreach (const File &file, src.file.split()) { |
| 39 | 39 | QScopedPointer<Format> format(Factory<Format>::make(file)); |
| 40 | - QList<Mat> mats = format->read(); | |
| 41 | - if (mats.isEmpty()) { | |
| 42 | - qWarning("Can't open %s", qPrintable(file.flat())); | |
| 43 | - fto = true; | |
| 44 | - } | |
| 45 | - dst += mats; | |
| 40 | + Template t = format->read(); | |
| 41 | + if (t.isEmpty()) qWarning("Can't open %s", qPrintable(file.flat())); | |
| 42 | + dst.append(t); | |
| 43 | + dst.file.append(t.file.localMetadata()); | |
| 46 | 44 | } |
| 47 | - dst.file = src.file; | |
| 48 | - dst.file.insert("FTO", fto); | |
| 45 | + dst.file.insert("FTO", dst.isEmpty()); | |
| 49 | 46 | } |
| 50 | 47 | }; |
| 51 | 48 | |
| ... | ... | @@ -93,6 +90,27 @@ BR_REGISTER(Transform, ShowTransform) |
| 93 | 90 | |
| 94 | 91 | /*! |
| 95 | 92 | * \ingroup transforms |
| 93 | + * \brief Prints the template's file to stdout or stderr. | |
| 94 | + * \author Josh Klontz \cite jklontz | |
| 95 | + */ | |
| 96 | +class PrintTransform : public UntrainableMetaTransform | |
| 97 | +{ | |
| 98 | + Q_OBJECT | |
| 99 | + Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) | |
| 100 | + BR_PROPERTY(bool, error, false) | |
| 101 | + | |
| 102 | + void project(const Template &src, Template &dst) const | |
| 103 | + { | |
| 104 | + dst = src; | |
| 105 | + if (error) qDebug("%s\n", qPrintable(src.file.flat())); | |
| 106 | + else printf("%s\n", qPrintable(src.file.flat())); | |
| 107 | + } | |
| 108 | +}; | |
| 109 | + | |
| 110 | +BR_REGISTER(Transform, PrintTransform) | |
| 111 | + | |
| 112 | +/*! | |
| 113 | + * \ingroup transforms | |
| 96 | 114 | * \brief Sets the template's matrix data to the br::File::name. |
| 97 | 115 | * \author Josh Klontz \cite jklontz |
| 98 | 116 | */ | ... | ... |
sdk/plugins/regions.cpp
| ... | ... | @@ -79,23 +79,29 @@ BR_REGISTER(Transform, ByRow) |
| 79 | 79 | class Cat : public UntrainableMetaTransform |
| 80 | 80 | { |
| 81 | 81 | Q_OBJECT |
| 82 | + Q_PROPERTY(int partitions READ get_partitions WRITE set_partitions RESET reset_partitions) | |
| 83 | + BR_PROPERTY(int, partitions, 1) | |
| 82 | 84 | |
| 83 | 85 | void project(const Template &src, Template &dst) const |
| 84 | 86 | { |
| 85 | - int vals = 0; | |
| 86 | - foreach (const cv::Mat &m, src) | |
| 87 | - vals += m.total() * m.channels(); | |
| 88 | - | |
| 89 | - Mat cat(1, (int)vals, CV_32FC1); | |
| 90 | - int offset = 0; | |
| 91 | - foreach (const cv::Mat &m, src) { | |
| 92 | - size_t size = m.total() * m.elemSize(); | |
| 93 | - memcpy(&cat.data[offset], m.ptr(), size); | |
| 94 | - offset += size; | |
| 95 | - } | |
| 96 | - | |
| 97 | 87 | dst.file = src.file; |
| 98 | - dst = cat; | |
| 88 | + | |
| 89 | + if (src.size() % partitions != 0) | |
| 90 | + qFatal("Cat %d partitions does not evenly divide %d matrices.", partitions, src.size()); | |
| 91 | + QVector<int> sizes(partitions, 0); | |
| 92 | + for (int i=0; i<src.size(); i++) | |
| 93 | + sizes[i%partitions] += src[i].total() * src[i].channels(); | |
| 94 | + | |
| 95 | + foreach (int size, sizes) | |
| 96 | + dst.append(Mat(1, size, CV_32FC1)); | |
| 97 | + | |
| 98 | + QVector<int> offsets(partitions, 0); | |
| 99 | + for (int i=0; i<src.size(); i++) { | |
| 100 | + size_t size = src[i].total() * src[i].elemSize(); | |
| 101 | + int j = i%partitions; | |
| 102 | + memcpy(&dst[j].data[offsets[j]], src[i].ptr(), size); | |
| 103 | + offsets[j] += size; | |
| 104 | + } | |
| 99 | 105 | } |
| 100 | 106 | }; |
| 101 | 107 | ... | ... |
share/openbr/openbr.bib
| 1 | -%% This BibTeX bibliography file was created using BibDesk. | |
| 2 | -%% http://bibdesk.sourceforge.net/ | |
| 3 | - | |
| 4 | - | |
| 5 | -%% Created for Scott Klum at 2013-01-11 13:06:08 -0500 | |
| 6 | - | |
| 7 | - | |
| 8 | -%% Saved with string encoding Unicode (UTF-8) | |
| 9 | - | |
| 10 | - | |
| 1 | +@article{meyers08, | |
| 2 | + Author = {Meyers, E. and Wolf, L.}, | |
| 3 | + Date-Added = {2013-01-11 18:46:12 +0000}, | |
| 4 | + Date-Modified = {2013-01-11 18:47:57 +0000}, | |
| 5 | + Journal = {Int. Journal of Computer Vision}, | |
| 6 | + Number = {1}, | |
| 7 | + Pages = {93-104}, | |
| 8 | + Title = {Using biologically inspired features for face processing}, | |
| 9 | + Volume = {76}, | |
| 10 | + Year = {2008}} | |
| 11 | 11 | |
| 12 | 12 | @misc{sklum, |
| 13 | 13 | Author = {Scott J. Klum}, |
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | @misc{mburge, |
| 25 | 25 | Author = {Dr. Mark J. Burge}, |
| 26 | 26 | Howpublished = {https://github.com/mburge}, |
| 27 | - Title = {mburge at ieee.org}} | |
| 27 | + Title = {mburge at gmail.com}} | |
| 28 | 28 | |
| 29 | 29 | @misc{bklare, |
| 30 | 30 | Author = {Dr. Brendan F. Klare}, | ... | ... |