Commit e443d2244ccddf56b2e60f0ea898bfa70db5575f
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
19 changed files
with
318 additions
and
265 deletions
app/examples/age_estimation.cpp
| ... | ... | @@ -29,9 +29,7 @@ |
| 29 | 29 | |
| 30 | 30 | static void printTemplate(const br::Template &t) |
| 31 | 31 | { |
| 32 | - printf("%s age: %d\n", | |
| 33 | - qPrintable(t.file.fileName()), | |
| 34 | - t.file.get<int>("Label")); | |
| 32 | + printf("%s age: %d\n", qPrintable(t.file.fileName()), int(t.file.label())); | |
| 35 | 33 | } |
| 36 | 34 | |
| 37 | 35 | int main(int argc, char *argv[]) | ... | ... |
app/examples/face_recognition_evaluation.cpp
| ... | ... | @@ -55,14 +55,12 @@ int main(int argc, char *argv[]) |
| 55 | 55 | |
| 56 | 56 | // Evaluate the performance of OpenBR's FaceRecognition and a COTS face recognition system. |
| 57 | 57 | br_eval("FaceRecognition_MEDS.mtx", "MEDS.mask", "Algorithm_Dataset/FaceRecognition_MEDS.csv"); |
| 58 | - br_eval("../data/MEDS/simmat/COTS_MEDS.mtx", "MEDS.mask", "Algorithm_Dataset/COTS_MEDS.csv"); | |
| 59 | 58 | |
| 60 | 59 | // The '_' character has special significance and is used to populate plot legends. |
| 61 | 60 | // Requires R installation, see documentation of br_plot for details. |
| 62 | - const char *files[2]; | |
| 61 | + const char *files[1]; | |
| 63 | 62 | files[0] = "Algorithm_Dataset/FaceRecognition_MEDS.csv"; |
| 64 | - files[1] = "Algorithm_Dataset/COTS_MEDS.csv"; | |
| 65 | - br_plot(2, files, "MEDS", true); | |
| 63 | + br_plot(1, files, "MEDS", true); | |
| 66 | 64 | |
| 67 | 65 | br_finalize(); |
| 68 | 66 | return 0; | ... | ... |
app/examples/gender_estimation.cpp
| ... | ... | @@ -29,9 +29,7 @@ |
| 29 | 29 | |
| 30 | 30 | static void printTemplate(const br::Template &t) |
| 31 | 31 | { |
| 32 | - printf("%s gender: %s\n", | |
| 33 | - qPrintable(t.file.fileName()), | |
| 34 | - t.file.get<int>("Label") == 1 ? "Female" : "Male"); | |
| 32 | + printf("%s gender: %s\n", qPrintable(t.file.fileName()), t.file.label() == 1 ? "Female" : "Male"); | |
| 35 | 33 | } |
| 36 | 34 | |
| 37 | 35 | int main(int argc, char *argv[]) | ... | ... |
openbr/core/bee.cpp
| ... | ... | @@ -58,24 +58,18 @@ FileList BEE::readSigset(const QString &sigset, bool ignoreMetadata) |
| 58 | 58 | QString name = d.attribute("name"); |
| 59 | 59 | while (!fileNode.isNull()) { |
| 60 | 60 | // Looping through files |
| 61 | - File file; | |
| 61 | + File file("", name); | |
| 62 | 62 | |
| 63 | 63 | QDomElement e = fileNode.toElement(); |
| 64 | 64 | QDomNamedNodeMap attributes = e.attributes(); |
| 65 | 65 | for (int i=0; i<attributes.length(); i++) { |
| 66 | - QString key = attributes.item(i).nodeName(); | |
| 67 | - QString value = attributes.item(i).nodeValue(); | |
| 68 | - | |
| 69 | - if (key == "file-name") { | |
| 70 | - File newFile(value, name); | |
| 71 | - newFile.append(file); | |
| 72 | - file = newFile; | |
| 73 | - } else if (!ignoreMetadata) { | |
| 74 | - file.set(key, value); | |
| 75 | - } | |
| 66 | + const QString key = attributes.item(i).nodeName(); | |
| 67 | + const QString value = attributes.item(i).nodeValue(); | |
| 68 | + if (key == "file-name") file.name = value; | |
| 69 | + else if (!ignoreMetadata) file.set(key, value); | |
| 76 | 70 | } |
| 77 | 71 | |
| 78 | - if (file.isNull()) qFatal("Empty file-name in %s.", qPrintable(sigset)); | |
| 72 | + if (file.name.isEmpty()) qFatal("Missing file-name in %s.", qPrintable(sigset)); | |
| 79 | 73 | fileList.append(file); |
| 80 | 74 | |
| 81 | 75 | fileNode = fileNode.nextSibling(); |
| ... | ... | @@ -99,7 +93,7 @@ void BEE::writeSigset(const QString &sigset, const br::FileList &files, bool ign |
| 99 | 93 | QStringList metadata; |
| 100 | 94 | if (!ignoreMetadata) |
| 101 | 95 | foreach (const QString &key, file.localKeys()) { |
| 102 | - if ((key == "Index") || (key == "Label")) continue; | |
| 96 | + if ((key == "Index") || (key == "Subject")) continue; | |
| 103 | 97 | metadata.append(key+"=\""+QtUtils::toString(file.value(key))+"\""); |
| 104 | 98 | } |
| 105 | 99 | lines.append("\t<biometric-signature name=\"" + file.subject() +"\">"); | ... | ... |
openbr/core/classify.cpp
| ... | ... | @@ -56,7 +56,7 @@ void br::EvalClassification(const QString &predictedInput, const QString &truthI |
| 56 | 56 | } |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | - QSharedPointer<Output> output(Output::make("", FileList() << "Label" << "Count" << "Precision" << "Recall" << "F-score", FileList(counters.size()))); | |
| 59 | + QSharedPointer<Output> output(Output::make("", FileList() << "Subject" << "Count" << "Precision" << "Recall" << "F-score", FileList(counters.size()))); | |
| 60 | 60 | |
| 61 | 61 | int tpc = 0; |
| 62 | 62 | int fnc = 0; | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -77,7 +77,7 @@ struct AlgorithmCore |
| 77 | 77 | const bool hasComparer = !distance.isNull(); |
| 78 | 78 | out << hasComparer; |
| 79 | 79 | if (hasComparer) distance->store(out); |
| 80 | - out << Globals->classes; | |
| 80 | + out << Globals->subjects; | |
| 81 | 81 | |
| 82 | 82 | // Compress and save to file |
| 83 | 83 | QtUtils::writeFile(model, data, -1); |
| ... | ... | @@ -97,7 +97,7 @@ struct AlgorithmCore |
| 97 | 97 | transform->load(in); |
| 98 | 98 | bool hasDistance; in >> hasDistance; |
| 99 | 99 | if (hasDistance) distance->load(in); |
| 100 | - in >> Globals->classes; | |
| 100 | + in >> Globals->subjects; | |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | File getMemoryGallery(const File &file) const | ... | ... |
openbr/gui/classifier.cpp
| ... | ... | @@ -44,13 +44,13 @@ void Classifier::_classify(File file) |
| 44 | 44 | |
| 45 | 45 | if (algorithm == "GenderClassification") { |
| 46 | 46 | key = "Gender"; |
| 47 | - value = (f.get<int>("Label", 0) == 0 ? "Male" : "Female"); | |
| 47 | + value = (f.label() == 0 ? "Male" : "Female"); | |
| 48 | 48 | } else if (algorithm == "AgeRegression") { |
| 49 | 49 | key = "Age"; |
| 50 | - value = QString::number(int(f.get<float>("Label", 0)+0.5)) + " Years"; | |
| 50 | + value = QString::number(int(f.label()+0.5)) + " Years"; | |
| 51 | 51 | } else { |
| 52 | 52 | key = algorithm; |
| 53 | - value = f.get<QString>("Label"); | |
| 53 | + value = QString::number(f.label()); | |
| 54 | 54 | } |
| 55 | 55 | break; |
| 56 | 56 | } | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -132,33 +132,11 @@ QVariant File::parse(const QString &value) |
| 132 | 132 | if (ok) return point; |
| 133 | 133 | const QRectF rect = QtUtils::toRect(value, &ok); |
| 134 | 134 | if (ok) return rect; |
| 135 | - | |
| 136 | - /* We assume that if the value starts with '0' | |
| 137 | - then it was probably intended to be a string UID | |
| 138 | - and that it's numerical value is not relevant. */ | |
| 139 | - if (!value.startsWith('0') || (value == "0")) { | |
| 140 | - const float f = value.toFloat(&ok); | |
| 141 | - if (ok) return f; | |
| 142 | - } | |
| 143 | - | |
| 135 | + const float f = value.toFloat(&ok); | |
| 136 | + if (ok) return f; | |
| 144 | 137 | return value; |
| 145 | 138 | } |
| 146 | 139 | |
| 147 | -void File::set(const QString &key, const QVariant &value) | |
| 148 | -{ | |
| 149 | - if (key == "Label") { | |
| 150 | - const QString valueString = value.toString(); | |
| 151 | - if (!Globals->classes.contains(valueString)) { | |
| 152 | - static QMutex mutex; | |
| 153 | - QMutexLocker mutexLocker(&mutex); | |
| 154 | - if (!Globals->classes.contains(valueString)) | |
| 155 | - Globals->classes.insert(valueString, Globals->classes.size()); | |
| 156 | - } | |
| 157 | - } | |
| 158 | - | |
| 159 | - m_metadata.insert(key, value); | |
| 160 | -} | |
| 161 | - | |
| 162 | 140 | void File::set(const QString &key, const QString &value) |
| 163 | 141 | { |
| 164 | 142 | if (value.startsWith('[') && value.endsWith(']')) { |
| ... | ... | @@ -179,22 +157,27 @@ bool File::getBool(const QString &key, bool defaultValue) const |
| 179 | 157 | return variant.value<bool>(); |
| 180 | 158 | } |
| 181 | 159 | |
| 182 | -QString File::subject(int label) | |
| 160 | +QString File::subject() const | |
| 183 | 161 | { |
| 184 | - return Globals->classes.key(label, QString::number(label)); | |
| 162 | + const QVariant l = m_metadata.value("Label"); | |
| 163 | + if (!l.isNull()) return Globals->subjects.key(l.toFloat(), l.toString()); | |
| 164 | + return m_metadata.value("Subject").toString(); | |
| 185 | 165 | } |
| 186 | 166 | |
| 187 | 167 | float File::label() const |
| 188 | 168 | { |
| 189 | - const QVariant variant = value("Label"); | |
| 190 | - if (variant.isNull()) return -1; | |
| 169 | + const QVariant l = m_metadata.value("Label"); | |
| 170 | + if (!l.isNull()) return l.toFloat(); | |
| 191 | 171 | |
| 192 | - if (Globals->classes.contains(variant.toString())) | |
| 193 | - return Globals->classes.value(variant.toString()); | |
| 172 | + const QVariant s = m_metadata.value("Subject"); | |
| 173 | + if (s.isNull()) return -1; | |
| 194 | 174 | |
| 195 | - bool ok; | |
| 196 | - const float val = variant.toFloat(&ok); | |
| 197 | - return ok ? val : -1; | |
| 175 | + const QString subject = s.toString(); | |
| 176 | + static QMutex mutex; | |
| 177 | + QMutexLocker mutexLocker(&mutex); | |
| 178 | + if (!Globals->subjects.contains(subject)) | |
| 179 | + Globals->subjects.insert(subject, Globals->subjects.size()); | |
| 180 | + return Globals->subjects.value(subject); | |
| 198 | 181 | } |
| 199 | 182 | |
| 200 | 183 | QList<QPointF> File::namedPoints() const |
| ... | ... | @@ -310,8 +293,6 @@ QDataStream &br::operator<<(QDataStream &stream, const File &file) |
| 310 | 293 | QDataStream &br::operator>>(QDataStream &stream, File &file) |
| 311 | 294 | { |
| 312 | 295 | return stream >> file.name >> file.m_metadata; |
| 313 | - const QVariant label = file.m_metadata.value("Label"); | |
| 314 | - if (!label.isNull()) file.set("Label", label); // Trigger population of Globals->classes | |
| 315 | 296 | } |
| 316 | 297 | |
| 317 | 298 | /* FileList - public methods */ |
| ... | ... | @@ -464,14 +445,15 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) |
| 464 | 445 | |
| 465 | 446 | TemplateList TemplateList::relabel(const TemplateList &tl) |
| 466 | 447 | { |
| 467 | - QHash<int,int> labels; | |
| 468 | - foreach (int label, tl.labels<int>()) | |
| 469 | - if (!labels.contains(label)) | |
| 470 | - labels.insert(label, labels.size()); | |
| 448 | + const QList<int> originalLabels = tl.labels<int>(); | |
| 449 | + QHash<int,int> labelTable; | |
| 450 | + foreach (int label, originalLabels) | |
| 451 | + if (!labelTable.contains(label)) | |
| 452 | + labelTable.insert(label, labelTable.size()); | |
| 471 | 453 | |
| 472 | 454 | TemplateList result = tl; |
| 473 | 455 | for (int i=0; i<result.size(); i++) |
| 474 | - result[i].file.setLabel(labels[result[i].file.label()]); | |
| 456 | + result[i].file.set("Label", labelTable[originalLabels[i]]); | |
| 475 | 457 | return result; |
| 476 | 458 | } |
| 477 | 459 | |
| ... | ... | @@ -681,12 +663,17 @@ void Object::setProperty(const QString &name, const QString &value) |
| 681 | 663 | variant = value; |
| 682 | 664 | } |
| 683 | 665 | |
| 684 | - if (!QObject::setProperty(qPrintable(name), variant) && !type.isEmpty()) | |
| 685 | - qFatal("Failed to set %s::%s to: %s %s", | |
| 686 | - metaObject()->className(), qPrintable(name), qPrintable(value), qPrintable(type)); | |
| 666 | + setProperty(name, variant, !type.isEmpty()); | |
| 667 | +} | |
| 668 | + | |
| 669 | +void Object::setProperty(const QString &name, const QVariant &value, bool failOnError) | |
| 670 | +{ | |
| 671 | + if (!QObject::setProperty(qPrintable(name), value) && failOnError) | |
| 672 | + qFatal("Failed to set %s::%s to: %s", | |
| 673 | + metaObject()->className(), qPrintable(name), qPrintable(value.toString())); | |
| 687 | 674 | } |
| 688 | 675 | |
| 689 | -QStringList br::Object::parse(const QString &string, char split) | |
| 676 | +QStringList Object::parse(const QString &string, char split) | |
| 690 | 677 | { |
| 691 | 678 | return QtUtils::parse(string, split); |
| 692 | 679 | } |
| ... | ... | @@ -738,19 +725,21 @@ void Object::init(const File &file_) |
| 738 | 725 | } |
| 739 | 726 | |
| 740 | 727 | foreach (QString key, file.localKeys()) { |
| 741 | - const QString value = file.value(key).toString(); | |
| 728 | + const QVariant value = file.value(key); | |
| 729 | + const QString valueString = value.toString(); | |
| 742 | 730 | |
| 743 | 731 | if (key.startsWith(("_Arg"))) { |
| 744 | - int argument_number = key.mid(4).toInt(); | |
| 745 | - int target_idx = argument_number + firstAvailablePropertyIdx; | |
| 746 | - | |
| 747 | - if (target_idx >= metaObject()->propertyCount()) { | |
| 748 | - qWarning("too many arguments for transform, ignoring %s\n", qPrintable(value)); | |
| 732 | + int argumentNumber = key.mid(4).toInt(); | |
| 733 | + int targetIdx = argumentNumber + firstAvailablePropertyIdx; | |
| 734 | + if (targetIdx >= metaObject()->propertyCount()) { | |
| 735 | + qWarning("too many arguments for transform %s, ignoring %s", qPrintable(objectName()), qPrintable(valueString)); | |
| 749 | 736 | continue; |
| 750 | 737 | } |
| 751 | - key = metaObject()->property(target_idx).name(); | |
| 738 | + key = metaObject()->property(targetIdx).name(); | |
| 752 | 739 | } |
| 753 | - setProperty(key, value); | |
| 740 | + | |
| 741 | + if (valueString.isEmpty()) setProperty(key, value); // Set the property directly | |
| 742 | + else setProperty(key, valueString); // Parse the value first | |
| 754 | 743 | } |
| 755 | 744 | |
| 756 | 745 | init(); |
| ... | ... | @@ -1038,8 +1027,10 @@ MatrixOutput *MatrixOutput::make(const FileList &targetFiles, const FileList &qu |
| 1038 | 1027 | /* MatrixOutput - protected methods */ |
| 1039 | 1028 | QString MatrixOutput::toString(int row, int column) const |
| 1040 | 1029 | { |
| 1041 | - if (targetFiles[column] == "Label") | |
| 1042 | - return File::subject(data.at<float>(row,column)); | |
| 1030 | + if (targetFiles[column] == "Label") { | |
| 1031 | + const int label = data.at<float>(row,column); | |
| 1032 | + return Globals->subjects.key(label, QString::number(label)); | |
| 1033 | + } | |
| 1043 | 1034 | return QString::number(data.at<float>(row,column)); |
| 1044 | 1035 | } |
| 1045 | 1036 | |
| ... | ... | @@ -1085,153 +1076,6 @@ Gallery *Gallery::make(const File &file) |
| 1085 | 1076 | return gallery; |
| 1086 | 1077 | } |
| 1087 | 1078 | |
| 1088 | -static TemplateList Downsample(const TemplateList &templates, const Transform *transform) | |
| 1089 | -{ | |
| 1090 | - // Return early when no downsampling is required | |
| 1091 | - if ((transform->classes == std::numeric_limits<int>::max()) && | |
| 1092 | - (transform->instances == std::numeric_limits<int>::max()) && | |
| 1093 | - (transform->fraction >= 1)) | |
| 1094 | - return templates; | |
| 1095 | - | |
| 1096 | - const bool atLeast = transform->instances < 0; | |
| 1097 | - const int instances = abs(transform->instances); | |
| 1098 | - | |
| 1099 | - QList<int> allLabels = templates.labels<int>(); | |
| 1100 | - QList<int> uniqueLabels = allLabels.toSet().toList(); | |
| 1101 | - qSort(uniqueLabels); | |
| 1102 | - | |
| 1103 | - QMap<int,int> counts = templates.labelCounts(instances != std::numeric_limits<int>::max()); | |
| 1104 | - if ((instances != std::numeric_limits<int>::max()) && (transform->classes != std::numeric_limits<int>::max())) | |
| 1105 | - foreach (int label, counts.keys()) | |
| 1106 | - if (counts[label] < instances) | |
| 1107 | - counts.remove(label); | |
| 1108 | - uniqueLabels = counts.keys(); | |
| 1109 | - if ((transform->classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < transform->classes)) | |
| 1110 | - qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size()); | |
| 1111 | - | |
| 1112 | - Common::seedRNG(); | |
| 1113 | - QList<int> selectedLabels = uniqueLabels; | |
| 1114 | - if (transform->classes < uniqueLabels.size()) { | |
| 1115 | - std::random_shuffle(selectedLabels.begin(), selectedLabels.end()); | |
| 1116 | - selectedLabels = selectedLabels.mid(0, transform->classes); | |
| 1117 | - } | |
| 1118 | - | |
| 1119 | - TemplateList downsample; | |
| 1120 | - for (int i=0; i<selectedLabels.size(); i++) { | |
| 1121 | - const int selectedLabel = selectedLabels[i]; | |
| 1122 | - QList<int> indices; | |
| 1123 | - for (int j=0; j<allLabels.size(); j++) | |
| 1124 | - if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false))) | |
| 1125 | - indices.append(j); | |
| 1126 | - | |
| 1127 | - std::random_shuffle(indices.begin(), indices.end()); | |
| 1128 | - const int max = atLeast ? indices.size() : std::min(indices.size(), instances); | |
| 1129 | - for (int j=0; j<max; j++) | |
| 1130 | - downsample.append(templates.value(indices[j])); | |
| 1131 | - } | |
| 1132 | - | |
| 1133 | - if (transform->fraction < 1) { | |
| 1134 | - std::random_shuffle(downsample.begin(), downsample.end()); | |
| 1135 | - downsample = downsample.mid(0, downsample.size()*transform->fraction); | |
| 1136 | - } | |
| 1137 | - | |
| 1138 | - return downsample; | |
| 1139 | -} | |
| 1140 | - | |
| 1141 | -/*! | |
| 1142 | - * \ingroup transforms | |
| 1143 | - * \brief Clones the transform so that it can be applied independently. | |
| 1144 | - * | |
| 1145 | - * \em Independent transforms expect single-matrix templates. | |
| 1146 | - */ | |
| 1147 | -class Independent : public MetaTransform | |
| 1148 | -{ | |
| 1149 | - Q_PROPERTY(QList<Transform*> transforms READ get_transforms WRITE set_transforms STORED false) | |
| 1150 | - BR_PROPERTY(QList<Transform*>, transforms, QList<Transform*>()) | |
| 1151 | - | |
| 1152 | - public: | |
| 1153 | - /*! | |
| 1154 | - * \brief Independent | |
| 1155 | - * \param transform | |
| 1156 | - */ | |
| 1157 | - Independent(Transform *transform) | |
| 1158 | - { | |
| 1159 | - transform->setParent(this); | |
| 1160 | - transforms.append(transform); | |
| 1161 | - file = transform->file; | |
| 1162 | - trainable = transform->trainable; | |
| 1163 | - setObjectName(transforms.first()->objectName()); | |
| 1164 | - } | |
| 1165 | - | |
| 1166 | -private: | |
| 1167 | - Transform *clone() const | |
| 1168 | - { | |
| 1169 | - return new Independent(transforms.first()->clone()); | |
| 1170 | - } | |
| 1171 | - | |
| 1172 | - static void _train(Transform *transform, const TemplateList *data) | |
| 1173 | - { | |
| 1174 | - transform->train(*data); | |
| 1175 | - } | |
| 1176 | - | |
| 1177 | - void train(const TemplateList &data) | |
| 1178 | - { | |
| 1179 | - // Don't bother if the transform is untrainable | |
| 1180 | - if (!trainable) return; | |
| 1181 | - | |
| 1182 | - QList<TemplateList> templatesList; | |
| 1183 | - foreach (const Template &t, data) { | |
| 1184 | - if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) | |
| 1185 | - qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size()); | |
| 1186 | - while (templatesList.size() < t.size()) | |
| 1187 | - templatesList.append(TemplateList()); | |
| 1188 | - for (int i=0; i<t.size(); i++) | |
| 1189 | - templatesList[i].append(Template(t.file, t[i])); | |
| 1190 | - } | |
| 1191 | - | |
| 1192 | - while (transforms.size() < templatesList.size()) | |
| 1193 | - transforms.append(transforms.first()->clone()); | |
| 1194 | - | |
| 1195 | - for (int i=0; i<templatesList.size(); i++) | |
| 1196 | - templatesList[i] = Downsample(templatesList[i], transforms[i]); | |
| 1197 | - | |
| 1198 | - QFutureSynchronizer<void> futures; | |
| 1199 | - for (int i=0; i<templatesList.size(); i++) | |
| 1200 | - futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | |
| 1201 | - futures.waitForFinished(); | |
| 1202 | - } | |
| 1203 | - | |
| 1204 | - void project(const Template &src, Template &dst) const | |
| 1205 | - { | |
| 1206 | - dst.file = src.file; | |
| 1207 | - QList<Mat> mats; | |
| 1208 | - for (int i=0; i<src.size(); i++) { | |
| 1209 | - transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); | |
| 1210 | - mats.append(dst); | |
| 1211 | - dst.clear(); | |
| 1212 | - } | |
| 1213 | - dst.append(mats); | |
| 1214 | - } | |
| 1215 | - | |
| 1216 | - void store(QDataStream &stream) const | |
| 1217 | - { | |
| 1218 | - const int size = transforms.size(); | |
| 1219 | - stream << size; | |
| 1220 | - for (int i=0; i<size; i++) | |
| 1221 | - transforms[i]->store(stream); | |
| 1222 | - } | |
| 1223 | - | |
| 1224 | - void load(QDataStream &stream) | |
| 1225 | - { | |
| 1226 | - int size; | |
| 1227 | - stream >> size; | |
| 1228 | - while (transforms.size() < size) | |
| 1229 | - transforms.append(transforms.first()->clone()); | |
| 1230 | - for (int i=0; i<size; i++) | |
| 1231 | - transforms[i]->load(stream); | |
| 1232 | - } | |
| 1233 | -}; | |
| 1234 | - | |
| 1235 | 1079 | /* Transform - public methods */ |
| 1236 | 1080 | Transform::Transform(bool _independent, bool _trainable) |
| 1237 | 1081 | { |
| ... | ... | @@ -1279,8 +1123,17 @@ Transform *Transform::make(QString str, QObject *parent) |
| 1279 | 1123 | File f = "." + str; |
| 1280 | 1124 | Transform *transform = Factory<Transform>::make(f); |
| 1281 | 1125 | |
| 1282 | - if (transform->independent) | |
| 1283 | - transform = new Independent(transform); | |
| 1126 | + if (transform->independent) { | |
| 1127 | +// Transform *independentTransform = Factory<Transform>::make(".Independent"); | |
| 1128 | +// static_cast<QObject*>(independentTransform)->setProperty("transform", qVariantFromValue<void*>(transform)); | |
| 1129 | +// independentTransform->init(); | |
| 1130 | +// transform = independentTransform; | |
| 1131 | + | |
| 1132 | + File independent(".Independent"); | |
| 1133 | + independent.set("transform", qVariantFromValue<void*>(transform)); | |
| 1134 | + transform = Factory<Transform>::make(independent); | |
| 1135 | + } | |
| 1136 | + | |
| 1284 | 1137 | transform->setParent(parent); |
| 1285 | 1138 | return transform; |
| 1286 | 1139 | } | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -107,11 +107,11 @@ void reset_##NAME() { NAME = DEFAULT; } |
| 107 | 107 | * |
| 108 | 108 | * The br::File is one of the workhorse classes in OpenBR. |
| 109 | 109 | * It is typically used to store the path to a file on disk with associated metadata. |
| 110 | - * The ability to associate a hashtable of metadata with the file helps keep the API simple and stable while providing customizable behavior when appropriate. | |
| 110 | + * The ability to associate a metadata map with the file helps keep the API simple and stable while providing customizable behavior when appropriate. | |
| 111 | 111 | * |
| 112 | - * When querying the value of a metadata key, the value will first try to be resolved using the file's private metadata table. | |
| 113 | - * If the key does not exist in the local hashtable then it will be resolved using the properities in the global br::Context. | |
| 114 | - * This has the desirable effect that file metadata may optionally set globally using br::Context::set to operate on all files. | |
| 112 | + * When querying the value of a metadata key, the value will first try to be resolved using the file's private metadata. | |
| 113 | + * If the key does not exist in the local map then it will be resolved using the properities in the global br::Context. | |
| 114 | + * This has the desirable effect that file metadata may optionally be set globally using br::Context::set to operate on all files. | |
| 115 | 115 | * |
| 116 | 116 | * Files have a simple grammar that allow them to be converted to and from strings. |
| 117 | 117 | * If a string ends with a \c ] or \c ) then the text within the final \c [] or \c () are parsed as comma sperated metadata fields. |
| ... | ... | @@ -119,6 +119,13 @@ void reset_##NAME() { NAME = DEFAULT; } |
| 119 | 119 | * Fields within \c () are expected to have the format <tt>(value1, value2, ..., valueN)</tt> with the keys determined from the order of \c Q_PROPERTY. |
| 120 | 120 | * The rest of the string is assigned to #name. |
| 121 | 121 | * |
| 122 | + * The metadata keys \c Subject and \c Label have special significance in the system. | |
| 123 | + * \c Subject is a string specifying a unique identifier used to determine ground truth match/non-match. | |
| 124 | + * \c Label is a floating point value used for supervised learning. | |
| 125 | + * When the system needs labels for training, but only subjects are provided in the file metadata, the rule for generating labels is as follows. | |
| 126 | + * If the subject value can be converted to a float then do so and consider that the label. | |
| 127 | + * Otherwise, generate a unique integer ID for the string starting from zero and incrementing by one everytime another ID is needed. | |
| 128 | + * | |
| 122 | 129 | * Metadata keys fall into one of two categories: |
| 123 | 130 | * - \c camelCaseKeys are inputs that specify how to process the file. |
| 124 | 131 | * - \c Capitalized_Underscored_Keys are outputs computed from processing the file. |
| ... | ... | @@ -129,7 +136,8 @@ void reset_##NAME() { NAME = DEFAULT; } |
| 129 | 136 | * --- | ---- | ----------- |
| 130 | 137 | * separator | QString | Seperate #name into multiple files |
| 131 | 138 | * Index | int | Index of a template in a template list |
| 132 | - * Label | float | Classification/Regression class | |
| 139 | + * Subject | QString | Class name | |
| 140 | + * Label | float | Class value | |
| 133 | 141 | * Confidence | float | Classification/Regression quality |
| 134 | 142 | * FTE | bool | Failure to enroll |
| 135 | 143 | * FTO | bool | Failure to open |
| ... | ... | @@ -153,7 +161,7 @@ struct BR_EXPORT File |
| 153 | 161 | |
| 154 | 162 | File() {} |
| 155 | 163 | File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */ |
| 156 | - File(const QString &file, const QVariant &label) { init(file); set("Label", label); } /*!< \brief Construct a file from a string and assign a label. */ | |
| 164 | + File(const QString &file, const QVariant &subject) { init(file); set("Subject", subject); } /*!< \brief Construct a file from a string and assign a label. */ | |
| 157 | 165 | File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */ |
| 158 | 166 | inline operator QString() const { return name; } /*!< \brief Returns #name. */ |
| 159 | 167 | QString flat() const; /*!< \brief A stringified version of the file with metadata. */ |
| ... | ... | @@ -195,7 +203,7 @@ struct BR_EXPORT File |
| 195 | 203 | bool contains(const QString &key) const; /*!< \brief Returns \c true if the key has an associated value, \c false otherwise. */ |
| 196 | 204 | QVariant value(const QString &key) const; /*!< \brief Returns the value for the specified key. */ |
| 197 | 205 | static QVariant parse(const QString &value); /*!< \brief Try to convert the QString to a QPointF or QRectF if possible. */ |
| 198 | - void set(const QString &key, const QVariant &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ | |
| 206 | + inline void set(const QString &key, const QVariant &value) { m_metadata.insert(key, value); } /*!< \brief Insert or overwrite the metadata key with the specified value. */ | |
| 199 | 207 | void set(const QString &key, const QString &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ |
| 200 | 208 | inline void remove(const QString &key) { m_metadata.remove(key); } /*!< \brief Remove the metadata key. */ |
| 201 | 209 | |
| ... | ... | @@ -235,10 +243,8 @@ struct BR_EXPORT File |
| 235 | 243 | return variant.value<T>(); |
| 236 | 244 | } |
| 237 | 245 | |
| 238 | - static QString subject(int label); /*!< \brief Looks up the subject for the provided label. */ | |
| 239 | - inline QString subject() const { return subject(label()); } /*!< \brief Looks up the subject from the file's label. */ | |
| 246 | + QString subject() const; /*!< \brief Looks up the subject from the file's label. */ | |
| 240 | 247 | float label() const; /*!< \brief Convenience function for retrieving the file's \c Label. */ |
| 241 | - inline void setLabel(float label) { set("Label", label); } /*!< \brief Convenience function for setting the file's \c Label. */ | |
| 242 | 248 | inline bool failed() const { return getBool("FTE") || getBool("FTO"); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */ |
| 243 | 249 | |
| 244 | 250 | QList<QPointF> namedPoints() const; /*!< \brief Returns points convertible from metadata keys. */ |
| ... | ... | @@ -497,6 +503,7 @@ public: |
| 497 | 503 | QString argument(int index) const; /*!< \brief A string value for the argument at the specified index. */ |
| 498 | 504 | QString description() const; /*!< \brief Returns a string description of the object. */ |
| 499 | 505 | void setProperty(const QString &name, const QString &value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ |
| 506 | + void setProperty(const QString &name, const QVariant &value, bool failOnError = false); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ | |
| 500 | 507 | static QStringList parse(const QString &string, char split = ','); /*!< \brief Splits the string while respecting lexical scoping of <tt>()</tt>, <tt>[]</tt>, <tt>\<\></tt>, and <tt>{}</tt>. */ |
| 501 | 508 | |
| 502 | 509 | private: |
| ... | ... | @@ -633,7 +640,7 @@ public: |
| 633 | 640 | BR_PROPERTY(int, crossValidate, 0) |
| 634 | 641 | |
| 635 | 642 | QHash<QString,QString> abbreviations; /*!< \brief Used by br::Transform::make() to expand abbreviated algorithms into their complete definitions. */ |
| 636 | - QHash<QString,int> classes; /*!< \brief Used by classifiers to associate text class labels with unique integers IDs. */ | |
| 643 | + QHash<QString,int> subjects; /*!< \brief Used by classifiers to associate text class labels with unique integers IDs. */ | |
| 637 | 644 | QTime startTime; /*!< \brief Used to estimate timeRemaining(). */ |
| 638 | 645 | |
| 639 | 646 | /*! | ... | ... |
openbr/plugins/gallery.cpp
| ... | ... | @@ -37,6 +37,7 @@ namespace br |
| 37 | 37 | * \ingroup galleries |
| 38 | 38 | * \brief Weka ARFF file format. |
| 39 | 39 | * \author Josh Klontz \cite jklontz |
| 40 | + * http://weka.wikispaces.com/ARFF+%28stable+version%29 | |
| 40 | 41 | */ |
| 41 | 42 | class arffGallery : public Gallery |
| 42 | 43 | { |
| ... | ... | @@ -59,19 +60,16 @@ class arffGallery : public Gallery |
| 59 | 60 | "@RELATION OpenBR\n" |
| 60 | 61 | "\n"); |
| 61 | 62 | |
| 62 | - arffFile.write("@ATTRIBUTE filename STRING\n"); | |
| 63 | - arffFile.write(qPrintable("@ATTRIBUTE class {" + QStringList(Globals->classes.keys()).join(',') + "}\n")); | |
| 64 | - | |
| 65 | 63 | const int dimensions = t.m().rows * t.m().cols; |
| 66 | 64 | for (int i=0; i<dimensions; i++) |
| 67 | - arffFile.write(qPrintable("@ATTRIBUTE v" + QString::number(i) + " NUMERIC\n")); | |
| 65 | + arffFile.write(qPrintable("@ATTRIBUTE v" + QString::number(i) + " REAL\n")); | |
| 66 | + arffFile.write(qPrintable("@ATTRIBUTE class {" + QStringList(Globals->subjects.keys()).join(',') + "}\n")); | |
| 68 | 67 | |
| 69 | 68 | arffFile.write("\n@DATA\n"); |
| 70 | 69 | } |
| 71 | 70 | |
| 72 | - arffFile.write(qPrintable("'" + t.file.name + "',")); | |
| 73 | - arffFile.write(qPrintable("'" + t.file.subject() + "',")); | |
| 74 | - arffFile.write(qPrintable(OpenCVUtils::matrixToStringList(t).join(',')+"\n")); | |
| 71 | + arffFile.write(qPrintable(OpenCVUtils::matrixToStringList(t).join(','))); | |
| 72 | + arffFile.write(qPrintable(",'" + t.file.subject() + "'\n")); | |
| 75 | 73 | } |
| 76 | 74 | }; |
| 77 | 75 | |
| ... | ... | @@ -117,6 +115,8 @@ class galGallery : public Gallery |
| 117 | 115 | |
| 118 | 116 | void write(const Template &t) |
| 119 | 117 | { |
| 118 | + if (t.isEmpty() && t.file.isNull()) | |
| 119 | + return; | |
| 120 | 120 | stream << t; |
| 121 | 121 | } |
| 122 | 122 | }; |
| ... | ... | @@ -464,7 +464,7 @@ class csvGallery : public Gallery |
| 464 | 464 | static QString getCSVElement(const QString &key, const QVariant &value, bool header) |
| 465 | 465 | { |
| 466 | 466 | if ((key == "Label") && !header) { |
| 467 | - QString stringLabel = Globals->classes.key(value.value<int>()); | |
| 467 | + QString stringLabel = Globals->subjects.key(value.value<int>()); | |
| 468 | 468 | if (stringLabel.isEmpty()) return value.value<QString>(); |
| 469 | 469 | else return stringLabel; |
| 470 | 470 | } else if (value.canConvert<QString>()) { | ... | ... |
openbr/plugins/independent.cpp
0 โ 100644
| 1 | +#include <QFutureSynchronizer> | |
| 2 | +#include <QtConcurrentRun> | |
| 3 | + | |
| 4 | +#include "openbr_internal.h" | |
| 5 | +#include "openbr/core/common.h" | |
| 6 | + | |
| 7 | +using namespace cv; | |
| 8 | + | |
| 9 | +namespace br | |
| 10 | +{ | |
| 11 | + | |
| 12 | +static TemplateList Downsample(const TemplateList &templates, const Transform *transform) | |
| 13 | +{ | |
| 14 | + // Return early when no downsampling is required | |
| 15 | + if ((transform->classes == std::numeric_limits<int>::max()) && | |
| 16 | + (transform->instances == std::numeric_limits<int>::max()) && | |
| 17 | + (transform->fraction >= 1)) | |
| 18 | + return templates; | |
| 19 | + | |
| 20 | + const bool atLeast = transform->instances < 0; | |
| 21 | + const int instances = abs(transform->instances); | |
| 22 | + | |
| 23 | + QList<int> allLabels = templates.labels<int>(); | |
| 24 | + QList<int> uniqueLabels = allLabels.toSet().toList(); | |
| 25 | + qSort(uniqueLabels); | |
| 26 | + | |
| 27 | + QMap<int,int> counts = templates.labelCounts(instances != std::numeric_limits<int>::max()); | |
| 28 | + if ((instances != std::numeric_limits<int>::max()) && (transform->classes != std::numeric_limits<int>::max())) | |
| 29 | + foreach (int label, counts.keys()) | |
| 30 | + if (counts[label] < instances) | |
| 31 | + counts.remove(label); | |
| 32 | + uniqueLabels = counts.keys(); | |
| 33 | + if ((transform->classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < transform->classes)) | |
| 34 | + qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size()); | |
| 35 | + | |
| 36 | + Common::seedRNG(); | |
| 37 | + QList<int> selectedLabels = uniqueLabels; | |
| 38 | + if (transform->classes < uniqueLabels.size()) { | |
| 39 | + std::random_shuffle(selectedLabels.begin(), selectedLabels.end()); | |
| 40 | + selectedLabels = selectedLabels.mid(0, transform->classes); | |
| 41 | + } | |
| 42 | + | |
| 43 | + TemplateList downsample; | |
| 44 | + for (int i=0; i<selectedLabels.size(); i++) { | |
| 45 | + const int selectedLabel = selectedLabels[i]; | |
| 46 | + QList<int> indices; | |
| 47 | + for (int j=0; j<allLabels.size(); j++) | |
| 48 | + if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false))) | |
| 49 | + indices.append(j); | |
| 50 | + | |
| 51 | + std::random_shuffle(indices.begin(), indices.end()); | |
| 52 | + const int max = atLeast ? indices.size() : std::min(indices.size(), instances); | |
| 53 | + for (int j=0; j<max; j++) | |
| 54 | + downsample.append(templates.value(indices[j])); | |
| 55 | + } | |
| 56 | + | |
| 57 | + if (transform->fraction < 1) { | |
| 58 | + std::random_shuffle(downsample.begin(), downsample.end()); | |
| 59 | + downsample = downsample.mid(0, downsample.size()*transform->fraction); | |
| 60 | + } | |
| 61 | + | |
| 62 | + return downsample; | |
| 63 | +} | |
| 64 | + | |
| 65 | +/*! | |
| 66 | + * \ingroup transforms | |
| 67 | + * \brief Clones the transform so that it can be applied independently. | |
| 68 | + * \author Josh Klontz \cite jklontz | |
| 69 | + * \em Independent transforms expect single-matrix templates. | |
| 70 | + */ | |
| 71 | +class IndependentTransform : public MetaTransform | |
| 72 | +{ | |
| 73 | + Q_OBJECT | |
| 74 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform STORED false) | |
| 75 | + BR_PROPERTY(br::Transform*, transform, NULL) | |
| 76 | + | |
| 77 | + QList<Transform*> transforms; | |
| 78 | + | |
| 79 | + void init() | |
| 80 | + { | |
| 81 | + transforms.clear(); | |
| 82 | + if (transform == NULL) | |
| 83 | + return; | |
| 84 | + | |
| 85 | + transform->setParent(this); | |
| 86 | + transforms.append(transform); | |
| 87 | + file = transform->file; | |
| 88 | + trainable = transform->trainable; | |
| 89 | + setObjectName(transform->objectName()); | |
| 90 | + } | |
| 91 | + | |
| 92 | + Transform *clone() const | |
| 93 | + { | |
| 94 | + IndependentTransform *independentTransform = new IndependentTransform(); | |
| 95 | + independentTransform->transform = transform->clone(); | |
| 96 | + independentTransform->init(); | |
| 97 | + return independentTransform; | |
| 98 | + } | |
| 99 | + | |
| 100 | + static void _train(Transform *transform, const TemplateList *data) | |
| 101 | + { | |
| 102 | + transform->train(*data); | |
| 103 | + } | |
| 104 | + | |
| 105 | + void train(const TemplateList &data) | |
| 106 | + { | |
| 107 | + // Don't bother if the transform is untrainable | |
| 108 | + if (!trainable) return; | |
| 109 | + | |
| 110 | + QList<TemplateList> templatesList; | |
| 111 | + foreach (const Template &t, data) { | |
| 112 | + if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) | |
| 113 | + qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size()); | |
| 114 | + while (templatesList.size() < t.size()) | |
| 115 | + templatesList.append(TemplateList()); | |
| 116 | + for (int i=0; i<t.size(); i++) | |
| 117 | + templatesList[i].append(Template(t.file, t[i])); | |
| 118 | + } | |
| 119 | + | |
| 120 | + while (transforms.size() < templatesList.size()) | |
| 121 | + transforms.append(transform->clone()); | |
| 122 | + | |
| 123 | + for (int i=0; i<templatesList.size(); i++) | |
| 124 | + templatesList[i] = Downsample(templatesList[i], transforms[i]); | |
| 125 | + | |
| 126 | + QFutureSynchronizer<void> futures; | |
| 127 | + for (int i=0; i<templatesList.size(); i++) | |
| 128 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | |
| 129 | + futures.waitForFinished(); | |
| 130 | + } | |
| 131 | + | |
| 132 | + void project(const Template &src, Template &dst) const | |
| 133 | + { | |
| 134 | + dst.file = src.file; | |
| 135 | + QList<Mat> mats; | |
| 136 | + for (int i=0; i<src.size(); i++) { | |
| 137 | + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); | |
| 138 | + mats.append(dst); | |
| 139 | + dst.clear(); | |
| 140 | + } | |
| 141 | + dst.append(mats); | |
| 142 | + } | |
| 143 | + | |
| 144 | + void store(QDataStream &stream) const | |
| 145 | + { | |
| 146 | + const int size = transforms.size(); | |
| 147 | + stream << size; | |
| 148 | + for (int i=0; i<size; i++) | |
| 149 | + transforms[i]->store(stream); | |
| 150 | + } | |
| 151 | + | |
| 152 | + void load(QDataStream &stream) | |
| 153 | + { | |
| 154 | + int size; | |
| 155 | + stream >> size; | |
| 156 | + while (transforms.size() < size) | |
| 157 | + transforms.append(transform->clone()); | |
| 158 | + for (int i=0; i<size; i++) | |
| 159 | + transforms[i]->load(stream); | |
| 160 | + } | |
| 161 | +}; | |
| 162 | + | |
| 163 | +BR_REGISTER(Transform, IndependentTransform) | |
| 164 | + | |
| 165 | +} // namespace br | |
| 166 | + | |
| 167 | +#include "independent.moc" | ... | ... |
openbr/plugins/mask.cpp
openbr/plugins/meta.cpp
| ... | ... | @@ -15,6 +15,7 @@ |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <QFutureSynchronizer> |
| 18 | +#include <QRegularExpression> | |
| 18 | 19 | #include <QtConcurrentRun> |
| 19 | 20 | #include "openbr_internal.h" |
| 20 | 21 | #include "openbr/core/common.h" |
| ... | ... | @@ -440,7 +441,7 @@ private: |
| 440 | 441 | const QString &file = src.file; |
| 441 | 442 | if (cache.contains(file)) { |
| 442 | 443 | dst = cache[file]; |
| 443 | - dst.file.setLabel(src.file.label()); | |
| 444 | + dst.file.set("Label", src.file.label()); | |
| 444 | 445 | } else { |
| 445 | 446 | transform->project(src, dst); |
| 446 | 447 | cacheLock.lock(); | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -423,6 +423,51 @@ class RelabelTransform : public UntrainableMetaTransform |
| 423 | 423 | |
| 424 | 424 | BR_REGISTER(Transform, RelabelTransform) |
| 425 | 425 | |
| 426 | +/*! | |
| 427 | + * \ingroup transforms | |
| 428 | + * \brief Remove templates with the specified file extension. | |
| 429 | + * \author Josh Klontz \cite jklontz | |
| 430 | + */ | |
| 431 | +class RemoveTemplatesTransform : public UntrainableMetaTransform | |
| 432 | +{ | |
| 433 | + Q_OBJECT | |
| 434 | + Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) | |
| 435 | + BR_PROPERTY(QString, regexp, "") | |
| 436 | + | |
| 437 | + void project(const Template &src, Template &dst) const | |
| 438 | + { | |
| 439 | + const QRegularExpression re(regexp); | |
| 440 | + const QRegularExpressionMatch match = re.match(src.file.suffix()); | |
| 441 | + if (match.hasMatch()) dst = Template(); | |
| 442 | + else dst = src; | |
| 443 | + } | |
| 444 | +}; | |
| 445 | + | |
| 446 | +BR_REGISTER(Transform, RemoveTemplatesTransform) | |
| 447 | + | |
| 448 | +/*! | |
| 449 | + * \ingroup transforms | |
| 450 | + * \brief Remove template metadata with the specified key(s). | |
| 451 | + * \author Josh Klontz \cite jklontz | |
| 452 | + */ | |
| 453 | +class RemoveMetadataTransform : public UntrainableMetaTransform | |
| 454 | +{ | |
| 455 | + Q_OBJECT | |
| 456 | + Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) | |
| 457 | + BR_PROPERTY(QString, regexp, "") | |
| 458 | + | |
| 459 | + void project(const Template &src, Template &dst) const | |
| 460 | + { | |
| 461 | + dst = src; | |
| 462 | + const QRegularExpression re(regexp); | |
| 463 | + foreach (const QString &key, dst.file.localKeys()) | |
| 464 | + if (re.match(key).hasMatch()) | |
| 465 | + dst.file.remove(key); | |
| 466 | + } | |
| 467 | +}; | |
| 468 | + | |
| 469 | +BR_REGISTER(Transform, RemoveMetadataTransform) | |
| 470 | + | |
| 426 | 471 | } |
| 427 | 472 | |
| 428 | 473 | #include "misc.moc" | ... | ... |
openbr/plugins/output.cpp
| ... | ... | @@ -298,7 +298,7 @@ class rankOutput : public MatrixOutput |
| 298 | 298 | typedef QPair<float,int> Pair; |
| 299 | 299 | int rank = 1; |
| 300 | 300 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true)) { |
| 301 | - if(targetFiles[pair.second].get<QString>("Label") == queryFiles[i].get<QString>("Label")) { | |
| 301 | + if (targetFiles[pair.second].get<QString>("Subject") == queryFiles[i].get<QString>("Subject")) { | |
| 302 | 302 | ranks.append(rank); |
| 303 | 303 | positions.append(pair.second); |
| 304 | 304 | scores.append(pair.first); | ... | ... |
openbr/plugins/pixel.cpp
| ... | ... | @@ -122,7 +122,7 @@ class PerPixelClassifierTransform : public MetaTransform |
| 122 | 122 | } |
| 123 | 123 | cv::Mat labelMat = src.file.value("labels").value<cv::Mat>(); |
| 124 | 124 | uchar* plabel = labelMat.ptr(); |
| 125 | - temp.file.setLabel(plabel[index]); | |
| 125 | + temp.file.set("Label", plabel[index]); | |
| 126 | 126 | |
| 127 | 127 | if (orient){ |
| 128 | 128 | Template rotated; | ... | ... |
openbr/plugins/svm.cpp
| ... | ... | @@ -114,7 +114,7 @@ private: |
| 114 | 114 | void project(const Template &src, Template &dst) const |
| 115 | 115 | { |
| 116 | 116 | dst = src; |
| 117 | - dst.file.setLabel((svm.predict(src.m().reshape(0, 1)) - b)/a); | |
| 117 | + dst.file.set("Label", ((svm.predict(src.m().reshape(0, 1)) - b)/a)); | |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | 120 | void store(QDataStream &stream) const | ... | ... |
scripts/evalFaceRecognition-MEDS.sh
| ... | ... | @@ -18,14 +18,5 @@ fi |
| 18 | 18 | # Run Algorithm on MEDS |
| 19 | 19 | br -algorithm ${ALGORITHM} -path ../data/MEDS/img -compare ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml ${ALGORITHM}_MEDS.mtx -eval ${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv |
| 20 | 20 | |
| 21 | -# Evaluate other algorithms | |
| 22 | -for ALGORITHM in COTS | |
| 23 | -do | |
| 24 | - if [ ! -e Algorithm_Dataset/${ALGORITHM}_MEDS.csv ]; then | |
| 25 | - br -eval ../data/MEDS/simmat/${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv & | |
| 26 | - fi | |
| 27 | -done | |
| 28 | -wait | |
| 29 | - | |
| 30 | 21 | # Plot results |
| 31 | 22 | br -plot Algorithm_Dataset/*_MEDS.csv MEDS | ... | ... |