diff --git a/app/examples/face_recognition_train.cpp b/app/examples/face_recognition_train.cpp new file mode 100644 index 0000000..01fe840 --- /dev/null +++ b/app/examples/face_recognition_train.cpp @@ -0,0 +1,55 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright 2012 The MITRE Corporation * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); * + * you may not use this file except in compliance with the License. * + * You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*! + * \ingroup cli + * \page cli_face_recognition_train Face Recognition Train + * \ref cpp_face_recognition_train "C++ Equivalent" + * \code + * $ br -algorithm 'Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)' -train ../data/ATT/img FaceRecognitionATT + * \endcode + */ + +//! [face_recognition_train] +#include + +int main(int argc, char *argv[]) +{ + br::Context::initialize(argc, argv); + + const QString trainedModelFile = "FaceRecognitionATT"; + if (QFile(trainedModelFile).exists()) + return 0; // Already trained + + br::Globals->algorithm = "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)"; + // br::Globals->algorithm = "4SF"; // Equally valid alternative. "4SF" is the abbreviation, see openbr/plugins/algorithms.cpp + + // Note the structure of the `../data/ATT/img` training data: + // - Subdirectory for each person + // - Multiple images per person + // Run `scripts/downloadDatasets.sh` to obtain these images if you haven't already. + const QString trainingData = "../data/ATT/img"; + + // After training completes you can use `FaceRecognitionATT` like `FaceRecognition`: + // $ br -algorithm FaceRecognitionATT + // provided the `FaceRecognitionATT` file is in your current working directory or in `share/openbr/models/algorithms`. + printf("Note: Training will take at least a few minutes to complete.\n"); + br::Train(trainingData, trainedModelFile); + + br::Context::finalize(); + return 0; +} +//! [face_recognition_train] diff --git a/data/ATT/README.md b/data/ATT/README.md new file mode 100644 index 0000000..2d31160 --- /dev/null +++ b/data/ATT/README.md @@ -0,0 +1,5 @@ +## AT&T Database of Faces +40 subjects with 10 images each. +* [Website](http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html) +* [Paper](http://www.cl.cam.ac.uk/Research/DTG/attarchive/abstracts.html#55) +* [Dataset](http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip) diff --git a/data/KTH/test_9ppl.xml b/data/KTH/test_9ppl.xml index c211650..2d2a85d 100644 --- a/data/KTH/test_9ppl.xml +++ b/data/KTH/test_9ppl.xml @@ -1,651 +1,237 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/data/KTH/train_16ppl.xml b/data/KTH/train_16ppl.xml index c4bdc71..799f563 100644 --- a/data/KTH/train_16ppl.xml +++ b/data/KTH/train_16ppl.xml @@ -1,1149 +1,417 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + + + + - - - - - - + + + + + + + + + + + + + + + + - + + + + + - - - - - - + + + + + + + + + + + + + + + + - + + + + + - - - - - - + + + + + + + + + + + + + + + + - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/data/README.md b/data/README.md index 5861118..1583ffb 100644 --- a/data/README.md +++ b/data/README.md @@ -1,17 +1,19 @@ # Datasets -* [BioID](BioID/README.md) +* __[AT&T](ATT/README.md)__ +* __[BioID](BioID/README.md)__ * [CUFS](CUFS/README.md) * [CUFSF](CUFSF/README.md) -* [HFB](HFB/README.md) +* [FDDB](FDDB/README.md) * [FERET](FERET/README.md) * [FRGC](FRGC/README.md) -* [LFW](LFW/LFW.md) -* [MEDS](MEDS/README.md) +* [HFB](HFB/README.md) +* __[KTH](KTH/README.md)__ +* __[LFW](LFW/LFW.md)__ +* __[MEDS](MEDS/README.md)__ * [MNIST](MNIST/README.md) * [PCSO](PCSO/README.md) -* [KTH](KTH/README.md) -* [FDDB](FDDB/README.md) -For both practical and legal reasons we only include images for some of the datasets in this repository. +For both practical and legal reasons we don't include images for the datasets in this repository. +Datasets in __bold__ can be downloaded automatically by running `scripts/downloadDatasets.sh`. Researchers should contact the respective owners of the other datasets in order to obtain a copy. The provided sigsets indicate how the images are expected to be arranged in directories, generally following the conventions established by the original authors. diff --git a/openbr/core/bee.h b/openbr/core/bee.h index 682192c..5bf384e 100644 --- a/openbr/core/bee.h +++ b/openbr/core/bee.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __BEE_H -#define __BEE_H +#ifndef BEE_BEE_H +#define BEE_BEE_H #include #include @@ -52,4 +52,4 @@ namespace BEE void combineMasks(const QStringList &inputMasks, const QString &outputMask, const QString &method); } -#endif // __BEE_H +#endif // BEE_BEE_H diff --git a/openbr/core/cluster.h b/openbr/core/cluster.h index 7e881f6..9d5ce7b 100644 --- a/openbr/core/cluster.h +++ b/openbr/core/cluster.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __CLUSTER_H -#define __CLUSTER_H +#ifndef BR_CLUSTER_H +#define BR_CLUSTER_H #include #include @@ -34,4 +34,4 @@ namespace br void WriteClusters(const Clusters &clusters, const QString &csv); } -#endif // __CLUSTER_H +#endif // BR_CLUSTER_H diff --git a/openbr/core/common.h b/openbr/core/common.h index 166ee45..bd0b603 100644 --- a/openbr/core/common.h +++ b/openbr/core/common.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __COMMON_H -#define __COMMON_H +#ifndef COMMON_COMMON_H +#define COMMON_COMMON_H #include #include @@ -332,4 +332,4 @@ V Downsample(V vals, int k) } -#endif // __COMMON_H +#endif // COMMON_COMMON_H diff --git a/openbr/core/eval.cpp b/openbr/core/eval.cpp index 6a2d7c7..9bb9886 100644 --- a/openbr/core/eval.cpp +++ b/openbr/core/eval.cpp @@ -79,19 +79,28 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) // Read similarity matrix QString target, query; - const Mat scores = BEE::readSimmat(simmat, &target, &query); + Mat scores; + if (simmat.endsWith(".mtx")) { + scores = BEE::readSimmat(simmat, &target, &query); + } else { + QScopedPointer format(Factory::make(simmat)); + scores = format->read(); + } // Read mask matrix Mat truth; if (mask.isEmpty()) { // Use the galleries specified in the similarity matrix + if (target.isEmpty()) qFatal("Unspecified target gallery."); + if (query.isEmpty()) qFatal("Unspecified query gallery."); truth = BEE::makeMask(TemplateList::fromGallery(target).files(), TemplateList::fromGallery(query).files()); } else { File maskFile(mask); maskFile.set("rows", scores.rows); maskFile.set("columns", scores.cols); - truth = BEE::readMask(maskFile); + QScopedPointer format(Factory::make(maskFile)); + truth = format->read(); } return Evaluate(scores, truth, csv); @@ -477,6 +486,7 @@ float EvalDetection(const QString &predictedGallery, const QString &truthGallery } averageOverlap = totalOverlap / keep; } + lines.append(QString("AverageOverlap,%1,").arg(QString::number(averageOverlap))); QtUtils::writeFile(csv, lines); qDebug("Average Overlap = %.3f", averageOverlap); diff --git a/openbr/core/eval.h b/openbr/core/eval.h index c58b60a..76881c5 100644 --- a/openbr/core/eval.h +++ b/openbr/core/eval.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __EVAL_H -#define __EVAL_H +#ifndef BR_EVAL_H +#define BR_EVAL_H #include #include @@ -32,5 +32,5 @@ namespace br void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = ""); } -#endif // __EVAL_H +#endif // BR_EVAL_H diff --git a/openbr/core/fuse.h b/openbr/core/fuse.h index 6521d58..7f6d690 100644 --- a/openbr/core/fuse.h +++ b/openbr/core/fuse.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __FUSE_H -#define __FUSE_H +#ifndef BR_FUSE_H +#define BR_FUSE_H #include #include @@ -25,4 +25,4 @@ namespace br void Fuse(const QStringList &inputSimmats, File mask, const QString &normalization, const QString &fusion, const QString &outputSimmat); } -#endif // __FUSE_H +#endif // BR_FUSE_H diff --git a/openbr/core/opencvutils.h b/openbr/core/opencvutils.h index 0e49fa0..8deeb49 100644 --- a/openbr/core/opencvutils.h +++ b/openbr/core/opencvutils.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __OPENCVUTILS_H -#define __OPENCVUTILS_H +#ifndef OPENCVUTILS_OPENCVUTILS_H +#define OPENCVUTILS_OPENCVUTILS_H #include #include @@ -157,4 +157,4 @@ public: } }; -#endif // __OPENCVUTILS_H +#endif // OPENCVUTILS_OPENCVUTILS_H diff --git a/openbr/core/plot.cpp b/openbr/core/plot.cpp index 7f7eecb..b053ae1 100644 --- a/openbr/core/plot.cpp +++ b/openbr/core/plot.cpp @@ -311,6 +311,7 @@ bool PlotDetection(const QStringList &files, const File &destination, bool show) "DiscretePR <- data[grep(\"DiscretePR\",data$Plot),-c(1)]\n" "ContinuousPR <- data[grep(\"ContinuousPR\",data$Plot),-c(1)]\n" "Overlap <- data[grep(\"Overlap\",data$Plot),-c(1)]\n" + "AverageOverlap <- data[grep(\"AverageOverlap\",data$Plot),-c(1)]\n" "rm(data)\n" "\n"); @@ -341,6 +342,12 @@ bool PlotDetection(const QStringList &files, const File &destination, bool show) (p.major.size > 1 ? (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg(p.minor.header, p.major.header) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.major.header)) : QString()) + QString(" + theme(aspect.ratio=1)\n\n"))); + p.file.write(qPrintable(QString("ggplot(AverageOverlap, aes(x=%1, y=%2, label=round(X,3)), main=\"Average Overlap\") + geom_text() + theme_minimal()").arg(p.minor.size > 1 ? p.minor.header : "'X'", p.major.size > 1 ? p.major.header : "'Y'") + + QString("%1%2\n\n").arg(p.minor.size > 1 ? "" : " + xlab(NULL)", p.major.size > 1 ? "" : "ylab(NULL)"))); + + p.file.write(qPrintable(QString("ggplot(AverageOverlap, aes(x=%1, y=%2, fill=X)) + geom_tile() + scale_fill_continuous(\"Average Overlap\") + theme_minimal()").arg(p.minor.size > 1 ? p.minor.header : "'X'", p.major.size > 1 ? p.major.header : "'Y'") + + QString("%1%2\n\n").arg(p.minor.size > 1 ? "" : " + xlab(NULL)", p.major.size > 1 ? "" : "ylab(NULL)"))); + return p.finalize(show); } diff --git a/openbr/core/plot.h b/openbr/core/plot.h index 7edd0fd..223f746 100644 --- a/openbr/core/plot.h +++ b/openbr/core/plot.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __PLOT_H -#define __PLOT_H +#ifndef BR_PLOT_H +#define BR_PLOT_H #include #include @@ -30,4 +30,4 @@ namespace br bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false); } -#endif // __PLOT_H +#endif // BR_PLOT_H diff --git a/openbr/core/qtutils.cpp b/openbr/core/qtutils.cpp index 1d3f748..a153853 100644 --- a/openbr/core/qtutils.cpp +++ b/openbr/core/qtutils.cpp @@ -186,8 +186,9 @@ QString find(const QString &file, const QString &alt) bool toBool(const QString &string) { bool ok; - bool result = (bool)string.toInt(&ok); if (!ok) qFatal("Expected integer value, got %s.", qPrintable(string)); - return result; + bool result = (string.toFloat(&ok) != 0.f); + if (ok) return result; + else return (string != "FALSE") && (string != "false") && (string != "F") && (string != "f"); } int toInt(const QString &string) diff --git a/openbr/core/qtutils.h b/openbr/core/qtutils.h index 7fa743a..320e2e8 100644 --- a/openbr/core/qtutils.h +++ b/openbr/core/qtutils.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __QTUTILS_H -#define __QTUTILS_H +#ifndef QTUTILS_QTUTILS_H +#define QTUTILS_QTUTILS_H #include #include @@ -78,4 +78,4 @@ namespace QtUtils float euclideanLength(const QPointF &point); } -#endif // __QTUTILS_H +#endif // QTUTILS_QTUTILS_H diff --git a/openbr/core/resource.h b/openbr/core/resource.h index d418e78..393a365 100644 --- a/openbr/core/resource.h +++ b/openbr/core/resource.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __RESOURCE_H -#define __RESOURCE_H +#ifndef BR_RESOURCE_H +#define BR_RESOURCE_H #include #include @@ -26,6 +26,9 @@ #include #include +namespace br +{ + template class ResourceMaker { @@ -97,4 +100,6 @@ public: } }; -#endif //__RESOURCE_H +} // namespace br + +#endif // BR_RESOURCE_H diff --git a/openbr/frvt2012.h b/openbr/frvt2012.h index 45c2d2c..945e9a9 100644 --- a/openbr/frvt2012.h +++ b/openbr/frvt2012.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef _FRVT2012_H_ -#define _FRVT2012_H_ +#ifndef FRVT2012_H +#define FRVT2012_H #include #include @@ -413,4 +413,4 @@ struct BR_EXPORT SdkEstimator : public Estimator /*! @}*/ -#endif // _FRVT2012_H_ +#endif // FRVT2012_H diff --git a/openbr/gui/algorithm.h b/openbr/gui/algorithm.h index d16a506..d6bc2a4 100644 --- a/openbr/gui/algorithm.h +++ b/openbr/gui/algorithm.h @@ -1,5 +1,5 @@ -#ifndef __ALGORITHM_H -#define __ALGORITHM_H +#ifndef BR_ALGORITHM_H +#define BR_ALGORITHM_H #include #include @@ -29,4 +29,4 @@ signals: } -#endif // __ALGORITHM_H +#endif // BR_ALGORITHM_H diff --git a/openbr/gui/classifier.h b/openbr/gui/classifier.h index 5263955..02a8c3d 100644 --- a/openbr/gui/classifier.h +++ b/openbr/gui/classifier.h @@ -1,5 +1,5 @@ -#ifndef __CLASSIFIER_H -#define __CLASSIFIER_H +#ifndef BR_CLASSIFIER_H +#define BR_CLASSIFIER_H #include #include @@ -33,4 +33,4 @@ signals: } // namespace br -#endif // __CLASSIFIER_H +#endif // BR_CLASSIFIER_H diff --git a/openbr/gui/dataset.h b/openbr/gui/dataset.h index 85e9727..af9dbe3 100644 --- a/openbr/gui/dataset.h +++ b/openbr/gui/dataset.h @@ -1,5 +1,5 @@ -#ifndef __DATASET_H -#define __DATASET_H +#ifndef BR_DATASET_H +#define BR_DATASET_H #include #include @@ -30,4 +30,4 @@ signals: } // namespace br -#endif // __DATASET_H +#endif // BR_DATASET_H diff --git a/openbr/gui/gallerytoolbar.h b/openbr/gui/gallerytoolbar.h index 1503a5b..87b4673 100644 --- a/openbr/gui/gallerytoolbar.h +++ b/openbr/gui/gallerytoolbar.h @@ -1,5 +1,5 @@ -#ifndef __GALLERYTOOLBAR_H -#define __GALLERYTOOLBAR_H +#ifndef BR_GALLERYTOOLBAR_H +#define BR_GALLERYTOOLBAR_H #include #include @@ -55,4 +55,4 @@ signals: } // namespace br -#endif // GALLERYTOOLBAR_H +#endif // BR_GALLERYTOOLBAR_H diff --git a/openbr/gui/galleryviewer.h b/openbr/gui/galleryviewer.h index 29ccfa8..de52ae9 100644 --- a/openbr/gui/galleryviewer.h +++ b/openbr/gui/galleryviewer.h @@ -1,5 +1,5 @@ -#ifndef GALLERYVIEWER_H -#define GALLERYVIEWER_H +#ifndef BR_GALLERYVIEWER_H +#define BR_GALLERYVIEWER_H #include #include @@ -30,4 +30,4 @@ public slots: } // namespace br -#endif // GALLERYVIEWER_H +#endif // BR_GALLERYVIEWER_H diff --git a/openbr/gui/help.h b/openbr/gui/help.h index 9afa8c8..280f0fb 100644 --- a/openbr/gui/help.h +++ b/openbr/gui/help.h @@ -1,5 +1,5 @@ -#ifndef HELP_H -#define HELP_H +#ifndef BR_HELP_H +#define BR_HELP_H #include #include @@ -27,4 +27,4 @@ public slots: } // namespace br -#endif // HELP_H +#endif // BR_HELP_H diff --git a/openbr/gui/imageviewer.h b/openbr/gui/imageviewer.h index e0467d2..072f33c 100644 --- a/openbr/gui/imageviewer.h +++ b/openbr/gui/imageviewer.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __IMAGEVIEWER_H -#define __IMAGEVIEWER_H +#ifndef BR_IMAGEVIEWER_H +#define BR_IMAGEVIEWER_H #include #include @@ -61,4 +61,4 @@ private slots: } // namespace br -#endif // __IMAGEVIEWER_H +#endif // BR_IMAGEVIEWER_H diff --git a/openbr/gui/progress.h b/openbr/gui/progress.h index b8e5a4e..a4b4dd2 100644 --- a/openbr/gui/progress.h +++ b/openbr/gui/progress.h @@ -1,5 +1,5 @@ -#ifndef __PROGRESS_H -#define __PROGRESS_H +#ifndef BR_PROGRESS_H +#define BR_PROGRESS_H #include #include @@ -28,4 +28,4 @@ private slots: } -#endif // __PROGRESS_H +#endif // BR_PROGRESS_H diff --git a/openbr/gui/score.h b/openbr/gui/score.h index 8d1f4ea..43a48b4 100644 --- a/openbr/gui/score.h +++ b/openbr/gui/score.h @@ -1,5 +1,5 @@ -#ifndef __SCORE_H -#define __SCORE_H +#ifndef BR_SCORE_H +#define BR_SCORE_H #include #include @@ -21,4 +21,4 @@ public slots: } -#endif // __SCORE_H +#endif // BR_SCORE_H diff --git a/openbr/gui/splashscreen.h b/openbr/gui/splashscreen.h index 7c8cf8c..45d0332 100644 --- a/openbr/gui/splashscreen.h +++ b/openbr/gui/splashscreen.h @@ -1,5 +1,5 @@ -#ifndef __SPLASHSCREEN_H -#define __SPLASHSCREEN_H +#ifndef BR_SPLASHSCREEN_H +#define BR_SPLASHSCREEN_H #include #include @@ -28,4 +28,4 @@ private slots: } // namespace br -#endif // __SPLASHSCREEN_H +#endif // BR_SPLASHSCREEN_H diff --git a/openbr/gui/templatemetadata.h b/openbr/gui/templatemetadata.h index 4b62078..95568c8 100644 --- a/openbr/gui/templatemetadata.h +++ b/openbr/gui/templatemetadata.h @@ -1,5 +1,5 @@ -#ifndef __TEMPLATEMETADATA_H -#define __TEMPLATEMETADATA_H +#ifndef BR_TEMPLATEMETADATA_H +#define BR_TEMPLATEMETADATA_H #include #include @@ -43,4 +43,4 @@ public slots: } // namespace br -#endif // TEMPLATEMETADATA_H +#endif // BR_TEMPLATEMETADATA_H diff --git a/openbr/gui/templateviewer.h b/openbr/gui/templateviewer.h index 78f9b0d..90b04bc 100644 --- a/openbr/gui/templateviewer.h +++ b/openbr/gui/templateviewer.h @@ -1,5 +1,5 @@ -#ifndef __TEMPLATEVIEWER_H -#define __TEMPLATEVIEWER_H +#ifndef BR_TEMPLATEVIEWER_H +#define BR_TEMPLATEVIEWER_H #include #include @@ -58,4 +58,4 @@ signals: } -#endif // TEMPLATEVIEWER_H +#endif // BR_TEMPLATEVIEWER_H diff --git a/openbr/gui/templateviewergrid.h b/openbr/gui/templateviewergrid.h index 4db0205..9685c29 100644 --- a/openbr/gui/templateviewergrid.h +++ b/openbr/gui/templateviewergrid.h @@ -1,5 +1,5 @@ -#ifndef __TEMPLATE_VIEWER_GRID_H -#define __TEMPLATE_VIEWER_GRID_H +#ifndef BR_TEMPLATEVIEWERGRID_H +#define BR_TEMPLATEVIEWERGRID_H #include #include @@ -35,4 +35,4 @@ signals: } // namespace br -#endif // __TEMPLATE_VIEWER_GRID_H +#endif // BR_TEMPLATEVIEWERGRID_H diff --git a/openbr/gui/transformeditor.h b/openbr/gui/transformeditor.h index 390add3..e9888df 100644 --- a/openbr/gui/transformeditor.h +++ b/openbr/gui/transformeditor.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __TRANSFORMEDITOR_H -#define __TRANSFORMEDITOR_H +#ifndef BR_TRANSFORMEDITOR_H +#define BR_TRANSFORMEDITOR_H #include #include @@ -38,4 +38,4 @@ public: } // namespace br -#endif // __TRANSFORMEDITOR_H +#endif // BR_TRANSFORMEDITOR_H diff --git a/openbr/gui/transformlisteditor.h b/openbr/gui/transformlisteditor.h index b7d2c4f..f8be8ac 100644 --- a/openbr/gui/transformlisteditor.h +++ b/openbr/gui/transformlisteditor.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __TRANSFORMLISTEDITOR_H -#define __TRANSFORMLISTEDITOR_H +#ifndef BR_TRANSFORMLISTEDITOR_H +#define BR_TRANSFORMLISTEDITOR_H #include #include @@ -43,4 +43,4 @@ private slots: } // namespace br -#endif // __TRANSFORMLISTEDITOR_H +#endif // BR_TRANSFORMLISTEDITOR_H diff --git a/openbr/gui/utility.h b/openbr/gui/utility.h index 2a6a40a..f4c3d60 100644 --- a/openbr/gui/utility.h +++ b/openbr/gui/utility.h @@ -1,9 +1,9 @@ -#ifndef UTILITY_H -#define UTILITY_H +#ifndef BR_UTILITY_H +#define BR_UTILITY_H #include #include QImage toQImage(const cv::Mat &mat); -#endif // UTILITY_H +#endif // BR_UTILITY_H diff --git a/openbr/gui/view.h b/openbr/gui/view.h index 5acd8fd..ce21c71 100644 --- a/openbr/gui/view.h +++ b/openbr/gui/view.h @@ -1,5 +1,5 @@ -#ifndef VIEW_H -#define VIEW_H +#ifndef BR_VIEW_H +#define BR_VIEW_H #include #include @@ -34,4 +34,4 @@ signals: } // namespace br -#endif // VIEW_H +#endif // BR_VIEW_H diff --git a/openbr/openbr.cpp b/openbr/openbr.cpp index 6703a09..9c89c9c 100644 --- a/openbr/openbr.cpp +++ b/openbr/openbr.cpp @@ -72,7 +72,7 @@ float br_eval(const char *simmat, const char *mask, const char *csv) return Evaluate(simmat, mask, csv); } -void br_eval_classification(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property, const char * truth_property) +void br_eval_classification(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property, const char *truth_property) { EvalClassification(predicted_gallery, truth_gallery, predicted_property, truth_property); } @@ -92,7 +92,7 @@ float br_eval_landmarking(const char *predicted_gallery, const char *truth_galle return EvalLandmarking(predicted_gallery, truth_gallery, csv, normalization_index_a, normalization_index_b); } -void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char * predicted_property, const char * truth_property) +void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property, const char *truth_property) { EvalRegression(predicted_gallery, truth_gallery, predicted_property, truth_property); } diff --git a/openbr/openbr.h b/openbr/openbr.h index c999b86..b91a7ac 100644 --- a/openbr/openbr.h +++ b/openbr/openbr.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __OPENBR_H -#define __OPENBR_H +#ifndef OPENBR_H +#define OPENBR_H #include @@ -41,18 +41,6 @@ extern "C" { * \section managed_return_value Managed Return Value * Memory for const char* return values is managed internally and guaranteed until the next call to the function. * - * \section python_api Python API - * A Python API is available via SWIG. - * \code - * $ ls include/br/python - * \endcode - * - * \section java_api Java API - * A Java API is available via SWIG. - * \code - * $ ls include/br/java - * \endcode - * * \section examples Examples * - \ref c_face_recognition_evaluation * @@ -148,8 +136,10 @@ BR_EXPORT float br_eval(const char *simmat, const char *mask, const char *csv = * \brief Evaluates and prints classification accuracy to terminal. * \param predicted_gallery The predicted br::Gallery. * \param truth_gallery The ground truth br::Gallery. + * \param predicted_property (Optional) which metadata key to use from predicted_gallery. + * \param truth_property (Optional) which metadata key to use from truth_gallery. */ -BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char *truth_gallery, const char * predicted_property="", const char * truth_property=""); +BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property = "", const char *truth_property = ""); /*! * \brief Evaluates and prints clustering accuracy to the terminal. @@ -182,8 +172,10 @@ BR_EXPORT float br_eval_landmarking(const char *predicted_gallery, const char *t * \brief Evaluates regression accuracy to disk. * \param predicted_gallery The predicted br::Gallery. * \param truth_gallery The ground truth br::Gallery. + * \param predicted_property (Optional) which metadata key to use from predicted_gallery. + * \param truth_property (Optional) which metadata key to use from truth_gallery. */ -BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char * predicted_property="", const char * truth_property=""); +BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property = "", const char *truth_property = ""); /*! * \brief Wraps br::Context::finalize() @@ -267,7 +259,7 @@ BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *im * * OpenBR uses file and folder names to automatically determine the plot legend. * For example, let's consider the case where three algorithms (A, B, & C) were each evaluated on two datasets (Y & Z). - * The suggested way to plot these experiments on the same graph is to create a folder named Algorithm_Dataset that contains the six .csv files produced by \ref br_eval: A_Y.csv, A_Z.csv, B_Y.csv, B_Z.csv, C_Y.csv, & C_Z.csv. + * The suggested way to plot these experiments on the same graph is to create a folder named Algorithm_Dataset that contains the six .csv files produced by br_eval A_Y.csv, A_Z.csv, B_Y.csv, B_Z.csv, C_Y.csv, & C_Z.csv. * The '_' character plays a special role in determining the legend title(s) and value(s). * In this case, A, B, & C will be identified as different values of type Algorithm, and each will be assigned its own color; Y & Z will be identified as different values of type Dataset, and each will be assigned its own line style. * @@ -291,6 +283,8 @@ BR_EXPORT bool br_plot(int num_files, const char *files[], const char *destinati * -# Discrete Precision Recall (DiscretePR) * -# Continuous Precision Recall (ContinuousPR) * -# Bounding Box Overlap Histogram (Overlap) + * -# Average Overlap Table (AverageOverlap) + * -# Average Overlap Heatmap (AverageOverlap) * * Detection accuracy is measured with overlap fraction = bounding box intersection / union. * When computing discrete curves, an overlap >= 0.5 is considered a true positive, otherwise it is considered a false negative. @@ -421,4 +415,4 @@ BR_EXPORT const char *br_version(); } #endif -#endif // __OPENBR_H +#endif // OPENBR_H diff --git a/openbr/openbr_export.cpp b/openbr/openbr_export.cpp index dac8526..482c774 100644 --- a/openbr/openbr_export.cpp +++ b/openbr/openbr_export.cpp @@ -29,7 +29,7 @@ * \section get_started Get Started * - \ref introduction - A high-level technical overview of OpenBR. * - \ref installation - A hacker's guide to building, editing, and running OpenBR. - * - \ref qmake_integration - Add OpenBR to your Qt .pro project. + * - \ref examples - Source code illustrating common use cases. * * \section learn_more Learn More * - \ref algorithm_grammar - How algorithms are constructed from string descriptions. @@ -37,6 +37,7 @@ * - \ref c_sdk - High-level API for running algorithms and evaluating results. * - \ref cpp_plugin_sdk - Plugin API for extending OpenBR functionality. * - \ref bee - A NIST standard for evaluating biometric algorithms. + * - \ref qmake_integration - Add OpenBR to your Qt .pro project. */ /*! @@ -331,7 +332,7 @@ $ br -help * \code * $ sudo apt-get install cmake cmake-curses-gui * \endcode - * -# Download OpenCV 2.4.5 + * -# Download OpenCV 2.4.5, note this * \code * $ cd ~/Downloads * $ tar -xf opencv-2.4.5.tar.gz diff --git a/openbr/openbr_export.h b/openbr/openbr_export.h index f039ec9..4bde0f8 100644 --- a/openbr/openbr_export.h +++ b/openbr/openbr_export.h @@ -14,25 +14,21 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __OPENBR_EXPORT_H -#define __OPENBR_EXPORT_H +#ifndef OPENBR_EXPORT_H +#define OPENBR_EXPORT_H -#if defined SWIG -# define BR_EXPORT extern +#if defined BR_LIBRARY +# if defined _WIN32 || defined __CYGWIN__ +# define BR_EXPORT __declspec(dllexport) +# else +# define BR_EXPORT __attribute__((visibility("default"))) +# endif #else -# if defined BR_LIBRARY -# if defined _WIN32 || defined __CYGWIN__ -# define BR_EXPORT __declspec(dllexport) -# else -# define BR_EXPORT __attribute__((visibility("default"))) -# endif +# if defined _WIN32 || defined __CYGWIN__ +# define BR_EXPORT __declspec(dllimport) # else -# if defined _WIN32 || defined __CYGWIN__ -# define BR_EXPORT __declspec(dllimport) -# else -# define BR_EXPORT -# endif +# define BR_EXPORT # endif #endif -#endif // __OPENBR_EXPORT_H +#endif // OPENBR_EXPORT_H diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 31cdb73..ccfae5c 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -996,9 +996,9 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte switch (type) { case QtWarningMsg: txt = QString("Warning: %1\n" ).arg(msg); break; case QtCriticalMsg: txt = QString("Critical: %1\n").arg(msg); break; - default: txt = QString("Fatal: %1\n" ).arg(msg); + default: txt = QString("Fatal: %1\n" ).arg(msg); break; } - txt += " File: " + QString(context.file) + "\n Function: " + QString(context.function) + "\n Line: " + QString::number(context.line) + "\n"; + txt += " SDK Path: " + Globals->sdkPath + "\n File: " + QString(context.file) + "\n Function: " + QString(context.function) + "\n Line: " + QString::number(context.line) + "\n"; } std::cerr << txt.toStdString(); @@ -1225,6 +1225,26 @@ TemplateEvent * Transform::getEvent(const QString & name) return NULL; } +void Transform::train(const TemplateList &data) +{ + if (!trainable) { + qWarning("Train called on untrainable transform %s", this->metaObject()->className()); + return; + } + QList input; + input.append(data); + train(input); +} + +void Transform::train(const QList &data) +{ + TemplateList combined; + foreach(const TemplateList & set, data) { + combined.append(set); + } + train(combined); +} + /* Distance - public methods */ Distance *Distance::make(QString str, QObject *parent) { diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index aa808c6..f33d00c 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -14,8 +14,8 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __OPENBR_PLUGIN_H -#define __OPENBR_PLUGIN_H +#ifndef BR_OPENBR_PLUGIN_H +#define BR_OPENBR_PLUGIN_H #ifdef __cplusplus @@ -74,6 +74,10 @@ * \ref cli_face_recognition_search "Command Line Interface Equivalent" * \snippet app/examples/face_recognition_search.cpp face_recognition_search * + * \subsection cpp_face_recognition_train Face Recognition Train + * \ref cli_face_recognition_train "Command Line Interface Equivalent" + * \snippet app/examples/face_recognition_train.cpp face_recognition_train + * * \subsection cpp_age_estimation Age Estimation * \ref cli_age_estimation "Command Line Interface Equivalent" * \snippet app/examples/age_estimation.cpp age_estimation @@ -1037,7 +1041,7 @@ private: /*! * \brief For asynchronous events during template projection. - * \see #Transform::getEvent + * \see Transform::getEvent */ class TemplateEvent : public QObject { @@ -1073,17 +1077,41 @@ public: static QSharedPointer fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's transform. */ virtual Transform *clone() const; /*!< \brief Copy the transform. */ - virtual void train(const TemplateList &data) = 0; /*!< \brief Train the transform. */ - virtual void project(const Template &src, Template &dst) const = 0; /*!< \brief Apply the transform. */ - virtual void project(const TemplateList &src, TemplateList &dst) const; /*!< \brief Apply the transform. */ - /*!< \brief Apply the transform, may update the transform's internal state */ + /*!< \brief Train the transform. */ + virtual void train(const TemplateList &data); + + /*!< \brief Train the transform, separate list items represent the way calls to project would be broken up + * Transforms that have to call train on another transform should implement train(QList), the strucutre of the + * list should mirror the calls that would be made to project by the parent transform. For example, DistributeTemplates + * would make a separate project call for each template it receives, and therefore sets the QList to contain single item + * template lists before passing it on. + * This version of train(QList) is appropriate for transforms that perform training on themselves, and don't call train + * on other transforms. It combines everything in data into a single TemplateList, then calls train(TemplateList) + */ + virtual void train(const QList &data); + + /*!< \brief Apply the transform to a single template. Typically used by independent transforms */ + virtual void project(const Template &src, Template &dst) const = 0; + /*!< \brief Apply the transform, taking the full template list as input. + * A TemplateList is what is typically passed from transform to transform. Transforms that just + * need to operatoe on a single template at a time (and want to output exactly 1 template) can implement + * project(template), but transforms that want to change the structure of the TemplateList (such as flatten), or + * or output more or less than one template (e.g. detection methods) should implement project(TemplateList) directly + */ + virtual void project(const TemplateList &src, TemplateList &dst) const; + + /*!< \brief Apply the transform to a single template, may update the transform's internal state + * By default, just call project, we can always call a const function from a non-const function. + * If a transform implements projectUpdate, it should report true to timeVarying so that it can be + * handled correctly by e.g. Stream. + */ virtual void projectUpdate(const Template &src, Template &dst) { project(src, dst); } - /*!< \brief Apply the transform, may update the transform's internal state */ + /*!< \brief Apply the transform, may update the transform's internal state. */ virtual void projectUpdate(const TemplateList &src, TemplateList &dst) { project(src,dst); @@ -1145,7 +1173,9 @@ public: * \brief Perform the minimum amount of work necessary to make a * transform that can be used safely from a different thread than this * transform. For transforms that aren't time-varying, nothing needs to be - * done, returning this is sufficient. + * done, returning this is sufficient. Time varying transforms should implement this method + * and copy enough of their state that projectUpdate can safely be called on the original + * instance, and the copy concurrently. */ virtual Transform * smartCopy() { return this;} @@ -1292,4 +1322,4 @@ Q_DECLARE_METATYPE(QList) #endif // __cplusplus -#endif // __OPENBR_PLUGIN_H +#endif // BR_OPENBR_PLUGIN_H diff --git a/openbr/plugins/algorithms.cpp b/openbr/plugins/algorithms.cpp index d770730..2bf0895 100644 --- a/openbr/plugins/algorithms.cpp +++ b/openbr/plugins/algorithms.cpp @@ -44,6 +44,7 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+Bin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+Bin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1"); Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)"); + Globals->abbreviations.insert("4SF", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)"); // Video Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); diff --git a/openbr/plugins/cluster.cpp b/openbr/plugins/cluster.cpp index 3a9b577..24bea1f 100644 --- a/openbr/plugins/cluster.cpp +++ b/openbr/plugins/cluster.cpp @@ -91,12 +91,14 @@ class KNNTransform : public Transform Q_PROPERTY(int numSubjects READ get_numSubjects WRITE set_numSubjects RESET reset_numSubjects STORED false) Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false) + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) BR_PROPERTY(int, k, 1) BR_PROPERTY(br::Distance*, distance, NULL) BR_PROPERTY(bool, weighted, false) BR_PROPERTY(int, numSubjects, 1) BR_PROPERTY(QString, inputVariable, "Label") BR_PROPERTY(QString, outputVariable, "KNN") + BR_PROPERTY(QString, galleryName, "") TemplateList gallery; @@ -126,6 +128,7 @@ class KNNTransform : public Transform } dst.file.set(outputVariable, subjects.size() > 1 ? "[" + subjects.join(",") + "]" : subjects.first()); + dst.file.set("Nearest", gallery[sortedScores[0].second].file.name); } void store(QDataStream &stream) const @@ -137,11 +140,69 @@ class KNNTransform : public Transform { stream >> gallery; } + + void init() + { + if (!galleryName.isEmpty()) + gallery = TemplateList::fromGallery(galleryName); + } }; BR_REGISTER(Transform, KNNTransform) +/*! + * \ingroup transforms + * \brief Chooses k random points to be centroids. + * \author Austin Blanton \cite imaus10 + * \see KMeansTransform + */ +class RandomCentroidsTransform : public Transform +{ + Q_OBJECT + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) + BR_PROPERTY(int, kTrain, 256) + BR_PROPERTY(int, kSearch, 1) + + Mat centers; + mutable QScopedPointer index; + mutable QMutex mutex; + + void reindex() + { + index.reset(new flann::Index(centers, flann::LinearIndexParams())); + } + + void train(const TemplateList &data) + { + Mat flat = OpenCVUtils::toMatByRow(data.data()); + QList sample = Common::RandSample(kTrain, flat.rows, 0, true); + foreach (const int &idx, sample) + centers.push_back(flat.row(idx)); + reindex(); + } + + void project(const Template &src, Template &dst) const + { + QMutexLocker locker(&mutex); + Mat dists, indicies; + index->knnSearch(src, indicies, dists, kSearch); + dst = indicies.reshape(1, 1); + } + + void load(QDataStream &stream) + { + stream >> centers; + reindex(); + } + + void store(QDataStream &stream) const + { + stream << centers; + } +}; +BR_REGISTER(Transform, RandomCentroidsTransform) } // namespace br diff --git a/openbr/plugins/draw.cpp b/openbr/plugins/draw.cpp index 9c57127..5f594fe 100644 --- a/openbr/plugins/draw.cpp +++ b/openbr/plugins/draw.cpp @@ -15,6 +15,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include +#include +#include #include "openbr_internal.h" #include "openbr/core/opencvutils.h" @@ -248,6 +250,100 @@ class MeanTransform : public Transform BR_REGISTER(Transform, MeanTransform) +/*! + * \ingroup transforms + * \brief Load the image named in the specified property, draw it on the current matrix adjacent to the rect specified in the other property. + * \author Charles Otto \cite caotto + */ +class AdjacentOverlayTransform : public Transform +{ + Q_OBJECT + + Q_PROPERTY(QString imgName READ get_imgName WRITE set_imgName RESET reset_imgName STORED false) + Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false) + BR_PROPERTY(QString, imgName, "") + BR_PROPERTY(QString, targetName, "") + + QSharedPointer opener; + void project(const Template &src, Template &dst) const + { + dst = src; + if (imgName.isEmpty() || targetName.isEmpty() || !dst.file.contains(imgName) || !dst.file.contains(targetName)) + return; + + QString im_name = src.file.get(imgName); + QRectF target_location = src.file.get(targetName); + Template temp_im; + opener->project(File(im_name), temp_im); + cv::Mat im = temp_im.m(); + + // match width with target region + qreal target_width = target_location.width(); + qreal current_width = im.cols; + qreal current_height = im.rows; + + qreal aspect_ratio = current_height / current_width; + qreal target_height = target_width * aspect_ratio; + + cv::resize(im, im, cv::Size(target_width, target_height)); + + cv::Rect clip_roi; + clip_roi.x = 0; + clip_roi.y = 0; + clip_roi.width = im.cols; + clip_roi.height= im.rows; + + int half_width = src.m().cols / 2; + int out_x = 0; + cv::Rect target_roi; + // Place left + if (target_location.center().rx() > half_width) { + out_x = target_location.left() - im.cols; + if (out_x < 0) { + clip_roi.width += out_x; + out_x = 0; + } + } + // place right + else { + out_x = target_location.right(); + int high = out_x + im.cols; + if (high >= src.m().cols) { + clip_roi.width -= high - src.m().cols + 1; + } + } + target_roi.x = out_x; + target_roi.width = clip_roi.width; + target_roi.y = target_location.top(); + target_roi.height = clip_roi.height; + + im = im(clip_roi); + + cv::Mat outIm = dst.m(); + std::vector channels; + cv::split(outIm, channels); + + std::vector patch_channels; + cv::split(im, patch_channels); + + for (size_t i=0; i < channels.size(); i++) + { + cv::addWeighted(channels[i](target_roi), 0, patch_channels[i % patch_channels.size()], 1, 0,channels[i](target_roi)); + } + cv::merge(channels, outIm); + dst.m() = outIm; + } + + void init() + { + opener = br::Transform::fromAlgorithm("Cache(Open)"); + + } + +}; + +BR_REGISTER(Transform, AdjacentOverlayTransform) + // TODO: re-implement EditTransform using Qt #if 0 /*! diff --git a/openbr/plugins/eigen3.cpp b/openbr/plugins/eigen3.cpp index 42340bd..accea75 100644 --- a/openbr/plugins/eigen3.cpp +++ b/openbr/plugins/eigen3.cpp @@ -84,7 +84,7 @@ private: for (int i=0; i(trainingSet[i].m().ptr(), dimsIn, 1).cast(); - train(data); + trainCore(data); } void project(const Template &src, Template &dst) const @@ -110,7 +110,7 @@ private: } protected: - void train(Eigen::MatrixXd data) + void trainCore(Eigen::MatrixXd data) { int dimsIn = data.rows(); int instances = data.cols(); @@ -227,7 +227,7 @@ class RowWisePCATransform : public PCATransform for (int i=0; i(t.m().ptr(i), dimsIn, 1).cast(); - PCATransform::train(data); + PCATransform::trainCore(data); } void project(const Template &src, Template &dst) const @@ -358,7 +358,7 @@ class LDATransform : public Transform // one per class), the total rank of the covariance/scatter // matrix that will be computed in PCA is bound by instances - numClasses. space1.keep = std::min(dimsIn, instances-numClasses); - space1.train(data); + space1.trainCore(data); // Divide each eigenvector by sqrt of eigenvalue. // This has the effect of whitening the within-class scatter. @@ -369,7 +369,7 @@ class LDATransform : public Transform { space1.drop = instances - numClasses; space1.keep = std::min(dimsIn, instances) - space1.drop; - space1.train(data); + space1.trainCore(data); } else { @@ -381,7 +381,7 @@ class LDATransform : public Transform // to discard Null space). We keep the Null space b/c this is where // the within-class scatter goes to zero, i.e. it is very useful. space1.keep = dimsIn; - space1.train(data); + space1.trainCore(data); if (dimsIn > instances - numClasses) { // Here, we are replacing the eigenvalue of the null space @@ -445,7 +445,7 @@ class LDATransform : public Transform int dim2 = std::min((int)space1.keep, numClasses-1); PCATransform space2; space2.keep = dim2; - space2.train(data2); + space2.trainCore(data2); // Compute final projection matrix projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); diff --git a/openbr/plugins/format.cpp b/openbr/plugins/format.cpp index 63bc36d..9d33e19 100644 --- a/openbr/plugins/format.cpp +++ b/openbr/plugins/format.cpp @@ -726,6 +726,58 @@ class xmlFormat : public Format BR_REGISTER(Format, xmlFormat) +/*! + * \ingroup formats + * \brief Reads in scores or ground truth from a text table. + * \author Josh Klontz + * + * Example of the format: + * \code + * 2.2531514 FALSE 99990377 99990164 + * 2.2549822 TRUE 99990101 99990101 + * \endcode + */ +class scoresFormat : public Format +{ + Q_OBJECT + Q_PROPERTY(int column READ get_column WRITE set_column RESET reset_column STORED false) + Q_PROPERTY(bool groundTruth READ get_groundTruth WRITE set_groundTruth RESET reset_groundTruth STORED false) + Q_PROPERTY(QString delimiter READ get_delimiter WRITE set_delimiter RESET reset_delimiter STORED false) + BR_PROPERTY(int, column, 0) + BR_PROPERTY(bool, groundTruth, false) + BR_PROPERTY(QString, delimiter, "\t") + + Template read() const + { + QFile f(file.name); + if (!f.open(QFile::ReadOnly | QFile::Text)) + qFatal("Failed to open %s for reading.", qPrintable(f.fileName())); + QList values; + while (!f.atEnd()) { + const QStringList words = QString(f.readLine()).split(delimiter); + if (words.size() <= column) qFatal("Expected file to have at least %d columns.", column+1); + const QString &word = words[column]; + bool ok; + float value = word.toFloat(&ok); + if (!ok) value = (QtUtils::toBool(word) ? BEE::Match : BEE::NonMatch); + values.append(value); + } + if (values.size() == 1) + qWarning("Only one value read, double check file line endings."); + Mat result = OpenCVUtils::toMat(values); + if (groundTruth) result.convertTo(result, CV_8U); + return result; + } + + void write(const Template &t) const + { + (void) t; + qFatal("Not implemented."); + } +}; + +BR_REGISTER(Format, scoresFormat) + } // namespace br #include "format.moc" diff --git a/openbr/plugins/hist.cpp b/openbr/plugins/hist.cpp index 1896ae0..5563ff6 100644 --- a/openbr/plugins/hist.cpp +++ b/openbr/plugins/hist.cpp @@ -54,7 +54,7 @@ class HistTransform : public UntrainableTransform const float* ranges[] = {range}; Mat hist, chan = mv[i]; // calcHist requires F or U, might as well convert just in case - if (mv[i].depth() != CV_8U || mv[i].depth() == CV_32F) + if (mv[i].depth() != CV_8U && mv[i].depth() != CV_32F) mv[i].convertTo(chan, CV_32F); calcHist(&chan, 1, channels, Mat(), hist, 1, histSize, ranges); memcpy(m.ptr(i), hist.ptr(), dims * sizeof(float)); diff --git a/openbr/plugins/jni.cmake b/openbr/plugins/jni.cmake new file mode 100644 index 0000000..0fc3f77 --- /dev/null +++ b/openbr/plugins/jni.cmake @@ -0,0 +1,12 @@ +set(BR_WITH_JAVA OFF CACHE BOOL "Use Java Code") + +if (${BR_WITH_JAVA}) + find_package(JNI REQUIRED) + find_package(JAVA REQUIRED) + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/jni.cpp) + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES}) + + include_directories(${JAVA_INCLUDE_PATH}) + include_directories(${JAVA_INCLUDE_PATH2}) + +endif() diff --git a/openbr/plugins/jni.cpp b/openbr/plugins/jni.cpp new file mode 100644 index 0000000..9aa6870 --- /dev/null +++ b/openbr/plugins/jni.cpp @@ -0,0 +1,104 @@ +//Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables + +#include +#include "openbr_internal.h" +#include "openbr/core/resource.h" +#include + +namespace br +{ + +/*! + * \ingroup initializers + * \brief Initialize JNI + * \author Jordan Cheney \cite jcheney + */ +class JNIInitializer : public Initializer +{ + Q_OBJECT + public: + static JavaVM* jvm; + static JavaVMInitArgs vm_args; + + void initialize() const + { + JNIEnv *env; + JavaVMOption options[1]; + + //Location of Java files + QByteArray classpath = QString("-Djava.class.path=").append(Globals->sdkPath).append(QString("/share/openbr/Java/jniLibraries/")).toLocal8Bit(); + char *charClasspath = classpath.data(); + + options[0].optionString = charClasspath; + vm_args.version = JNI_VERSION_1_6; + vm_args.nOptions = 1; + vm_args.options = options; + vm_args.ignoreUnrecognized = JNI_FALSE; + + JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); + + Globals->abbreviations.insert("JNIHelloWorld","Open+JNI(HelloWorld)"); + } + + void finalize() const + { + jvm->DestroyJavaVM(); + } +}; + +JavaVM *JNIInitializer::jvm; +JavaVMInitArgs JNIInitializer::vm_args; + +BR_REGISTER(Initializer, JNIInitializer) + +/*! + * \ingroup transforms + * \brief Execute Java code from OpenBR using the JNI + * \author Jordan Cheney \cite jcheney + */ + +class JNITransform : public UntrainableTransform +{ + Q_OBJECT + Q_PROPERTY(QString className READ get_className WRITE set_className RESET reset_className STORED false) + BR_PROPERTY(QString, className, "") + + void project(const Template &src, Template &dst) const + { + (void)dst; //Eliminates a compiler warning. + + JNIEnv *env; + + //Attach current thread to the thread of the JavaVM and access env + JNIInitializer::jvm->AttachCurrentThreadAsDaemon((void**)&env, NULL); + if (JNIInitializer::jvm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + qFatal("Failed to initialize JNI environment"); + } + + //Convert QString to const char* + QByteArray tmpClass = className.toLocal8Bit(); + const char* charClassName = tmpClass.constData(); + + //Call java method + jclass cls = env->FindClass(charClassName); + if (cls == NULL) { qFatal("Class not found"); } + jmethodID mid = env->GetStaticMethodID(cls, "project", "(Ljava/lang/String;)V"); + if (mid == NULL) { qFatal("MethodID not found"); } + + QByteArray tmp = src.file.name.toLocal8Bit(); + const char* fileName = tmp.constData(); + + //Convert char* to java compatible string + jstring jfileName = env->NewStringUTF(fileName); + + env->CallStaticObjectMethod(cls, mid, jfileName); + + JNIInitializer::jvm->DetachCurrentThread(); + } +}; + +BR_REGISTER(Transform, JNITransform) + +} // namespace br + +#include "jni.moc" diff --git a/openbr/plugins/keypoint.cpp b/openbr/plugins/keypoint.cpp index ca9710b..60d5f29 100644 --- a/openbr/plugins/keypoint.cpp +++ b/openbr/plugins/keypoint.cpp @@ -97,6 +97,7 @@ class KeyPointDescriptorTransform : public UntrainableTransform else foreach (const QPointF &landmark, src.file.points()) keyPoints.push_back(KeyPoint(landmark.x(), landmark.y(), size)); + if (keyPoints.empty()) return; descriptorExtractor->compute(src, keyPoints, dst); } }; diff --git a/openbr/plugins/mask.cpp b/openbr/plugins/mask.cpp index 81fa8fb..3019934 100644 --- a/openbr/plugins/mask.cpp +++ b/openbr/plugins/mask.cpp @@ -180,6 +180,26 @@ class LargestConvexAreaTransform : public UntrainableTransform BR_REGISTER(Transform, LargestConvexAreaTransform) +/*! + * \ingroup transforms + * \brief Applies a mask from the metadata. + * \author Austin Blanton \cite imaus10 + */ +class ApplyMaskTransform : public UntrainableTransform +{ + Q_OBJECT + + void project(const Template &src, Template &dst) const + { + if (src.file.contains("Mask")) + src.m().copyTo(dst, src.file.get("Mask")); + else + dst = src; + } +}; + +BR_REGISTER(Transform, ApplyMaskTransform) + } // namespace br #include "mask.moc" diff --git a/openbr/plugins/meta.cpp b/openbr/plugins/meta.cpp index f4f4aaf..0cc60f2 100644 --- a/openbr/plugins/meta.cpp +++ b/openbr/plugins/meta.cpp @@ -57,7 +57,7 @@ static TemplateList Expanded(const TemplateList &templates) return expanded; } -static void _train(Transform *transform, const TemplateList *data) +static void _train(Transform *transform, const QList *data) { transform->train(*data); } @@ -82,18 +82,11 @@ class PipeTransform : public CompositeTransform *srcdst >> *transforms[i]; } - void train(const TemplateList &data) + void train(const QList &data) { if (!trainable) return; - TemplateList copy(data); - QList singleItemLists; - for (int i=0; i < copy.size(); i++) - { - TemplateList temp; - temp.append(copy[i]); - singleItemLists.append(temp); - } + QList dataLines(data); int i = 0; while (i < transforms.size()) { @@ -102,23 +95,18 @@ class PipeTransform : public CompositeTransform // Conditional statement covers likely case that first transform is untrainable if (transforms[i]->trainable) { fprintf(stderr, " training..."); - transforms[i]->train(copy); + transforms[i]->train(dataLines); } // if the transform is time varying, we can't project it in parallel if (transforms[i]->timeVarying()) { fprintf(stderr, "\n%s projecting...", qPrintable(transforms[i]->objectName())); - for (int j=0; j < singleItemLists.size();j++) - transforms[i]->projectUpdate(singleItemLists[j], singleItemLists[j]); + for (int j=0; j < dataLines.size();j++) + transforms[i]->projectUpdate(dataLines[j], dataLines[j]); // advance i since we already projected for this stage. i++; - // set up copy again - copy.clear(); - for (int j=0; j < singleItemLists.size(); j++) - copy.append(singleItemLists[j]); - // the next stage might be trainable, so continue to evaluate it. continue; } @@ -136,14 +124,10 @@ class PipeTransform : public CompositeTransform fprintf(stderr, " projecting..."); QFutureSynchronizer futures; - for (int j=0; j < singleItemLists.size(); j++) - futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &singleItemLists[j], i, nextTrainableTransform)); + for (int j=0; j < dataLines.size(); j++) + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &dataLines[j], i, nextTrainableTransform)); futures.waitForFinished(); - copy.clear(); - for (int j=0; j < singleItemLists.size(); j++) - copy.append(singleItemLists[j]); - i = nextTrainableTransform; } } @@ -195,6 +179,26 @@ class PipeTransform : public CompositeTransform } } + void init() + { + QList flattened; + for (int i=0;i < transforms.size(); i++) + { + PipeTransform * probe = dynamic_cast (transforms[i]); + if (!probe) { + flattened.append(transforms[i]); + continue; + } + for (int j=0; j < probe->transforms.size(); j++) + { + flattened.append(probe->transforms[j]); + } + } + transforms = flattened; + + CompositeTransform::init(); + } + protected: // Template list project -- process templates in parallel through Transform::project // or if parallelism is disabled, handle them sequentially @@ -296,7 +300,7 @@ class ForkTransform : public CompositeTransform { Q_OBJECT - void train(const TemplateList &data) + void train(const QList &data) { if (!trainable) return; QFutureSynchronizer futures; @@ -440,7 +444,7 @@ private: } } - void train(const TemplateList &data) + void train(const QList &data) { transform->train(data); } @@ -612,14 +616,22 @@ public: return output; } - void train(const TemplateList &data) + void train(const QList &data) { if (!transform->trainable) { qWarning("Attempted to train untrainable transform, nothing will happen."); return; } - transform->train(data); + QList separated; + foreach (const TemplateList & list, data) { + foreach(const Template & t, list) { + separated.append(TemplateList()); + separated.last().append(t); + } + } + + transform->train(separated); } void project(const Template &src, Template &dst) const diff --git a/openbr/plugins/misc.cpp b/openbr/plugins/misc.cpp index 5a5ce50..e7c6007 100644 --- a/openbr/plugins/misc.cpp +++ b/openbr/plugins/misc.cpp @@ -496,14 +496,16 @@ class IncrementalOutputTransform : public TimeVaryingTransform } dst = src; + int idx =0; foreach(const Template & t, src) { if (t.empty()) continue; // Build the output filename for this template QFileInfo finfo(t.file.name); - QString outputName = finfo.baseName() +"_" + t.file.get("FrameNumber") + fileFormat; + QString outputName = finfo.baseName() +"_" + t.file.get("FrameNumber") + "_" + QString::number(idx)+ fileFormat; + idx++; Template out = t; out.file.name = outputName; writer->write(out); diff --git a/openbr/plugins/opticalflow.cpp b/openbr/plugins/motion.cpp index 89c2044..d746527 100644 --- a/openbr/plugins/opticalflow.cpp +++ b/openbr/plugins/motion.cpp @@ -1,4 +1,5 @@ #include +#include #include "openbr_internal.h" #include "openbr/core/opencvutils.h" @@ -52,6 +53,45 @@ class OpticalFlowTransform : public UntrainableMetaTransform BR_REGISTER(Transform, OpticalFlowTransform) +/*! + * \ingroup transforms + * \brief Wraps OpenCV's BackgroundSubtractorMOG2 and puts the foreground mask in the Template metadata. + * \author Austin Blanton \cite imaus10 + */ +class SubtractBackgroundTransform : public TimeVaryingTransform +{ + Q_OBJECT + + BackgroundSubtractorMOG2 mog; + +public: + SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} + +private: + void projectUpdate(const Template &src, Template &dst) + { + dst = src; + Mat mask; + mog(src, mask); + erode(mask, mask, Mat()); + dilate(mask, mask, Mat()); + dst.file.set("Mask", QVariant::fromValue(mask)); + } + + void project(const Template &src, Template &dst) const + { + (void) src; (void) dst; qFatal("no way"); + } + + void finalize(TemplateList &output) + { + (void) output; + mog = BackgroundSubtractorMOG2(); + } +}; + +BR_REGISTER(Transform, SubtractBackgroundTransform) + } // namespace br -#include "opticalflow.moc" +#include "motion.moc" diff --git a/openbr/plugins/openbr_internal.h b/openbr/plugins/openbr_internal.h index 84ff5ee..3348b8c 100644 --- a/openbr/plugins/openbr_internal.h +++ b/openbr/plugins/openbr_internal.h @@ -1,5 +1,5 @@ -#ifndef __OPENBR_INTERNAL_H -#define __OPENBR_INTERNAL_H +#ifndef OPENBR_INTERNAL_H +#define OPENBR_INTERNAL_H #include "openbr/openbr_plugin.h" #include "openbr/core/resource.h" @@ -88,7 +88,7 @@ public: transformSource.release(aTransform); } - void train(const TemplateList &data) + void train(const QList &data) { baseTransform->train(data); } @@ -242,4 +242,4 @@ protected: } -#endif +#endif // OPENBR_INTERNAL_H diff --git a/openbr/plugins/stream.cpp b/openbr/plugins/stream.cpp index 4550baa..14e3ab5 100644 --- a/openbr/plugins/stream.cpp +++ b/openbr/plugins/stream.cpp @@ -1016,7 +1016,27 @@ public: }; +// Semi-functional, doesn't do anything productive outside of stream::train +class CollectSets : public TimeVaryingTransform +{ + Q_OBJECT +public: + CollectSets() : TimeVaryingTransform(false, false) {} + + QList sets; + + void projectUpdate(const TemplateList &src, TemplateList &dst) + { + (void) dst; + sets.append(src); + } + void train(const TemplateList & data) + { + (void) data; + } + +}; class DirectStreamTransform : public CompositeTransform { @@ -1027,16 +1047,52 @@ public: friend class StreamTransfrom; - void train(const TemplateList & data) + void subProject(QList & data, int end_idx) + { + if (end_idx == 0) + return; + + CollectSets collector; + + // Set transforms to the start, up to end_idx + QList backup = this->transforms; + transforms = backup.mid(0,end_idx); + // We use collector to retain the project structure at the end of the + // truncated stream. + transforms.append(&collector); + + // Reinitialize, we now act as a shorter stream. + init(); + + QList output; + for (int i=0; i < data.size(); i++) { + projectUpdate(data[i], data[i]); + output.append(collector.sets); + collector.sets.clear(); + } + data = output; + transforms = backup; + } + + void train(const QList & data) { if (!trainable) { qWarning("Attempted to train untrainable transform, nothing will happen."); return; } - qFatal("Stream train is currently not implemented."); - foreach(Transform * transform, transforms) { - transform->train(data); + + for (int i=0; i < transforms.size(); i++) { + // OK we have a trainable transform, we need to get input data for it. + if (transforms[i]->trainable) { + QList copy = data; + // Project from the start to the trainable stage. + subProject(copy,i); + + transforms[i]->train(copy); + } } + // Re-initialize because subProject probably messed us up. + init(); } bool timeVarying() const { return true; } @@ -1287,8 +1343,7 @@ public: basis.projectUpdate(src,dst); } - - void train(const TemplateList & data) + void train(const QList & data) { basis.train(data); } diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index e47a728..d1ee4a7 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -7,6 +7,11 @@ namespace br { +static void _train(Transform * transform, TemplateList data) // think data has to be a copy -cao +{ + transform->train(data); +} + /*! * \ingroup transforms * \brief Cross validate a trainable transform. @@ -23,8 +28,12 @@ class CrossValidateTransform : public MetaTransform BR_PROPERTY(QString, description, "Identity") BR_PROPERTY(bool, leaveOneImageOut, false) + // numPartitions copies of transform specified by description. QList transforms; + // Treating this transform as a leaf (in terms of update training scheme), the child transform + // of this transform will lose any structure present in the training QList, which + // is generally incorrect behavior. void train(const TemplateList &data) { int numPartitions = 0; @@ -84,7 +93,7 @@ class CrossValidateTransform : public MetaTransform } else j--; } // Train on the remaining templates - futures.addFuture(QtConcurrent::run(transforms[i], &Transform::train, partitionedData)); + futures.addFuture(QtConcurrent::run(_train, transforms[i], partitionedData)); } futures.waitForFinished(); } diff --git a/scripts/downloadDatasets.sh b/scripts/downloadDatasets.sh index 35130ae..37daff3 100755 --- a/scripts/downloadDatasets.sh +++ b/scripts/downloadDatasets.sh @@ -5,6 +5,21 @@ if [ ! -f downloadDatasets.sh ]; then exit fi +# AT&T +if [ ! -d ../data/ATT/img ]; then + echo "Downloading AT&T…" + if hash curl 2>/dev/null; then + curl -OL http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip + else + wget http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip + fi + + unzip att_faces.zip -d att_faces + mv att_faces ../data/ATT/img + rm ../data/ATT/img/README att_faces.zip +fi + + # BioID if [ ! -d ../data/BioID/img ]; then echo "Downloading BioID..." @@ -20,6 +35,24 @@ if [ ! -d ../data/BioID/img ]; then rm *.eye description.txt BioID-FaceDatabase-V1.2.zip fi +# KTH +if [ ! -d ../data/KTH/vid ]; then + echo "Downloading KTH..." + mkdir ../data/KTH/vid + for vidclass in {'boxing','handclapping','handwaving','jogging','running','walking'}; do + if hash curl 2>/dev/null; then + curl -OL http://www.nada.kth.se/cvap/actions/${vidclass}.zip + else + wget http://www.nada.kth.se/cvap/actions/${vidclass}.zip + fi + mkdir ../data/KTH/vid/${vidclass} + unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} + rm ${vidclass}.zip + done + # this file is corrupted + rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi +fi + # LFW if [ ! -d ../data/LFW/img ]; then echo "Downloading LFW..." @@ -48,21 +81,3 @@ if [ ! -d ../data/MEDS/img ]; then mv data/*/*.jpg ../data/MEDS/img rm -r data NIST_SD32_MEDS-II_face.zip fi - -# KTH -if [ ! -d ../data/KTH/vid ]; then - echo "Downloading KTH..." - mkdir ../data/KTH/vid - for vidclass in {'boxing','handclapping','handwaving','jogging','running','walking'}; do - if hash curl 2>/dev/null; then - curl -OL http://www.nada.kth.se/cvap/actions/${vidclass}.zip - else - wget http://www.nada.kth.se/cvap/actions/${vidclass}.zip - fi - mkdir ../data/KTH/vid/${vidclass} - unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} - rm ${vidclass}.zip - done - # this file is corrupted - rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi -fi diff --git a/share/openbr/Java/jniLibraries/HelloWorld.jar b/share/openbr/Java/jniLibraries/HelloWorld.jar new file mode 100644 index 0000000..41cbbb3 --- /dev/null +++ b/share/openbr/Java/jniLibraries/HelloWorld.jar diff --git a/share/openbr/Java/jniLibraries/HelloWorld.java b/share/openbr/Java/jniLibraries/HelloWorld.java new file mode 100644 index 0000000..7cf7b0e --- /dev/null +++ b/share/openbr/Java/jniLibraries/HelloWorld.java @@ -0,0 +1,9 @@ +public class HelloWorld { + public static void project(String imgPath) { + System.out.println(); + System.out.println("Welcome to the OpenBR JNI transform! The image path string " + imgPath + " has been passed here from C++."); + System.out.println("To incorporate your Java code into OpenBR assemble a jar file will of the relevant classes and save it in the openbr/share/openbr/Java/jniLibraries folder."); + System.out.println("For documentation and additional resources on the JNI visit 'https://docs.oracle.com/javase/1.5.0/docs/guide/jni/specs/functions.html'"); + System.out.println(); + } +} \ No newline at end of file