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,6 +47,9 @@ FileList BEE::readSigset(QString sigset, bool ignoreMetadata) | ||
| 47 | file.close(); | 47 | file.close(); |
| 48 | 48 | ||
| 49 | QDomElement docElem = doc.documentElement(); | 49 | QDomElement docElem = doc.documentElement(); |
| 50 | + if (docElem.nodeName() != "biometric-signature-set") | ||
| 51 | + return fileList; | ||
| 52 | + | ||
| 50 | QDomNode subject = docElem.firstChild(); | 53 | QDomNode subject = docElem.firstChild(); |
| 51 | while (!subject.isNull()) { | 54 | while (!subject.isNull()) { |
| 52 | // Looping through subjects | 55 | // Looping through subjects |
sdk/core/plot.cpp
| @@ -431,7 +431,7 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | @@ -431,7 +431,7 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | ||
| 431 | p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") + | 431 | p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") + |
| 432 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + | 432 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 433 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + | 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 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + | 435 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 436 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + | 436 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 437 | QString(" + scale_x_continuous(trans=\"log10\") + scale_y_continuous(trans=\"log10\")") + | 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,7 +440,7 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | ||
| 440 | p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\"") + | 440 | p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\"") + |
| 441 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + | 441 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 442 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + | 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 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + | 444 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 445 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + | 445 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 446 | QString(" + scale_x_continuous(trans=\"log10\") + scale_y_continuous(labels=percent)") + | 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,15 +449,15 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | ||
| 449 | p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + | 449 | p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + |
| 450 | QString(", xlab=\"Score%1\"").arg((p.flip ? p.majorSize : p.minorSize) > 1 ? " / " + (p.flip ? p.majorHeader : p.minorHeader) : QString()) + | 450 | QString(", xlab=\"Score%1\"").arg((p.flip ? p.majorSize : p.minorSize) > 1 ? " / " + (p.flip ? p.majorHeader : p.minorHeader) : QString()) + |
| 451 | QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + | 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 | (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()) + | 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 | QString("\nggsave(\"%1\")\n").arg(p.subfile("SD")))); | 455 | QString("\nggsave(\"%1\")\n").arg(p.subfile("SD")))); |
| 456 | 456 | ||
| 457 | p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"line\", xlab=\"Rank\", ylab=\"Retrieval Rate\"") + | 457 | p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"line\", xlab=\"Rank\", ylab=\"Retrieval Rate\"") + |
| 458 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + | 458 | (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) + |
| 459 | (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + | 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 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + | 461 | (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) + |
| 462 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + | 462 | (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + |
| 463 | QString(" + scale_y_continuous(labels=percent)") + | 463 | QString(" + scale_y_continuous(labels=percent)") + |
| @@ -466,28 +466,28 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | @@ -466,28 +466,28 @@ bool br::Plot(const QStringList &files, const QString &destination, bool show) | ||
| 466 | p.file.write(qPrintable(QString("qplot(factor(%1), data=BC, geom=\"bar\", position=\"dodge\", weight=Y").arg(p.majorHeader) + | 466 | p.file.write(qPrintable(QString("qplot(factor(%1), data=BC, geom=\"bar\", position=\"dodge\", weight=Y").arg(p.majorHeader) + |
| 467 | (p.majorSize > 1 ? QString(", fill=factor(%1)").arg(p.majorHeader) : QString()) + | 467 | (p.majorSize > 1 ? QString(", fill=factor(%1)").arg(p.majorHeader) : QString()) + |
| 468 | QString(", xlab=\"%1False Accept Rate\"").arg(p.majorSize > 1 ? p.majorHeader + " / " : QString()) + | 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 | (p.majorSize > 1 ? getScale("fill", p.majorHeader, p.majorSize) : QString()) + | 470 | (p.majorSize > 1 ? getScale("fill", p.majorHeader, p.majorSize) : QString()) + |
| 471 | (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minorHeader) : QString(" + facet_wrap(~ X)")) + | 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 | QString("\nggsave(\"%1\")\n").arg(p.subfile("BC")))); | 473 | QString("\nggsave(\"%1\")\n").arg(p.subfile("BC")))); |
| 474 | 474 | ||
| 475 | p.file.write(qPrintable(QString("qplot(X, Y, data=FAR, geom=\"line\"") + | 475 | p.file.write(qPrintable(QString("qplot(X, Y, data=FAR, geom=\"line\"") + |
| 476 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) + | 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 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + | 478 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + |
| 479 | QString(" + scale_y_continuous(trans=\"log10\")") + | 479 | QString(" + scale_y_continuous(trans=\"log10\")") + |
| 480 | ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) + | 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 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FAR")))); | 482 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FAR")))); |
| 483 | 483 | ||
| 484 | p.file.write(qPrintable(QString("qplot(X, Y, data=FRR, geom=\"line\"") + | 484 | p.file.write(qPrintable(QString("qplot(X, Y, data=FRR, geom=\"line\"") + |
| 485 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) + | 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 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + | 487 | ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + |
| 488 | QString(" + scale_y_continuous(trans=\"log10\")") + | 488 | QString(" + scale_y_continuous(trans=\"log10\")") + |
| 489 | ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) + | 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 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FRR")))); | 491 | QString("\nggsave(\"%1\")\n").arg(p.subfile("FRR")))); |
| 492 | 492 | ||
| 493 | return p.finalize(show); | 493 | return p.finalize(show); |
| @@ -499,6 +499,6 @@ bool br::PlotMetadata(const QStringList &files, const QString &columns, bool sho | @@ -499,6 +499,6 @@ bool br::PlotMetadata(const QStringList &files, const QString &columns, bool sho | ||
| 499 | 499 | ||
| 500 | RPlot p(files, "PlotMetadata", false); | 500 | RPlot p(files, "PlotMetadata", false); |
| 501 | foreach (const QString &column, columns.split(";")) | 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 | return p.finalize(show); | 503 | return p.finalize(show); |
| 504 | } | 504 | } |
sdk/openbr_plugin.cpp
| @@ -112,13 +112,12 @@ float File::label() const | @@ -112,13 +112,12 @@ float File::label() const | ||
| 112 | const QVariant variant = value("Label"); | 112 | const QVariant variant = value("Label"); |
| 113 | if (variant.isNull()) return -1; | 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 | void File::remove(const QString &key) | 123 | void File::remove(const QString &key) |
| @@ -130,10 +129,17 @@ void File::set(const QString &key, const QVariant &value) | @@ -130,10 +129,17 @@ void File::set(const QString &key, const QVariant &value) | ||
| 130 | { | 129 | { |
| 131 | if (key == "Label") { | 130 | if (key == "Label") { |
| 132 | bool ok = false; | 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 | value.toFloat(&ok); | 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 | m_metadata.insert(key, value); | 145 | m_metadata.insert(key, value); |
| @@ -377,6 +383,10 @@ TemplateList TemplateList::fromInput(const br::File &input) | @@ -377,6 +383,10 @@ TemplateList TemplateList::fromInput(const br::File &input) | ||
| 377 | QScopedPointer<Gallery> i(Gallery::make(file)); | 383 | QScopedPointer<Gallery> i(Gallery::make(file)); |
| 378 | TemplateList newTemplates = i->read(); | 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 | // Propogate metadata | 390 | // Propogate metadata |
| 381 | for (int i=0; i<newTemplates.size(); i++) { | 391 | for (int i=0; i<newTemplates.size(); i++) { |
| 382 | newTemplates[i].file.append(input.localMetadata()); | 392 | newTemplates[i].file.append(input.localMetadata()); |
| @@ -451,6 +461,8 @@ QString Object::argument(int index) const | @@ -451,6 +461,8 @@ QString Object::argument(int index) const | ||
| 451 | return "[" + strings.join(",") + "]"; | 461 | return "[" + strings.join(",") + "]"; |
| 452 | } else if (type == "br::Transform*") { | 462 | } else if (type == "br::Transform*") { |
| 453 | return variant.value<Transform*>()->description(); | 463 | return variant.value<Transform*>()->description(); |
| 464 | + } else if (type == "QStringList") { | ||
| 465 | + return "[" + variant.toStringList().join(",") + "]"; | ||
| 454 | } | 466 | } |
| 455 | 467 | ||
| 456 | return variant.toString(); | 468 | return variant.toString(); |
| @@ -484,6 +496,10 @@ void Object::store(QDataStream &stream) const | @@ -484,6 +496,10 @@ void Object::store(QDataStream &stream) const | ||
| 484 | stream << property.read(this).toFloat(); | 496 | stream << property.read(this).toFloat(); |
| 485 | } else if (type == "double") { | 497 | } else if (type == "double") { |
| 486 | stream << property.read(this).toDouble(); | 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 | } else { | 503 | } else { |
| 488 | qFatal("Can't serialize value of type: %s", qPrintable(type)); | 504 | qFatal("Can't serialize value of type: %s", qPrintable(type)); |
| 489 | } | 505 | } |
| @@ -520,6 +536,14 @@ void Object::load(QDataStream &stream) | @@ -520,6 +536,14 @@ void Object::load(QDataStream &stream) | ||
| 520 | double value; | 536 | double value; |
| 521 | stream >> value; | 537 | stream >> value; |
| 522 | property.write(this, value); | 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 | } else { | 547 | } else { |
| 524 | qFatal("Can't serialize value of type: %s", qPrintable(type)); | 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,6 +584,8 @@ void Object::setProperty(const QString &name, const QString &value) | ||
| 560 | } | 584 | } |
| 561 | } else if (type == "br::Transform*") { | 585 | } else if (type == "br::Transform*") { |
| 562 | variant.setValue(Transform::make(value, this)); | 586 | variant.setValue(Transform::make(value, this)); |
| 587 | + } else if (type == "QStringList") { | ||
| 588 | + variant.setValue(parse(value.mid(1, value.size()-2))); | ||
| 563 | } else if (type == "bool") { | 589 | } else if (type == "bool") { |
| 564 | if (value.isEmpty()) variant = true; | 590 | if (value.isEmpty()) variant = true; |
| 565 | else if (value == "false") variant = false; | 591 | else if (value == "false") variant = false; |
| @@ -1218,6 +1244,29 @@ void Distance::compare(const TemplateList &target, const TemplateList &query, Ou | @@ -1218,6 +1244,29 @@ void Distance::compare(const TemplateList &target, const TemplateList &query, Ou | ||
| 1218 | if (Globals->parallelism) Globals->trackFutures(futures); | 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 | void Distance::compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const | 1270 | void Distance::compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const |
| 1222 | { | 1271 | { |
| 1223 | for (int i=0; i<query.size(); i++) | 1272 | for (int i=0; i<query.size(); i++) |
sdk/openbr_plugin.h
| @@ -485,6 +485,18 @@ public: | @@ -485,6 +485,18 @@ public: | ||
| 485 | Q_PROPERTY(bool enrollAll READ get_enrollAll WRITE set_enrollAll RESET reset_enrollAll) | 485 | Q_PROPERTY(bool enrollAll READ get_enrollAll WRITE set_enrollAll RESET reset_enrollAll) |
| 486 | BR_PROPERTY(bool, enrollAll, false) | 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 | QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ | 500 | QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ |
| 489 | QHash<QString,int> classes; /*!< \brief Used by classifiers to associate text class labels with unique integers IDs. */ | 501 | QHash<QString,int> classes; /*!< \brief Used by classifiers to associate text class labels with unique integers IDs. */ |
| 490 | QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ | 502 | QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ |
| @@ -821,9 +833,9 @@ private: | @@ -821,9 +833,9 @@ private: | ||
| 821 | 833 | ||
| 822 | /*! | 834 | /*! |
| 823 | * \ingroup formats | 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 | * br::File::suffix() is used to determine which plugin should handle the format. | 839 | * br::File::suffix() is used to determine which plugin should handle the format. |
| 828 | */ | 840 | */ |
| 829 | class BR_EXPORT Format : public Object | 841 | class BR_EXPORT Format : public Object |
| @@ -832,7 +844,7 @@ class BR_EXPORT Format : public Object | @@ -832,7 +844,7 @@ class BR_EXPORT Format : public Object | ||
| 832 | 844 | ||
| 833 | public: | 845 | public: |
| 834 | virtual ~Format() {} | 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,7 +1046,7 @@ public: | ||
| 1034 | static QSharedPointer<Distance> fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's distance. */ | 1046 | static QSharedPointer<Distance> fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's distance. */ |
| 1035 | virtual void train(const TemplateList &src); /*!< \brief Train the distance. */ | 1047 | virtual void train(const TemplateList &src); /*!< \brief Train the distance. */ |
| 1036 | virtual void compare(const TemplateList &target, const TemplateList &query, Output *output) const; /*!< \brief Compare two template lists. */ | 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 | private: | 1051 | private: |
| 1040 | virtual void compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const; | 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,7 +42,7 @@ public: | ||
| 42 | INF, | 42 | INF, |
| 43 | L1, | 43 | L1, |
| 44 | L2, | 44 | L2, |
| 45 | - CosineSimilarity }; | 45 | + Cosine }; |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | BR_PROPERTY(Metric, metric, L2) | 48 | BR_PROPERTY(Metric, metric, L2) |
| @@ -76,8 +76,8 @@ private: | @@ -76,8 +76,8 @@ private: | ||
| 76 | case L2: | 76 | case L2: |
| 77 | result = norm(a, b, NORM_L2); | 77 | result = norm(a, b, NORM_L2); |
| 78 | break; | 78 | break; |
| 79 | - case CosineSimilarity: | ||
| 80 | - result = cosineSimilarity(a, b); | 79 | + case Cosine: |
| 80 | + result = cosine(a, b); | ||
| 81 | break; | 81 | break; |
| 82 | default: | 82 | default: |
| 83 | qFatal("Invalid metric"); | 83 | qFatal("Invalid metric"); |
| @@ -89,33 +89,29 @@ private: | @@ -89,33 +89,29 @@ private: | ||
| 89 | return -log(result+1); | 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 | for (int row=0; row<a.rows; row++) { | 98 | for (int row=0; row<a.rows; row++) { |
| 102 | for (int col=0; col<a.cols; col++) { | 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 | BR_REGISTER(Distance, Dist) | 113 | BR_REGISTER(Distance, Dist) |
| 117 | 114 | ||
| 118 | - | ||
| 119 | /*! | 115 | /*! |
| 120 | * \ingroup distances | 116 | * \ingroup distances |
| 121 | * \brief Fast 8-bit L1 distance | 117 | * \brief Fast 8-bit L1 distance |
sdk/plugins/eigen3.cpp
| @@ -276,10 +276,10 @@ class LDA : public Transform | @@ -276,10 +276,10 @@ class LDA : public Transform | ||
| 276 | 276 | ||
| 277 | int dimsIn = ldaTrainingSet.first().m().rows * ldaTrainingSet.first().m().cols; | 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 | QMap<int, int> classCounts = trainingSet.labelCounts(); | 281 | QMap<int, int> classCounts = trainingSet.labelCounts(); |
| 282 | - int numClasses = classCounts.size(); | 282 | + const int numClasses = classCounts.size(); |
| 283 | 283 | ||
| 284 | // Map Eigen into OpenCV | 284 | // Map Eigen into OpenCV |
| 285 | Eigen::MatrixXd data = Eigen::MatrixXd(dimsIn, instances); | 285 | Eigen::MatrixXd data = Eigen::MatrixXd(dimsIn, instances); |
sdk/plugins/filter.cpp
sdk/plugins/format.cpp
| @@ -14,9 +14,11 @@ | @@ -14,9 +14,11 @@ | ||
| 14 | * limitations under the License. * | 14 | * limitations under the License. * |
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | +#include <QDate> | ||
| 17 | #ifndef BR_EMBEDDED | 18 | #ifndef BR_EMBEDDED |
| 18 | #include <QNetworkAccessManager> | 19 | #include <QNetworkAccessManager> |
| 19 | #include <QNetworkReply> | 20 | #include <QNetworkReply> |
| 21 | +#include <QtXml> | ||
| 20 | #endif // BR_EMBEDDED | 22 | #endif // BR_EMBEDDED |
| 21 | #include <opencv2/highgui/highgui.hpp> | 23 | #include <opencv2/highgui/highgui.hpp> |
| 22 | #include <openbr_plugin.h> | 24 | #include <openbr_plugin.h> |
| @@ -33,7 +35,7 @@ class csvFormat : public Format | @@ -33,7 +35,7 @@ class csvFormat : public Format | ||
| 33 | { | 35 | { |
| 34 | Q_OBJECT | 36 | Q_OBJECT |
| 35 | 37 | ||
| 36 | - QList<Mat> read() const | 38 | + Template read() const |
| 37 | { | 39 | { |
| 38 | QFile f(file.name); | 40 | QFile f(file.name); |
| 39 | f.open(QFile::ReadOnly); | 41 | f.open(QFile::ReadOnly); |
| @@ -59,9 +61,7 @@ class csvFormat : public Format | @@ -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,9 +76,9 @@ class DefaultFormat : public Format | ||
| 76 | { | 76 | { |
| 77 | Q_OBJECT | 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 | if (file.name.startsWith("http://") || file.name.startsWith("www.")) { | 83 | if (file.name.startsWith("http://") || file.name.startsWith("www.")) { |
| 84 | #ifndef BR_EMBEDDED | 84 | #ifndef BR_EMBEDDED |
| @@ -94,16 +94,16 @@ class DefaultFormat : public Format | @@ -94,16 +94,16 @@ class DefaultFormat : public Format | ||
| 94 | delete reply; | 94 | delete reply; |
| 95 | 95 | ||
| 96 | Mat m = imdecode(Mat(1, data.size(), CV_8UC1, data.data()), 1); | 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 | #endif // BR_EMBEDDED | 98 | #endif // BR_EMBEDDED |
| 99 | } else { | 99 | } else { |
| 100 | QString prefix = ""; | 100 | QString prefix = ""; |
| 101 | if (!QFileInfo(file.name).exists()) prefix = file.getString("path") + "/"; | 101 | if (!QFileInfo(file.name).exists()) prefix = file.getString("path") + "/"; |
| 102 | Mat m = imread((prefix+file.name).toStdString()); | 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,7 +118,7 @@ class webcamFormat : public Format | ||
| 118 | { | 118 | { |
| 119 | Q_OBJECT | 119 | Q_OBJECT |
| 120 | 120 | ||
| 121 | - QList<Mat> read() const | 121 | + Template read() const |
| 122 | { | 122 | { |
| 123 | static QScopedPointer<VideoCapture> videoCapture; | 123 | static QScopedPointer<VideoCapture> videoCapture; |
| 124 | 124 | ||
| @@ -127,11 +127,73 @@ class webcamFormat : public Format | @@ -127,11 +127,73 @@ class webcamFormat : public Format | ||
| 127 | 127 | ||
| 128 | Mat m; | 128 | Mat m; |
| 129 | videoCapture->read(m); | 129 | videoCapture->read(m); |
| 130 | - | ||
| 131 | - return QList<Mat>() << m; | 130 | + return Template(m); |
| 132 | } | 131 | } |
| 133 | }; | 132 | }; |
| 134 | 133 | ||
| 135 | BR_REGISTER(Format, webcamFormat) | 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 | #include "format.moc" | 199 | #include "format.moc" |
sdk/plugins/llvm.cpp
| @@ -65,6 +65,22 @@ static Matrix MatrixFromMat(const cv::Mat &mat) | @@ -65,6 +65,22 @@ static Matrix MatrixFromMat(const cv::Mat &mat) | ||
| 65 | return m; | 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 | static void AllocateMatrixFromMat(Matrix &m, cv::Mat &mat) | 84 | static void AllocateMatrixFromMat(Matrix &m, cv::Mat &mat) |
| 69 | { | 85 | { |
| 70 | int cvType = -1; | 86 | int cvType = -1; |
| @@ -230,26 +246,29 @@ struct MatrixBuilder : public Matrix | @@ -230,26 +246,29 @@ struct MatrixBuilder : public Matrix | ||
| 230 | Value *compareLT(Value *i, Value *j) const { return isFloating() ? b->CreateFCmpOLT(i, j) : (isSigned() ? b->CreateICmpSLT(i, j) : b->CreateICmpULT(i, j)); } | 246 | Value *compareLT(Value *i, Value *j) const { return isFloating() ? b->CreateFCmpOLT(i, j) : (isSigned() ? b->CreateICmpSLT(i, j) : b->CreateICmpULT(i, j)); } |
| 231 | Value *compareGT(Value *i, Value *j) const { return isFloating() ? b->CreateFCmpOGT(i, j) : (isSigned() ? b->CreateICmpSGT(i, j) : b->CreateICmpUGT(i, j)); } | 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 | builder.CreateBr(loop); | 251 | builder.CreateBr(loop); |
| 245 | builder.SetInsertPoint(loop); | 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 | builder.SetInsertPoint(exit); | 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 | template <typename T> | 273 | template <typename T> |
| 255 | inline static std::vector<T> toVector(T value) { std::vector<T> vector; vector.push_back(value); return vector; } | 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,14 +459,14 @@ private: | ||
| 440 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); | 459 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); |
| 441 | IRBuilder<> builder(entry); | 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 | Matrix n; | 465 | Matrix n; |
| 447 | preallocate(m, n); | 466 | preallocate(m, n); |
| 448 | build(MatrixBuilder(m, src, &builder, function, "src"), MatrixBuilder(n, dst, &builder, function, "dst"), i); | 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 | builder.CreateRetVoid(); | 471 | builder.CreateRetVoid(); |
| 453 | return function; | 472 | return function; |
| @@ -533,14 +552,14 @@ private: | @@ -533,14 +552,14 @@ private: | ||
| 533 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); | 552 | BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); |
| 534 | IRBuilder<> builder(entry); | 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 | Matrix o; | 558 | Matrix o; |
| 540 | preallocate(m, n, o); | 559 | preallocate(m, n, o); |
| 541 | build(MatrixBuilder(m, srcA, &builder, function, "srcA"), MatrixBuilder(n, srcB, &builder, function, "srcB"), MatrixBuilder(o, dst, &builder, function, "dst"), i); | 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 | builder.CreateRetVoid(); | 564 | builder.CreateRetVoid(); |
| 546 | return function; | 565 | return function; |
| @@ -744,53 +763,52 @@ class sumTransform : public UnaryKernel | @@ -744,53 +763,52 @@ class sumTransform : public UnaryKernel | ||
| 744 | dst.deindex(i, &c, &x, &y, &t); | 763 | dst.deindex(i, &c, &x, &y, &t); |
| 745 | AllocaInst *sum = dst.autoAlloca(0, "sum"); | 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 | Value *src_c, *src_x, *src_y, *src_t; | 768 | Value *src_c, *src_x, *src_y, *src_t; |
| 751 | 769 | ||
| 752 | if (frames && !src.singleFrame()) { | 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 | } else { | 775 | } else { |
| 758 | src_t = t; | 776 | src_t = t; |
| 759 | } | 777 | } |
| 760 | 778 | ||
| 761 | if (rows && !src.singleRow()) { | 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 | } else { | 784 | } else { |
| 767 | src_y = y; | 785 | src_y = y; |
| 768 | } | 786 | } |
| 769 | 787 | ||
| 770 | if (columns && !src.singleColumn()) { | 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 | } else { | 793 | } else { |
| 776 | src_x = x; | 794 | src_x = x; |
| 777 | } | 795 | } |
| 778 | 796 | ||
| 779 | if (channels && !src.singleChannel()) { | 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 | } else { | 802 | } else { |
| 785 | src_c = c; | 803 | src_c = c; |
| 786 | } | 804 | } |
| 787 | 805 | ||
| 788 | 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); | 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 | dst.store(i, dst.b->CreateLoad(sum)); | 813 | dst.store(i, dst.b->CreateLoad(sum)); |
| 796 | } | 814 | } |
sdk/plugins/meta.cpp
| @@ -329,12 +329,15 @@ class LoadStoreTransform : public MetaTransform | @@ -329,12 +329,15 @@ class LoadStoreTransform : public MetaTransform | ||
| 329 | { | 329 | { |
| 330 | Q_OBJECT | 330 | Q_OBJECT |
| 331 | Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | 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 | BR_PROPERTY(QString, description, "Identity") | 332 | BR_PROPERTY(QString, description, "Identity") |
| 334 | - BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 335 | 333 | ||
| 334 | + Transform *transform; | ||
| 336 | QString baseName; | 335 | QString baseName; |
| 337 | 336 | ||
| 337 | +public: | ||
| 338 | + LoadStoreTransform() : transform(NULL) {} | ||
| 339 | + | ||
| 340 | +private: | ||
| 338 | void init() | 341 | void init() |
| 339 | { | 342 | { |
| 340 | if (transform != NULL) return; | 343 | if (transform != NULL) return; |
| @@ -354,7 +357,7 @@ class LoadStoreTransform : public MetaTransform | @@ -354,7 +357,7 @@ class LoadStoreTransform : public MetaTransform | ||
| 354 | QDataStream stream(&byteArray, QFile::WriteOnly); | 357 | QDataStream stream(&byteArray, QFile::WriteOnly); |
| 355 | stream << description; | 358 | stream << description; |
| 356 | transform->store(stream); | 359 | transform->store(stream); |
| 357 | - QtUtils::writeFile(getFileName(), byteArray); | 360 | + QtUtils::writeFile(baseName, byteArray); |
| 358 | } | 361 | } |
| 359 | 362 | ||
| 360 | void project(const Template &src, Template &dst) const | 363 | void project(const Template &src, Template &dst) const |
| @@ -369,6 +372,7 @@ class LoadStoreTransform : public MetaTransform | @@ -369,6 +372,7 @@ class LoadStoreTransform : public MetaTransform | ||
| 369 | 372 | ||
| 370 | QString getFileName() const | 373 | QString getFileName() const |
| 371 | { | 374 | { |
| 375 | + if (QFileInfo(baseName).exists()) return baseName; | ||
| 372 | const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + baseName; | 376 | const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + baseName; |
| 373 | return QFileInfo(file).exists() ? file : QString(); | 377 | return QFileInfo(file).exists() ? file : QString(); |
| 374 | } | 378 | } |
sdk/plugins/misc.cpp
| @@ -34,18 +34,15 @@ class OpenTransform : public UntrainableMetaTransform | @@ -34,18 +34,15 @@ class OpenTransform : public UntrainableMetaTransform | ||
| 34 | void project(const Template &src, Template &dst) const | 34 | void project(const Template &src, Template &dst) const |
| 35 | { | 35 | { |
| 36 | if (Globals->verbose) qDebug("Opening %s", qPrintable(src.file.flat())); | 36 | if (Globals->verbose) qDebug("Opening %s", qPrintable(src.file.flat())); |
| 37 | - bool fto = false; | 37 | + dst.file = src.file; |
| 38 | foreach (const File &file, src.file.split()) { | 38 | foreach (const File &file, src.file.split()) { |
| 39 | QScopedPointer<Format> format(Factory<Format>::make(file)); | 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,6 +90,27 @@ BR_REGISTER(Transform, ShowTransform) | ||
| 93 | 90 | ||
| 94 | /*! | 91 | /*! |
| 95 | * \ingroup transforms | 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 | * \brief Sets the template's matrix data to the br::File::name. | 114 | * \brief Sets the template's matrix data to the br::File::name. |
| 97 | * \author Josh Klontz \cite jklontz | 115 | * \author Josh Klontz \cite jklontz |
| 98 | */ | 116 | */ |
sdk/plugins/regions.cpp
| @@ -79,23 +79,29 @@ BR_REGISTER(Transform, ByRow) | @@ -79,23 +79,29 @@ BR_REGISTER(Transform, ByRow) | ||
| 79 | class Cat : public UntrainableMetaTransform | 79 | class Cat : public UntrainableMetaTransform |
| 80 | { | 80 | { |
| 81 | Q_OBJECT | 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 | void project(const Template &src, Template &dst) const | 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 | dst.file = src.file; | 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 | @misc{sklum, | 12 | @misc{sklum, |
| 13 | Author = {Scott J. Klum}, | 13 | Author = {Scott J. Klum}, |
| @@ -24,7 +24,7 @@ | @@ -24,7 +24,7 @@ | ||
| 24 | @misc{mburge, | 24 | @misc{mburge, |
| 25 | Author = {Dr. Mark J. Burge}, | 25 | Author = {Dr. Mark J. Burge}, |
| 26 | Howpublished = {https://github.com/mburge}, | 26 | Howpublished = {https://github.com/mburge}, |
| 27 | - Title = {mburge at ieee.org}} | 27 | + Title = {mburge at gmail.com}} |
| 28 | 28 | ||
| 29 | @misc{bklare, | 29 | @misc{bklare, |
| 30 | Author = {Dr. Brendan F. Klare}, | 30 | Author = {Dr. Brendan F. Klare}, |