diff --git a/openbr/core/qtutils.cpp b/openbr/core/qtutils.cpp index a5590d5..0c29616 100644 --- a/openbr/core/qtutils.cpp +++ b/openbr/core/qtutils.cpp @@ -290,10 +290,10 @@ QPointF QtUtils::toPoint(const QString &string) QStringList values = string.split(','); if (values.size() == 2) { values[1].chop(1); - QPointF point(values[0].mid(1).toFloat(), values[1].toFloat()); - return point; + return QPointF(values[0].mid(1).toFloat(), values[1].toFloat()); } - else qFatal("Failed to convert %s to QPoint format.", qPrintable(string)); + else qFatal("Failed to convert %s to QPointF format.", qPrintable(string)); + return QPointF(); } QRectF QtUtils::toRect(const QString &string) @@ -301,10 +301,10 @@ QRectF QtUtils::toRect(const QString &string) QStringList values = string.split(','); if (values.size() == 4) { values[3].chop(1); - QRectF rect(values[0].mid(1).toFloat(), values[1].toFloat(), values[2].toFloat(), values[3].toFloat()); - return rect; + return QRectF(values[0].mid(1).toFloat(), values[1].toFloat(), values[2].toFloat(), values[3].toFloat()); } - else qFatal("Failed to convert %s to QRect format.", qPrintable(string)); + else qFatal("Failed to convert %s to QRectF format.", qPrintable(string)); + return QRectF(); } bool QtUtils::runRScript(const QString &file) diff --git a/openbr/frvt2012.cpp b/openbr/frvt2012.cpp index 7a95338..d574755 100644 --- a/openbr/frvt2012.cpp +++ b/openbr/frvt2012.cpp @@ -15,6 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include +#include #include "frvt2012.h" #include "core/distance_sse.h" diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 272393d..e5d7185 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #ifndef BR_EMBEDDED #include diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index 908764a..482a69b 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -1085,6 +1085,14 @@ public: return dst; } + /*! + * \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. + */ + virtual Transform * smartCopy() { return this;} + protected: Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ inline Transform *make(const QString &description) { return make(description, this); } /*!< \brief Make a subtransform. */ @@ -1125,133 +1133,6 @@ inline QDataStream &operator>>(QDataStream &stream, Transform &f) f.load(stream); return stream; } - -/*! - * \brief A br::Transform for which the results of project may change due to prior calls to project - */ -class BR_EXPORT TimeVaryingTransform : public Transform -{ - Q_OBJECT - -public: - virtual bool timeVarying() const { return true; } - - virtual void project(const Template &src, Template &dst) const - { - qFatal("No const project defined for time-varying transform"); - (void) dst; (void) src; - } - - virtual void project(const TemplateList &src, TemplateList &dst) const - { - qFatal("No const project defined for time-varying transform"); - (void) dst; (void) src; - } - - // Get a compile failure if this isn't here to go along with the other - // projectUpdate, no idea why - virtual void projectUpdate(const Template & src, Template & dst) - { - (void) src; (void) dst; - qFatal("do something useful"); - } - - virtual void projectUpdate(const TemplateList &src, TemplateList &dst) - { - foreach (const Template & src_part, src) { - Template out; - projectUpdate(src_part, out); - dst.append(out); - } - } - -protected: - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} -}; - -/*! - * \brief A br::Transform expecting multiple matrices per template. - */ -class BR_EXPORT MetaTransform : public Transform -{ - Q_OBJECT - -protected: - MetaTransform() : Transform(false) {} -}; - -/*! - * \brief A br::Transform that does not require training data. - */ -class BR_EXPORT UntrainableTransform : public Transform -{ - Q_OBJECT - -protected: - UntrainableTransform(bool independent = true) : Transform(independent, false) {} /*!< \brief Construct an untrainable transform. */ - -private: - Transform *clone() const { return const_cast(this); } - void train(const TemplateList &data) { (void) data; } - void store(QDataStream &stream) const { (void) stream; } - void load(QDataStream &stream) { (void) stream; } -}; - -/*! - * \brief A br::MetaTransform that does not require training data. - */ -class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform -{ - Q_OBJECT - -protected: - UntrainableMetaTransform() : UntrainableTransform(false) {} -}; - -/*! - * \brief A MetaTransform that aggregates some sub-transforms - */ -class BR_EXPORT CompositeTransform : public TimeVaryingTransform -{ - Q_OBJECT - -public: - Q_PROPERTY(QList transforms READ get_transforms WRITE set_transforms RESET reset_transforms) - BR_PROPERTY(QList, transforms, QList()) - - virtual void project(const Template &src, Template &dst) const - { - if (timeVarying()) qFatal("No const project defined for time-varying transform"); - _project(src, dst); - } - - virtual void project(const TemplateList &src, TemplateList &dst) const - { - if (timeVarying()) qFatal("No const project defined for time-varying transform"); - _project(src, dst); - } - - bool timeVarying() const { return isTimeVarying; } - - void init() - { - isTimeVarying = false; - trainable = false; - foreach (const br::Transform *transform, transforms) { - isTimeVarying = isTimeVarying || transform->timeVarying(); - trainable = trainable || transform->trainable; - } - } - -protected: - bool isTimeVarying; - - virtual void _project(const Template & src, Template & dst) const = 0; - virtual void _project(const TemplateList & src, TemplateList & dst) const = 0; - - CompositeTransform() : TimeVaryingTransform(false) {} -}; - /*! @}*/ /*! diff --git a/openbr/plugins/algorithms.cpp b/openbr/plugins/algorithms.cpp index ab8bc33..9fdf0b6 100644 --- a/openbr/plugins/algorithms.cpp +++ b/openbr/plugins/algorithms.cpp @@ -14,7 +14,7 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include +#include "openbr_internal.h" namespace br { @@ -42,7 +42,8 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("OpenBR", "FaceRecognition"); Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); - Globals->abbreviations.insert("FaceRecognitionHoG", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+Gradient+Bin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Center(Hellinger)+LDA(.95)+Normalize(L1)+Div(3)+ProductQuantization(3,L1,true)[fraction=0.2]):RecursiveProductQuantization"); + 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,Center(Hellinger)+LDA(.95)+Normalize(L1)+Div(3)+ProductQuantization(3,L1,true)[fraction=0.2]):RecursiveProductQuantization"); + Globals->abbreviations.insert("FaceRecognitionHoG", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+Gradient+Bin(0,360,9)+KernelHash(9,81)+Bin(0,81,81,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.95)+Normalize(L1)+Div(3)+ProductQuantization(3,L1,true)[fraction=0.2]):RecursiveProductQuantization"); // Generic Image Processing Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); @@ -50,7 +51,6 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)!EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); - Globals->abbreviations.insert("ImageRetrieval", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(88,88,0.25,0.35)+Gradient+Bin(0,360,8,true)+Merge+Integral+IntegralSampler+WordWise(RowWisePCA(8)+RowWiseMeanCenter+Binarize,RowWisePCA)+Sentence:SentenceSimilarity"); // Hash Globals->abbreviations.insert("FileName", "Name+Identity:Identical"); diff --git a/openbr/plugins/cascade.cpp b/openbr/plugins/cascade.cpp index f8373ee..0c00523 100644 --- a/openbr/plugins/cascade.cpp +++ b/openbr/plugins/cascade.cpp @@ -15,8 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" #include "openbr/core/resource.h" diff --git a/openbr/plugins/cluster.cpp b/openbr/plugins/cluster.cpp index 7876d69..560709f 100644 --- a/openbr/plugins/cluster.cpp +++ b/openbr/plugins/cluster.cpp @@ -14,7 +14,7 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include +#include "openbr_internal.h" #include #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/crop.cpp b/openbr/plugins/crop.cpp index e9cfff4..f0e14ea 100644 --- a/openbr/plugins/crop.cpp +++ b/openbr/plugins/crop.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/ct8.cpp b/openbr/plugins/ct8.cpp index 4fa3660..51d5598 100644 --- a/openbr/plugins/ct8.cpp +++ b/openbr/plugins/ct8.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include "openbr_internal.h" #include "core/resource.h" diff --git a/openbr/plugins/cvt.cpp b/openbr/plugins/cvt.cpp index 3a2197a..243851e 100644 --- a/openbr/plugins/cvt.cpp +++ b/openbr/plugins/cvt.cpp @@ -15,8 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" using namespace cv; diff --git a/openbr/plugins/denoising.cpp b/openbr/plugins/denoising.cpp index 9d76032..03ac646 100644 --- a/openbr/plugins/denoising.cpp +++ b/openbr/plugins/denoising.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/distance.cpp b/openbr/plugins/distance.cpp index c3ef877..cb07e12 100644 --- a/openbr/plugins/distance.cpp +++ b/openbr/plugins/distance.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include "openbr_internal.h" #include "openbr/core/distance_sse.h" #include "openbr/core/qtutils.h" diff --git a/openbr/plugins/draw.cpp b/openbr/plugins/draw.cpp index b41570b..f26336e 100644 --- a/openbr/plugins/draw.cpp +++ b/openbr/plugins/draw.cpp @@ -15,8 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" using namespace cv; diff --git a/openbr/plugins/eigen3.cpp b/openbr/plugins/eigen3.cpp index c1fbe71..8ee362e 100644 --- a/openbr/plugins/eigen3.cpp +++ b/openbr/plugins/eigen3.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/eigenutils.h" diff --git a/openbr/plugins/eyes.cpp b/openbr/plugins/eyes.cpp index 8b7d34b..e8e2ae9 100644 --- a/openbr/plugins/eyes.cpp +++ b/openbr/plugins/eyes.cpp @@ -34,8 +34,7 @@ */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" using namespace cv; diff --git a/openbr/plugins/fill.cpp b/openbr/plugins/fill.cpp index 81ac706..1614337 100644 --- a/openbr/plugins/fill.cpp +++ b/openbr/plugins/fill.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/filter.cpp b/openbr/plugins/filter.cpp index 32e9ec5..2bc8cd3 100644 --- a/openbr/plugins/filter.cpp +++ b/openbr/plugins/filter.cpp @@ -15,8 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/tanh_sse.h" using namespace cv; diff --git a/openbr/plugins/format.cpp b/openbr/plugins/format.cpp index 348683b..581577d 100644 --- a/openbr/plugins/format.cpp +++ b/openbr/plugins/format.cpp @@ -19,7 +19,7 @@ #include #endif // BR_EMBEDDED #include -#include +#include "openbr_internal.h" #include "openbr/core/bee.h" #include "openbr/core/opencvutils.h" @@ -245,6 +245,31 @@ BR_REGISTER(Format, DefaultFormat) /*! * \ingroup formats + * \brief Reads a NIST LFFS file. + * \author Josh Klontz \cite jklontz + */ +class lffsFormat : public Format +{ + Q_OBJECT + + Template read() const + { + QByteArray byteArray; + QtUtils::readFile(file.name, byteArray); + return Mat(1, byteArray.size(), CV_8UC1, byteArray.data()).clone(); + } + + void write(const Template &t) const + { + QByteArray byteArray((const char*)t.m().data, t.m().total()*t.m().elemSize()); + QtUtils::writeFile(file.name, byteArray); + } +}; + +BR_REGISTER(Format, lffsFormat) + +/*! + * \ingroup formats * \brief Reads a NIST BEE similarity matrix. * \author Josh Klontz \cite jklontz */ diff --git a/openbr/plugins/gallery.cpp b/openbr/plugins/gallery.cpp index 4537aab..07ef58e 100644 --- a/openbr/plugins/gallery.cpp +++ b/openbr/plugins/gallery.cpp @@ -24,7 +24,7 @@ #include #endif // BR_EMBEDDED #include -#include +#include "openbr_internal.h" #include "NaturalStringCompare.h" #include "openbr/core/bee.h" diff --git a/openbr/plugins/gui.cpp b/openbr/plugins/gui.cpp index 980fad8..c5d955b 100644 --- a/openbr/plugins/gui.cpp +++ b/openbr/plugins/gui.cpp @@ -1,8 +1,10 @@ #include #include #include +#include +#include #include -#include +#include "openbr_internal.h" using namespace cv; @@ -47,20 +49,39 @@ QImage toQImage(const Mat &mat) return QImage(mat8uc3.data, mat8uc3.cols, mat8uc3.rows, 3*mat8uc3.cols, QImage::Format_RGB888).copy(); } + // Provides slots for manipulating a QLabel, but does not inherit from QWidget. // Therefore, it can be moved to the main thread if not created there initially // since god forbid you create a QWidget subclass in not the main thread. class GUIProxy : public QObject { Q_OBJECT + QMutex lock; + QWaitCondition wait; + public: - QLabel * window; + bool eventFilter(QObject * obj, QEvent * event) + { + if (event->type() == QEvent::KeyPress) + { + wait.wakeAll(); + } + return QObject::eventFilter(obj, event); + } + + QLabel * window; GUIProxy() { window = NULL; } + void waitForKey() + { + QMutexLocker locker(&lock); + wait.wait(&lock); + } + public slots: void showImage(const QPixmap & input) @@ -75,6 +96,13 @@ public slots: delete window; window = new QLabel(); window->setVisible(true); + + QApplication::instance()->installEventFilter(this); + Qt::WindowFlags flags = window->windowFlags(); + + flags = flags & ~Qt::WindowCloseButtonHint; + window->setWindowFlags(flags); + window->show(); } }; @@ -89,9 +117,13 @@ class Show2Transform : public TimeVaryingTransform { Q_OBJECT public: + Q_PROPERTY(bool waitInput READ get_waitInput WRITE set_waitInput RESET reset_waitInput STORED false) + BR_PROPERTY(bool, waitInput, false) + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) BR_PROPERTY(QStringList, keys, QStringList("FrameNumber")) + Show2Transform() : TimeVaryingTransform(false, false) { // Create our GUI proxy @@ -146,6 +178,11 @@ public: // by the main thread isn't damaged when we update displayBuffer // later. emit updateImage(displayBuffer.copy(displayBuffer.rect())); + + // Blocking wait for a key-press + if (this->waitInput) + gui->waitForKey(); + } } } diff --git a/openbr/plugins/hash.cpp b/openbr/plugins/hash.cpp index 3ff12d1..179b547 100644 --- a/openbr/plugins/hash.cpp +++ b/openbr/plugins/hash.cpp @@ -15,10 +15,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/qtutils.h" +using namespace cv; + namespace br { @@ -55,6 +56,40 @@ private: BR_REGISTER(Transform, CryptographicHashTransform) +/*! + * \ingroup transforms + * \brief Kernel hash + * \author Josh Klontz \cite jklontz + */ +class KernelHashTransform : public UntrainableTransform +{ + Q_OBJECT + Q_PROPERTY(uchar dimsIn READ get_dimsIn WRITE set_dimsIn RESET reset_dimsIn STORED false) + Q_PROPERTY(uchar dimsOut READ get_dimsOut WRITE set_dimsOut RESET reset_dimsOut STORED false) + BR_PROPERTY(uchar, dimsIn, 8) + BR_PROPERTY(uchar, dimsOut, 7) + + void project(const Template &src, Template &dst) const + { + if (src.m().type() != CV_8UC1) + qFatal("Expected 8UC1 input."); + + dst = Mat::zeros(src.m().rows, src.m().cols, CV_8UC1); + const uchar *srcData = src.m().data; + uchar *dstData = dst.m().data; + const int step = src.m().cols; + for (int i=0; i -#include - +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/integral.cpp b/openbr/plugins/integral.cpp index 06f53d1..0880dfd 100644 --- a/openbr/plugins/integral.cpp +++ b/openbr/plugins/integral.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" @@ -285,7 +285,6 @@ private: void project(const Template &src, Template &dst) const { - if (src.m().type() != CV_8UC1) qFatal("Requires CV_8UC1 input."); Mat dx, dy, magnitude, angle; Sobel(src, dx, CV_32F, 1, 0); Sobel(src, dy, CV_32F, 0, 1); diff --git a/openbr/plugins/ipc2013.cpp b/openbr/plugins/ipc2013.cpp index 585978a..4f5ce59 100644 --- a/openbr/plugins/ipc2013.cpp +++ b/openbr/plugins/ipc2013.cpp @@ -1,4 +1,4 @@ -#include +#include "openbr_internal.h" #include #include #include diff --git a/openbr/plugins/keypoint.cpp b/openbr/plugins/keypoint.cpp index 5228ae1..b857aa7 100644 --- a/openbr/plugins/keypoint.cpp +++ b/openbr/plugins/keypoint.cpp @@ -16,8 +16,7 @@ #include #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" using namespace cv; @@ -109,7 +108,7 @@ BR_REGISTER(Transform, KeyPointDescriptorTransform) * \brief Wraps OpenCV Key Point Matcher * \author Josh Klontz \cite jklontz */ -class KeyPointMatcherTransform : public Distance +class KeyPointMatcherDistance : public Distance { Q_OBJECT Q_PROPERTY(QString matcher READ get_matcher WRITE set_matcher RESET reset_matcher STORED false) @@ -148,7 +147,7 @@ class KeyPointMatcherTransform : public Distance } }; -BR_REGISTER(Distance, KeyPointMatcherTransform) +BR_REGISTER(Distance, KeyPointMatcherDistance) /*! * \ingroup transforms diff --git a/openbr/plugins/lbp.cpp b/openbr/plugins/lbp.cpp index 6b36cca..a455021 100644 --- a/openbr/plugins/lbp.cpp +++ b/openbr/plugins/lbp.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/mask.cpp b/openbr/plugins/mask.cpp index 5e779af..f9979e8 100644 --- a/openbr/plugins/mask.cpp +++ b/openbr/plugins/mask.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/meta.cpp b/openbr/plugins/meta.cpp index 4c7eee1..7a462f6 100644 --- a/openbr/plugins/meta.cpp +++ b/openbr/plugins/meta.cpp @@ -16,11 +16,11 @@ #include #include -#include - +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" #include "openbr/core/qtutils.h" +#include "openbr/core/resource.h" using namespace cv; @@ -183,7 +183,6 @@ class PipeTransform : public CompositeTransform } } - protected: // Template list project -- process templates in parallel through Transform::project // or if parallelism is disabled, handle them sequentially @@ -590,6 +589,56 @@ static void _projectList(const Transform *transform, const TemplateList *src, Te } +class TransformCopier : public ResourceMaker +{ +public: + Transform * basis; + TransformCopier(Transform * _basis) + { + basis = _basis; + } + + virtual Transform *make() const + { + return basis->smartCopy(); + } + +}; + +class TimeInvariantWrapperTransform : public MetaTransform +{ +public: + Resource transformSource; + + TimeInvariantWrapperTransform(Transform * basis) : transformSource(new TransformCopier(basis)) + { + baseTransform = basis; + } + + virtual void project(const Template &src, Template &dst) const + { + Transform * aTransform = transformSource.acquire(); + aTransform->projectUpdate(src,dst); + transformSource.release(aTransform); + } + + + void project(const TemplateList &src, TemplateList &dst) const + { + Transform * aTransform = transformSource.acquire(); + aTransform->projectUpdate(src,dst); + transformSource.release(aTransform); + } + + void train(const TemplateList &data) + { + baseTransform->train(data); + } + +private: + Transform * baseTransform; +}; + class DistributeTemplateTransform : public MetaTransform { Q_OBJECT @@ -598,6 +647,16 @@ class DistributeTemplateTransform : public MetaTransform public: + Transform * smartCopy() + { + if (!transform->timeVarying()) + return this; + + DistributeTemplateTransform * output = new DistributeTemplateTransform; + output->transform = transform->smartCopy(); + return output; + } + void train(const TemplateList &data) { transform->train(data); @@ -620,15 +679,6 @@ public: // Process the single elemnt templates in parallel if parallelism is enabled. void project(const TemplateList &src, TemplateList &dst) const { - // Little ugly, but if we own a timeVaryingTransform and this gets called - // cast off the const modifier and use projectUpdate. This allows us to - // act as a single point of entry. - if (transform->timeVarying()) - { - DistributeTemplateTransform * non_const = (DistributeTemplateTransform *) this; - non_const->projectUpdate(src,dst); - return; - } // Pre-allocate output for each template QList output_buffer; output_buffer.reserve(src.size()); @@ -655,15 +705,16 @@ public: void projectUpdate(const TemplateList &src, TemplateList &dst) { - if (!transform->timeVarying()) { - this->project(src, dst); - return; - } - this->transform->projectUpdate(src, dst); + this->project(src, dst); + return; } + void init() + { - private: + if (transform && transform->timeVarying()) + transform = new br::TimeInvariantWrapperTransform(transform); + } }; BR_REGISTER(Transform, DistributeTemplateTransform) diff --git a/openbr/plugins/misc.cpp b/openbr/plugins/misc.cpp index e46a8be..b16282d 100644 --- a/openbr/plugins/misc.cpp +++ b/openbr/plugins/misc.cpp @@ -15,8 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include - +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" using namespace cv; diff --git a/openbr/plugins/mongoose.cpp b/openbr/plugins/mongoose.cpp index bb51223..7b4cc45 100644 --- a/openbr/plugins/mongoose.cpp +++ b/openbr/plugins/mongoose.cpp @@ -1,4 +1,4 @@ -#include +#include "openbr_internal.h" #include namespace br diff --git a/openbr/plugins/nec3.cpp b/openbr/plugins/nec3.cpp index f94f6e0..099138e 100644 --- a/openbr/plugins/nec3.cpp +++ b/openbr/plugins/nec3.cpp @@ -4,7 +4,7 @@ #include -#include +#include "openbr_internal.h" #include "core/resource.h" using namespace br; diff --git a/openbr/plugins/neclatent1.cpp b/openbr/plugins/neclatent1.cpp index a84142a..cf1a461 100644 --- a/openbr/plugins/neclatent1.cpp +++ b/openbr/plugins/neclatent1.cpp @@ -1,8 +1,7 @@ -#include +#include "openbr_internal.h" #include -// necessary to allocate a large memory though the actual template size -// may be much smaller +// Necessary to allocate a large memory though the actual template size may be much smaller #define MAX_TEMPLATE_SIZE 400000 namespace br @@ -21,6 +20,7 @@ class NECLatent1Initialier : public Initializer { Globals->abbreviations.insert("NECTenprint1", "Open+Cvt(Gray)+NECLatent1Enroll:NECLatent1Compare"); Globals->abbreviations.insert("NECLatent1", "Open+Cvt(Gray)+NECLatent1Enroll(true):NECLatent1Compare"); + Globals->abbreviations.insert("NECLatentLFFS1", "Open+NECLatent1Enroll(true,ELFT_M):NECLatent1Compare(ELFT_M)"); } }; @@ -41,7 +41,8 @@ class NECLatent1EnrollTransform : public UntrainableTransform public: enum Algorithm { LFML, - ELFT }; + ELFT, + ELFT_M }; private: BR_PROPERTY(bool, latent, false) @@ -50,27 +51,35 @@ private: void project(const Template &src, Template &dst) const { if (src.m().type() != CV_8UC1) qFatal("Requires 8UC1 data!"); - unsigned char data[MAX_TEMPLATE_SIZE]; + uchar *data = src.m().data; + const int rows = src.m().rows; + const int columns = src.m().cols; + uchar buff[MAX_TEMPLATE_SIZE]; + uchar* pBuff = NULL; int size = 0; int error; if (latent) { - if (algorithm == LFML) error = NEC_LFML_ExtractLatent(src.m().data, src.m().rows, src.m().cols, 500, data, &size); - else error = NEC_ELFT_ExtractLatent(src.m().data, src.m().rows, src.m().cols, 500, 4, data, &size); + if (algorithm == LFML) error = NEC_LFML_ExtractLatent(data, rows, columns, 500, buff, &size); + else if (algorithm == ELFT) error = NEC_ELFT_ExtractLatent(data, rows, columns, 500, 4, buff, &size); + else error = NEC_ELFT_M_ExtractLatent(data, columns, 1, &pBuff, &size); } else { - if (algorithm == LFML) error = NEC_LFML_ExtractTenprint(src.m().data, src.m().rows, src.m().cols, 500, data, &size); - else error = NEC_ELFT_ExtractTenprint(src.m().data, src.m().rows, src.m().cols, 500, 2, data, &size); + if (algorithm == LFML) error = NEC_LFML_ExtractTenprint(data, rows, columns, 500, buff, &size); + else if (algorithm == ELFT) error = NEC_ELFT_ExtractTenprint(data, rows, columns, 500, 2, buff, &size); + else qFatal("ELFT_M Tenprint not implemented."); } if (!error) { cv::Mat n(1, size, CV_8UC1); - memcpy(n.data, data, size); + memcpy(n.data, buff, size); dst.m() = n; } else { qWarning("NECLatent1EnrollTransform error %d for file %s.", error, qPrintable(src.file.flat())); dst.m() = cv::Mat(); dst.file.set("FTE", true); } + + if (pBuff != NULL) NEC_ELFT_M_FreeTemplate(&pBuff); } }; @@ -89,17 +98,21 @@ class NECLatent1CompareDistance : public Distance public: enum Algorithm { LFML, - ELFT }; + ELFT, + ELFT_M }; private: BR_PROPERTY(Algorithm, algorithm, LFML) float compare(const Template &a, const Template &b) const { + uchar *aData = a.m().data; + uchar *bData = b.m().data; if (!a.m().data || !b.m().data) return -std::numeric_limits::max(); int score; - if (algorithm == LFML) NEC_LFML_Verify(b.m().data, b.m().total(), a.m().data, a.m().total(), &score); - else NEC_ELFT_Verify(b.m().data, a.m().data, &score, 2); + if (algorithm == LFML) NEC_LFML_Verify(bData, b.m().total(), aData, a.m().total(), &score); + else if (algorithm == ELFT) NEC_ELFT_Verify(bData, aData, &score, 1); + else NEC_ELFT_M_Verify(bData, aData, &score, 1); return score; } }; diff --git a/openbr/plugins/normalize.cpp b/openbr/plugins/normalize.cpp index 11c3f88..a3f4942 100644 --- a/openbr/plugins/normalize.cpp +++ b/openbr/plugins/normalize.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" @@ -58,6 +58,9 @@ class NormalizeTransform : public UntrainableTransform Q_ENUMS(NormType) Q_PROPERTY(NormType normType READ get_normType WRITE set_normType RESET reset_normType STORED false) + Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) + BR_PROPERTY(bool, ByRow, false) + public: /*!< */ enum NormType { Inf = NORM_INF, @@ -69,7 +72,16 @@ private: void project(const Template &src, Template &dst) const { - normalize(src, dst, 1, 0, normType, CV_32F); + if (!ByRow) normalize(src, dst, 1, 0, normType, CV_32F); + else { + dst = src; + for (int i=0; i #include #include -#include +#include "openbr_internal.h" //IRIS #include diff --git a/openbr/plugins/openbr_internal.h b/openbr/plugins/openbr_internal.h new file mode 100644 index 0000000..7c992b6 --- /dev/null +++ b/openbr/plugins/openbr_internal.h @@ -0,0 +1,184 @@ +#ifndef __OPENBR_INTERNAL_H +#define __OPENBR_INTERNAL_H + +#include "openbr/openbr_plugin.h" + +namespace br +{ +/*! + * \brief A br::Transform that does not require training data. + */ +class BR_EXPORT UntrainableTransform : public Transform +{ + Q_OBJECT + +protected: + UntrainableTransform(bool independent = true) : Transform(independent, false) {} /*!< \brief Construct an untrainable transform. */ + +private: + Transform *clone() const { return const_cast(this); } + void train(const TemplateList &data) { (void) data; } + void store(QDataStream &stream) const { (void) stream; } + void load(QDataStream &stream) { (void) stream; } +}; + +/*! + * \brief A br::MetaTransform that does not require training data. + */ +class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform +{ + Q_OBJECT + +protected: + UntrainableMetaTransform() : UntrainableTransform(false) {} +}; + +/*! + * \brief A br::Transform for which the results of project may change due to prior calls to project + */ +class BR_EXPORT TimeVaryingTransform : public Transform +{ + Q_OBJECT + +public: + virtual bool timeVarying() const { return true; } + + virtual void project(const Template &src, Template &dst) const + { + qFatal("No const project defined for time-varying transform"); + (void) dst; (void) src; + } + + virtual void project(const TemplateList &src, TemplateList &dst) const + { + qFatal("No const project defined for time-varying transform"); + (void) dst; (void) src; + } + + // Get a compile failure if this isn't here to go along with the other + // projectUpdate, no idea why + virtual void projectUpdate(const Template & src, Template & dst) + { + (void) src; (void) dst; + qFatal("do something useful"); + } + + virtual void projectUpdate(const TemplateList &src, TemplateList &dst) + { + foreach (const Template & src_part, src) { + Template out; + projectUpdate(src_part, out); + dst.append(out); + } + } + + /*! + *\brief For transforms that don't do any training, this default implementation + * which creates a new copy of the Transform from its description string is sufficient. + */ + virtual Transform * smartCopy() + { + return this->clone(); + } + + +protected: + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} +}; + +/*! + * \brief A br::Transform expecting multiple matrices per template. + */ +class BR_EXPORT MetaTransform : public Transform +{ + Q_OBJECT + +protected: + MetaTransform() : Transform(false) {} +}; + +/*! + * \brief A MetaTransform that aggregates some sub-transforms + */ +class BR_EXPORT CompositeTransform : public TimeVaryingTransform +{ + Q_OBJECT + +public: + Q_PROPERTY(QList transforms READ get_transforms WRITE set_transforms RESET reset_transforms) + BR_PROPERTY(QList, transforms, QList()) + + virtual void project(const Template &src, Template &dst) const + { + if (timeVarying()) qFatal("No const project defined for time-varying transform"); + _project(src, dst); + } + + virtual void project(const TemplateList &src, TemplateList &dst) const + { + if (timeVarying()) qFatal("No const project defined for time-varying transform"); + _project(src, dst); + } + + bool timeVarying() const { return isTimeVarying; } + + void init() + { + isTimeVarying = false; + trainable = false; + foreach (const br::Transform *transform, transforms) { + isTimeVarying = isTimeVarying || transform->timeVarying(); + trainable = trainable || transform->trainable; + } + } + + /*! + * \brief Composite transforms need to create a copy of themselves if they + * have any time-varying children. If this object is flagged as time-varying, + * it creates a new copy of its own class, and gives that copy the child transforms + * returned by calling smartCopy on this transforms children + */ + Transform * smartCopy() + { + if (!timeVarying()) + return this; + + QString name = metaObject()->className(); + name.replace("Transform",""); + name += "([])"; + name.replace("br::",""); + CompositeTransform * output = dynamic_cast(Transform::make(name, NULL)); + + if (output == NULL) + qFatal("Dynamic cast failed!"); + + foreach(Transform* t, transforms ) + { + Transform * maybe_copy = t->smartCopy(); + if (maybe_copy->parent() == NULL) + maybe_copy->setParent(output); + output->transforms.append(t->smartCopy()); + } + + output->file = this->file; + output->classes = classes; + output->instances = instances; + output->fraction = fraction; + + output->init(); + + return output; + } + +protected: + bool isTimeVarying; + + virtual void _project(const Template & src, Template & dst) const = 0; + virtual void _project(const TemplateList & src, TemplateList & dst) const = 0; + + CompositeTransform() : TimeVaryingTransform(false) {} +}; + +} + +#endif diff --git a/openbr/plugins/output.cpp b/openbr/plugins/output.cpp index 75d5ad1..33c1f75 100644 --- a/openbr/plugins/output.cpp +++ b/openbr/plugins/output.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include "openbr_internal.h" #include "openbr/core/bee.h" #include "openbr/core/common.h" diff --git a/openbr/plugins/pbd.cpp b/openbr/plugins/pbd.cpp index 14ad713..f3e1089 100644 --- a/openbr/plugins/pbd.cpp +++ b/openbr/plugins/pbd.cpp @@ -2,7 +2,7 @@ #include -#include +#include "openbr_internal.h" #include "core/opencvutils.h" diff --git a/openbr/plugins/pixel.cpp b/openbr/plugins/pixel.cpp index 03f69d1..a4795f4 100644 --- a/openbr/plugins/pixel.cpp +++ b/openbr/plugins/pixel.cpp @@ -14,7 +14,7 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/plugins.cmake b/openbr/plugins/plugins.cmake index 4672098..21af22d 100644 --- a/openbr/plugins/plugins.cmake +++ b/openbr/plugins/plugins.cmake @@ -1,7 +1,7 @@ # Add source to BR_THIRDPARTY_SRC # Add libs to BR_THIRDPARTY_LIBS -file(GLOB PLUGINS plugins/*.cpp) +file(GLOB PLUGINS plugins/*.cpp plugins/*.h) foreach(PLUGIN ${PLUGINS} ${BR_THIRDPARTY_PLUGINS}) get_filename_component(PLUGIN_BASENAME ${PLUGIN} NAME_WE) get_filename_component(PLUGIN_PATH ${PLUGIN} PATH) diff --git a/openbr/plugins/pp5.cpp b/openbr/plugins/pp5.cpp index 36309f6..c8227a0 100644 --- a/openbr/plugins/pp5.cpp +++ b/openbr/plugins/pp5.cpp @@ -11,8 +11,7 @@ #include #include #include -#include - +#include "openbr_internal.h" #include "openbr/core/resource.h" #define TRY(CC) \ diff --git a/openbr/plugins/qtnetwork.cpp b/openbr/plugins/qtnetwork.cpp index 1f717e9..cf80390 100644 --- a/openbr/plugins/qtnetwork.cpp +++ b/openbr/plugins/qtnetwork.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/quality.cpp b/openbr/plugins/quality.cpp index 92eafcc..6d34ff4 100644 --- a/openbr/plugins/quality.cpp +++ b/openbr/plugins/quality.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/quantize.cpp b/openbr/plugins/quantize.cpp index 45fdcbf..2a37edc 100644 --- a/openbr/plugins/quantize.cpp +++ b/openbr/plugins/quantize.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/quantize2.cpp b/openbr/plugins/quantize2.cpp index ea9a299..d392810 100644 --- a/openbr/plugins/quantize2.cpp +++ b/openbr/plugins/quantize2.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/random.cpp b/openbr/plugins/random.cpp index 1cbeff4..0201710 100644 --- a/openbr/plugins/random.cpp +++ b/openbr/plugins/random.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/reduce.cpp b/openbr/plugins/reduce.cpp index c17e3cd..70b968e 100644 --- a/openbr/plugins/reduce.cpp +++ b/openbr/plugins/reduce.cpp @@ -14,7 +14,7 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/regions.cpp b/openbr/plugins/regions.cpp index 6608e4c..c3feafb 100644 --- a/openbr/plugins/regions.cpp +++ b/openbr/plugins/regions.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/register.cpp b/openbr/plugins/register.cpp index 4af9f73..0536780 100644 --- a/openbr/plugins/register.cpp +++ b/openbr/plugins/register.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/sentence.cpp b/openbr/plugins/sentence.cpp index 9151364..8f43794 100644 --- a/openbr/plugins/sentence.cpp +++ b/openbr/plugins/sentence.cpp @@ -1,5 +1,5 @@ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/stasm.cpp b/openbr/plugins/stasm.cpp index 6a386cc..483968d 100644 --- a/openbr/plugins/stasm.cpp +++ b/openbr/plugins/stasm.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/stream.cpp b/openbr/plugins/stream.cpp index eea38ca..340712e 100644 --- a/openbr/plugins/stream.cpp +++ b/openbr/plugins/stream.cpp @@ -5,14 +5,12 @@ #include #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" #include "openbr/core/opencvutils.h" #include "openbr/core/qtutils.h" -#include - using namespace cv; namespace br @@ -258,12 +256,16 @@ public: next_idx = 0; basis = input; video.open(input.file.name.toStdString()); - return video.isOpened(); + video_ok = video.isOpened(); + return video_ok; } + bool video_ok; - bool isOpen() { return video.isOpened(); } + bool isOpen() { return video_ok; } - void close() { video.release(); } + void close() { + video.release(); + } private: bool getNext(FrameData & output) @@ -279,8 +281,8 @@ private: bool res = video.read(output.data.last().last()); if (!res) { - video.release(); - return false; + video_ok = false; + return video_ok; } output.data.last().file.set("FrameNumber", output.sequenceNumber); return true; @@ -299,7 +301,9 @@ public: TemplateDataSource(int maxFrames) : DataSource(maxFrames) { current_idx = INT_MAX; + data_ok = false; } + bool data_ok; bool open(Template &input) { @@ -309,10 +313,13 @@ public: final_frame = -1; last_issued = -2; - return isOpen(); + data_ok = current_idx < basis.size(); + return data_ok; } - bool isOpen() { return current_idx < basis.size() ; } + bool isOpen() { + return data_ok; + } void close() { @@ -323,7 +330,8 @@ public: private: bool getNext(FrameData & output) { - if (!isOpen()) + data_ok = current_idx < basis.size(); + if (!data_ok) return false; output.data.append(basis[current_idx]); @@ -332,6 +340,7 @@ private: output.sequenceNumber = next_sequence; next_sequence++; + output.data.last().file.set("FrameNumber", output.sequenceNumber); return true; } @@ -595,10 +604,6 @@ public: FrameData * run(FrameData * input, bool & should_continue) { - if (input != NULL) { - dataSource.returnFrame(input); - } - // Is there anything on our input buffer? If so we should start a thread with that. QWriteLocker lock(&statusLock); input = dataSource.tryGetFrame(); diff --git a/openbr/plugins/svm.cpp b/openbr/plugins/svm.cpp index aceb2a4..0fc0b0c 100644 --- a/openbr/plugins/svm.cpp +++ b/openbr/plugins/svm.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/synthetic.cpp b/openbr/plugins/synthetic.cpp index dd4025e..96af658 100644 --- a/openbr/plugins/synthetic.cpp +++ b/openbr/plugins/synthetic.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" #include "openbr/core/opencvutils.h" diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index 61193e4..ea1b6de 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" #include namespace br diff --git a/openbr/plugins/wavelet.cpp b/openbr/plugins/wavelet.cpp index 7fc829d..25c6511 100644 --- a/openbr/plugins/wavelet.cpp +++ b/openbr/plugins/wavelet.cpp @@ -15,7 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include -#include +#include "openbr_internal.h" using namespace cv; diff --git a/openbr/plugins/youtube.cpp b/openbr/plugins/youtube.cpp index 54a5d11..7ed114c 100644 --- a/openbr/plugins/youtube.cpp +++ b/openbr/plugins/youtube.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "openbr_internal.h" #include "openbr/core/common.h" diff --git a/share/openbr/openbr.svg b/share/openbr/openbr.svg new file mode 100644 index 0000000..943f225 --- /dev/null +++ b/share/openbr/openbr.svg @@ -0,0 +1,83 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + +