Commit 3d4c5b16c11a57f1859e7b691e84e6262dd5ca41
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
6 changed files
with
128 additions
and
37 deletions
openbr/core/bee.cpp
| @@ -239,9 +239,11 @@ void BEE::makeMask(const QString &targetInput, const QString &queryInput, const | @@ -239,9 +239,11 @@ void BEE::makeMask(const QString &targetInput, const QString &queryInput, const | ||
| 239 | FileList queries = (queryInput == ".") ? targets : TemplateList::fromGallery(queryInput).files(); | 239 | FileList queries = (queryInput == ".") ? targets : TemplateList::fromGallery(queryInput).files(); |
| 240 | int partitions = targets.first().get<int>("crossValidate"); | 240 | int partitions = targets.first().get<int>("crossValidate"); |
| 241 | if (partitions == 0) writeMask(makeMask(targets, queries), mask, targetInput, queryInput); | 241 | if (partitions == 0) writeMask(makeMask(targets, queries), mask, targetInput, queryInput); |
| 242 | - else for (int i=0; i<partitions; i++) { | ||
| 243 | - QString maskPartition = mask; | ||
| 244 | - writeMask(makeMask(targets, queries, i), maskPartition.insert(maskPartition.indexOf('.'),"Partition_" + QString::number(i)), targetInput, queryInput); | 242 | + else { |
| 243 | + if (!mask.contains("%1")) qFatal("Mask file name missing partition number place marker (%1)"); | ||
| 244 | + for (int i=0; i<partitions; i++) { | ||
| 245 | + writeMask(makeMask(targets, queries, i), mask.arg(i), targetInput, queryInput); | ||
| 246 | + } | ||
| 245 | } | 247 | } |
| 246 | } | 248 | } |
| 247 | 249 |
openbr/core/core.cpp
| @@ -202,10 +202,20 @@ struct AlgorithmCore | @@ -202,10 +202,20 @@ struct AlgorithmCore | ||
| 202 | retrieveOrEnroll(targetGallery, t, targetFiles); | 202 | retrieveOrEnroll(targetGallery, t, targetFiles); |
| 203 | retrieveOrEnroll(queryGallery, q, queryFiles); | 203 | retrieveOrEnroll(queryGallery, q, queryFiles); |
| 204 | 204 | ||
| 205 | - // Make multiple outputs if output[split] | 205 | + QList<int> partitionSizes; |
| 206 | + QList<File> outputFiles; | ||
| 207 | + if (output.contains("split")) { | ||
| 208 | + if (!output.fileName().contains("%1")) qFatal("Output file name missing split number place marker (%1)"); | ||
| 209 | + partitionSizes = output.getList<int>("split"); | ||
| 210 | + for (int i=0; i<partitionSizes.size(); i++) { | ||
| 211 | + File splitOutputFile = output.fileName().arg(i); | ||
| 212 | + outputFiles.append(splitOutputFile); | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + else outputFiles.append(output); | ||
| 206 | 216 | ||
| 207 | - // Split each | ||
| 208 | - QScopedPointer<Output> o(Output::make(output, targetFiles, queryFiles)); | 217 | + QList<Output*> outputs; |
| 218 | + foreach (const File &outputFile, outputFiles) outputs.append(Output::make(outputFile, targetFiles, queryFiles)); | ||
| 209 | 219 | ||
| 210 | if (distance.isNull()) qFatal("Null distance."); | 220 | if (distance.isNull()) qFatal("Null distance."); |
| 211 | Globals->currentStep = 0; | 221 | Globals->currentStep = 0; |
| @@ -218,26 +228,35 @@ struct AlgorithmCore | @@ -218,26 +228,35 @@ struct AlgorithmCore | ||
| 218 | queryBlock++; | 228 | queryBlock++; |
| 219 | TemplateList queries = q->readBlock(&queryDone); | 229 | TemplateList queries = q->readBlock(&queryDone); |
| 220 | 230 | ||
| 221 | - // Split queries by matrix into list of template lists if output[split] | ||
| 222 | - // foreach TemplateList in perMatrixQueries | 231 | + QList<TemplateList> queryPartitions; |
| 232 | + if (!partitionSizes.empty()) queryPartitions = queries.partition(partitionSizes); | ||
| 233 | + else queryPartitions.append(queries); | ||
| 223 | 234 | ||
| 224 | - int targetBlock = -1; | ||
| 225 | - bool targetDone = false; | ||
| 226 | - while (!targetDone) { | ||
| 227 | - targetBlock++; | ||
| 228 | - // Check if templates contain the same number of matrices | ||
| 229 | - // Split targets by matrix into templateList if output[split] for matrices i | 235 | + for (int i=0; i<queryPartitions.size(); i++) { |
| 236 | + int targetBlock = -1; | ||
| 237 | + bool targetDone = false; | ||
| 238 | + while (!targetDone) { | ||
| 239 | + targetBlock++; | ||
| 230 | 240 | ||
| 231 | - TemplateList targets = t->readBlock(&targetDone); | 241 | + TemplateList targets = t->readBlock(&targetDone); |
| 232 | 242 | ||
| 233 | - o->setBlock(queryBlock, targetBlock); | ||
| 234 | - distance->compare(targets, queries, o.data()); | 243 | + QList<TemplateList> targetPartitions; |
| 244 | + if (!partitionSizes.empty()) targetPartitions = targets.partition(partitionSizes); | ||
| 245 | + else targetPartitions.append(targets); | ||
| 235 | 246 | ||
| 236 | - Globals->currentStep += double(targets.size()) * double(queries.size()); | ||
| 237 | - Globals->printStatus(); | 247 | + if (queryPartitions[i].first().size() != targetPartitions[i].first().size()) qFatal("Query and target templates have different number of matrices."); |
| 248 | + | ||
| 249 | + outputs[i]->setBlock(queryBlock, targetBlock); | ||
| 250 | + distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]); | ||
| 251 | + | ||
| 252 | + Globals->currentStep += double(targets.size()) * double(queries.size()); | ||
| 253 | + Globals->printStatus(); | ||
| 254 | + } | ||
| 238 | } | 255 | } |
| 239 | } | 256 | } |
| 240 | 257 | ||
| 258 | + qDeleteAll(outputs); | ||
| 259 | + | ||
| 241 | const float speed = 1000 * Globals->totalSteps / Globals->startTime.elapsed() / std::max(1, abs(Globals->parallelism)); | 260 | const float speed = 1000 * Globals->totalSteps / Globals->startTime.elapsed() / std::max(1, abs(Globals->parallelism)); |
| 242 | if (!Globals->quiet && (Globals->totalSteps > 1)) fprintf(stderr, "\rSPEED=%.1e \n", speed); | 261 | if (!Globals->quiet && (Globals->totalSteps > 1)) fprintf(stderr, "\rSPEED=%.1e \n", speed); |
| 243 | Globals->totalSteps = 0; | 262 | Globals->totalSteps = 0; |
openbr/core/qtutils.cpp
| @@ -285,6 +285,28 @@ void QtUtils::checkArgsSize(const QString &name, const QStringList &args, int mi | @@ -285,6 +285,28 @@ void QtUtils::checkArgsSize(const QString &name, const QStringList &args, int mi | ||
| 285 | if (args.size() > max) qFatal("%s expects no more than %d arguments, got %d", qPrintable(name), max, args.size()); | 285 | if (args.size() > max) qFatal("%s expects no more than %d arguments, got %d", qPrintable(name), max, args.size()); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | +QPointF QtUtils::toPoint(const QString &string) | ||
| 289 | +{ | ||
| 290 | + QStringList values = string.split(','); | ||
| 291 | + if (values.size() == 2) { | ||
| 292 | + values[1].chop(1); | ||
| 293 | + QPointF point(values[0].mid(1).toFloat(), values[1].toFloat()); | ||
| 294 | + return point; | ||
| 295 | + } | ||
| 296 | + else qFatal("Failed to convert %s to QPoint format.", qPrintable(string)); | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +QRectF QtUtils::toRect(const QString &string) | ||
| 300 | +{ | ||
| 301 | + QStringList values = string.split(','); | ||
| 302 | + if (values.size() == 4) { | ||
| 303 | + values[3].chop(1); | ||
| 304 | + QRectF rect(values[0].mid(1).toFloat(), values[1].toFloat(), values[2].toFloat(), values[3].toFloat()); | ||
| 305 | + return rect; | ||
| 306 | + } | ||
| 307 | + else qFatal("Failed to convert %s to QRect format.", qPrintable(string)); | ||
| 308 | +} | ||
| 309 | + | ||
| 288 | bool QtUtils::runRScript(const QString &file) | 310 | bool QtUtils::runRScript(const QString &file) |
| 289 | { | 311 | { |
| 290 | QProcess RScript; | 312 | QProcess RScript; |
openbr/core/qtutils.h
| @@ -62,6 +62,8 @@ namespace QtUtils | @@ -62,6 +62,8 @@ namespace QtUtils | ||
| 62 | QString shortTextHash(QString string); | 62 | QString shortTextHash(QString string); |
| 63 | QStringList parse(QString args, char split = ','); | 63 | QStringList parse(QString args, char split = ','); |
| 64 | void checkArgsSize(const QString &name, const QStringList &args, int min, int max); | 64 | void checkArgsSize(const QString &name, const QStringList &args, int min, int max); |
| 65 | + QPointF toPoint(const QString &string); | ||
| 66 | + QRectF toRect(const QString &string); | ||
| 65 | 67 | ||
| 66 | /**** Process Utilities ****/ | 68 | /**** Process Utilities ****/ |
| 67 | bool runRScript(const QString &file); | 69 | bool runRScript(const QString &file); |
openbr/openbr_plugin.cpp
| @@ -55,11 +55,11 @@ QString File::flat() const | @@ -55,11 +55,11 @@ QString File::flat() const | ||
| 55 | if (value.isNull()) values.append(key); | 55 | if (value.isNull()) values.append(key); |
| 56 | else { | 56 | else { |
| 57 | if (QString(value.typeName()) == "QVariantList") { | 57 | if (QString(value.typeName()) == "QVariantList") { |
| 58 | - QStringList landmarks; | ||
| 59 | - foreach(const QVariant &landmark, qvariant_cast<QVariantList>(value)) { | ||
| 60 | - landmarks.append(QtUtils::toString(landmark)); | 58 | + QStringList variants; |
| 59 | + foreach(const QVariant &variant, qvariant_cast<QVariantList>(value)) { | ||
| 60 | + variants.append(QtUtils::toString(variant)); | ||
| 61 | } | 61 | } |
| 62 | - if (!landmarks.isEmpty()) values.append(key + "=[" + landmarks.join(", ") + "]"); | 62 | + if (!variants.isEmpty()) values.append(key + "=[" + variants.join(", ") + "]"); |
| 63 | } | 63 | } |
| 64 | else values.append(key + "=" + QtUtils::toString(value)); | 64 | else values.append(key + "=" + QtUtils::toString(value)); |
| 65 | } | 65 | } |
| @@ -147,26 +147,26 @@ void File::set(const QString &key, const QVariant &value) | @@ -147,26 +147,26 @@ void File::set(const QString &key, const QVariant &value) | ||
| 147 | m_metadata.insert(key, value); | 147 | m_metadata.insert(key, value); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | +// Note that we assume all values within a parameter list are the same type | ||
| 150 | void File::set(const QString &key, const QString &value) | 151 | void File::set(const QString &key, const QString &value) |
| 151 | { | 152 | { |
| 152 | if (value[0] == '[') /* QVariantList */ { | 153 | if (value[0] == '[') /* QVariantList */ { |
| 153 | QStringList values = value.mid(1, value.size()-2).split(", "); | 154 | QStringList values = value.mid(1, value.size()-2).split(", "); |
| 154 | - foreach(const QString &word, values) set(key, word); | ||
| 155 | - } | ||
| 156 | - else if (value[0] == '(') { | ||
| 157 | - QStringList values = value.split(','); | ||
| 158 | - if (values.size() == 2) /* QPointF */ { | ||
| 159 | - values[1].chop(1); | ||
| 160 | - QPointF point(values[0].mid(1).toFloat(), values[1].toFloat()); | ||
| 161 | - if (key != "Points") m_metadata.insert(key, point); | ||
| 162 | - else appendPoint(point); | 155 | + QList<QVariant> variants; |
| 156 | + if (values[0][0] == '(') /* List of Points or Rects */ { | ||
| 157 | + if (values[0].split(',').size() == 2) /* List of Points */ foreach(const QString &word, values) variants.append(QtUtils::toPoint(word)); | ||
| 158 | + else if (values[0].split(',').size() == 4) /* List of Rects */ foreach(const QString &word, values) variants.append(QtUtils::toRect(word)); | ||
| 159 | + else qFatal("Incorrect landmark format."); | ||
| 163 | } | 160 | } |
| 164 | - else /* QRectF */ { | ||
| 165 | - values[3].chop(1); | ||
| 166 | - QRectF rect(values[0].mid(1).toFloat(), values[1].toFloat(), values[2].toFloat(), values[3].toFloat()); | ||
| 167 | - if (key != "Rects") m_metadata.insert(key, rect); | ||
| 168 | - else appendRect(rect); | 161 | + else { |
| 162 | + foreach(const QString &word, values) variants.append(word.toFloat()); | ||
| 169 | } | 163 | } |
| 164 | + m_metadata.insert(key, variants); | ||
| 165 | + } | ||
| 166 | + else if (value[0] == '(') /* Point or Rect */ { | ||
| 167 | + if (value.split(',').size() == 2) /* QPointF */ m_metadata.insert(key, QtUtils::toPoint(value)); | ||
| 168 | + else if (value.split(',').size() == 4) /* QRectF */ m_metadata.insert(key, QtUtils::toRect(value)); | ||
| 169 | + else qFatal("Incorrect landmark format."); | ||
| 170 | } | 170 | } |
| 171 | else m_metadata.insert(key, value); | 171 | else m_metadata.insert(key, value); |
| 172 | } | 172 | } |
openbr/openbr_plugin.h
| @@ -207,6 +207,19 @@ struct BR_EXPORT File | @@ -207,6 +207,19 @@ struct BR_EXPORT File | ||
| 207 | return variant.value<T>(); | 207 | return variant.value<T>(); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | + /*!< \brief Returns a list of type T for the key, throwing an error if the key does not exist or if the value cannot be converted to the specified type. */ | ||
| 211 | + template <typename T> | ||
| 212 | + QList<T> getList(const QString &key) const | ||
| 213 | + { | ||
| 214 | + if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 215 | + QList<T> list; | ||
| 216 | + foreach (const QVariant &item, m_metadata[key].toList()) { | ||
| 217 | + if (item.canConvert<T>()) list.append(item.value<T>()); | ||
| 218 | + else qFatal("Failed to convert value for key %s.", qPrintable(key)); | ||
| 219 | + } | ||
| 220 | + return list; | ||
| 221 | + } | ||
| 222 | + | ||
| 210 | /*!< \brief Specialization for boolean type. */ | 223 | /*!< \brief Specialization for boolean type. */ |
| 211 | bool getBool(const QString &key) const; | 224 | bool getBool(const QString &key) const; |
| 212 | 225 | ||
| @@ -375,6 +388,39 @@ struct TemplateList : public QList<Template> | @@ -375,6 +388,39 @@ struct TemplateList : public QList<Template> | ||
| 375 | } | 388 | } |
| 376 | 389 | ||
| 377 | /*! | 390 | /*! |
| 391 | + * \brief Returns a #br::TemplateList containing templates with one matrix at the specified index \em index. | ||
| 392 | + */ | ||
| 393 | + QList<TemplateList> partition(const QList<int> &partitionSizes) const | ||
| 394 | + { | ||
| 395 | + int sum = 0; | ||
| 396 | + QList<TemplateList> partitions; partitions.reserve(partitionSizes.size()); | ||
| 397 | + | ||
| 398 | + for(int i=0; i<partitionSizes.size(); i++) { | ||
| 399 | + partitions.append(TemplateList()); | ||
| 400 | + sum+=partitionSizes[i]; | ||
| 401 | + } | ||
| 402 | + | ||
| 403 | + if (sum != first().size()) qFatal("Partition sizes do not span template matrices properly"); | ||
| 404 | + | ||
| 405 | + foreach (const Template &t, *this) { | ||
| 406 | + int index = 0; | ||
| 407 | + while (index < t.size()) { | ||
| 408 | + for (int i=0; i<partitionSizes.size(); i++) { | ||
| 409 | + Template newTemplate; | ||
| 410 | + for (int j=0; j<partitionSizes[i]; j++) { | ||
| 411 | + newTemplate.append(t[index]); | ||
| 412 | + index++; | ||
| 413 | + } | ||
| 414 | + // Append to the ith element of partitions | ||
| 415 | + partitions[i].append(newTemplate); | ||
| 416 | + } | ||
| 417 | + } | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + return partitions; | ||
| 421 | + } | ||
| 422 | + | ||
| 423 | + /*! | ||
| 378 | * \brief Returns #br::Template::file for each template in the list. | 424 | * \brief Returns #br::Template::file for each template in the list. |
| 379 | */ | 425 | */ |
| 380 | FileList files() const | 426 | FileList files() const |