diff --git a/openbr/plugins/cmake/likely.cmake b/openbr/plugins/cmake/likely.cmake index ba894d6..6b7a114 100644 --- a/openbr/plugins/cmake/likely.cmake +++ b/openbr/plugins/cmake/likely.cmake @@ -5,6 +5,6 @@ if(${BR_WITH_LIKELY}) set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS}) else() set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/likely.cpp) - set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/lmat.cpp) - set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lmat.cpp) + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/lm.cpp) + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lm.cpp) endif() diff --git a/openbr/plugins/core/likely.cpp b/openbr/plugins/core/likely.cpp index 5c0854f..e3720a6 100644 --- a/openbr/plugins/core/likely.cpp +++ b/openbr/plugins/core/likely.cpp @@ -40,23 +40,26 @@ class LikelyTransform : public Transform qFatal("Failed to compile: %s", qPrintable(sourceFile)); } - void train(const TemplateList &) + void train(const TemplateList &trainingData) { + const likely_const_mat data = likelyFromOpenCVMats(trainingData.data().toVector().toStdVector()); + QByteArray sourceCode; QtUtils::readFile(sourceFile, sourceCode); // Pick settings to minimize code size - likely_settings settings; - settings.opt_level = 2; - settings.size_level = 2; - settings.multicore = false; - settings.heterogeneous = false; - settings.unroll_loops = false; - settings.vectorize_loops = false; - settings.verbose = false; + likely_settings settings = likely_default_settings(likely_file_bitcode, false); + settings.runtime_only = true; likely_mat output; - const likely_const_env parent = likely_standard(settings, &output, likely_file_bitcode); + likely_const_env parent = likely_standard(settings, &output, likely_file_bitcode); + + { // Construct an environment where `data` is accessible + const likely_const_env env = likely_define("data", data, parent); + likely_release_env(parent); + parent = env; + } + likely_release_env(likely_lex_parse_and_eval(sourceCode.data(), likely_guess_file_type(qPrintable(sourceFile)), parent)); likely_release_env(parent); @@ -64,6 +67,7 @@ class LikelyTransform : public Transform likely_release_mat(output); compile(); + likely_release_mat(data); } void project(const Template &src, Template &dst) const diff --git a/openbr/plugins/distance/emd.cpp b/openbr/plugins/distance/emd.cpp new file mode 100644 index 0000000..ba5e1c8 --- /dev/null +++ b/openbr/plugins/distance/emd.cpp @@ -0,0 +1,62 @@ +#include +#include + +using namespace cv; + +namespace br +{ + +/*! + * \ingroup distances + * \brief Computes Earth Mover's Distance + * \author Scott Klum \cite sklum + * \brief https://www.cs.duke.edu/~tomasi/papers/rubner/rubnerTr98.pdf + */ +class EMDDistance : public UntrainableDistance +{ + Q_OBJECT + + Q_ENUMS(Metric) + Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) + +public: + enum Metric { L1 = CV_DIST_L1, + L2 = CV_DIST_L2, + C = CV_DIST_C }; + +private: + BR_PROPERTY(Metric, metric, L2) + + float compare(const Template &a, const Template &b) const + { + const int dims_a = a.m().rows > 1 ? 3 : 2; + const int dims_b = b.m().rows > 1 ? 3 : 2; + + Mat sig_a(a.m().cols, dims_a, CV_32FC1); + Mat sig_b(b.m().cols, dims_b, CV_32FC1); + + for (int i=0; i(i*a.m().cols+j,0) = a.m().at(i,j); + sig_a.at(i*a.m().cols+j,1) = j; + if (dims_a == 3) sig_a.at(i*a.m().cols+j,2) = i; + } + } + + for (int i=0; i(i*b.m().cols+j,0) = b.m().at(i,j); + sig_b.at(i*b.m().cols+j,1) = j; + if (dims_b == 3) sig_a.at(i*b.m().cols+j,2) = i; + } + } + + return EMD(sig_a,sig_b,metric); + } +}; + +BR_REGISTER(Distance, EMDDistance) + +} // namespace br + +#include "distance/emd.moc" diff --git a/openbr/plugins/format/lmat.cpp b/openbr/plugins/format/lm.cpp index 9dc2ed2..ac1308e 100644 --- a/openbr/plugins/format/lmat.cpp +++ b/openbr/plugins/format/lm.cpp @@ -13,7 +13,7 @@ namespace br * www.liblikely.org * \author Josh Klontz \cite jklontz */ -class lmatFormat : public Format +class lmFormat : public Format { Q_OBJECT @@ -33,8 +33,8 @@ class lmatFormat : public Format } }; -BR_REGISTER(Format, lmatFormat) +BR_REGISTER(Format, lmFormat) } // namespace br -#include "format/lmat.moc" +#include "format/lm.moc" diff --git a/openbr/plugins/gallery/lmat.cpp b/openbr/plugins/gallery/lm.cpp index 1818d01..a0ed972 100644 --- a/openbr/plugins/gallery/lmat.cpp +++ b/openbr/plugins/gallery/lm.cpp @@ -14,22 +14,30 @@ namespace br * www.liblikely.org * \author Josh Klontz \cite jklontz */ -class lmatGallery : public Gallery +class lmGallery : public Gallery { Q_OBJECT QList mats; - ~lmatGallery() + ~lmGallery() { - const likely_const_mat m = likelyFromOpenCVMat(OpenCVUtils::toMatByRow(mats)); - likely_write(m, qPrintable(file.name)); + if (mats.empty()) + return; + likely_const_mat m = likelyFromOpenCVMats(mats.toVector().toStdVector()); + if (!likely_write(m, qPrintable(file.name))) + qFatal("Write failed"); likely_release_mat(m); } TemplateList readBlock(bool *done) { *done = true; - qFatal("Not supported."); + TemplateList templates; + const likely_const_mat m = likely_read(qPrintable(file.name), likely_file_matrix, likely_void); + foreach (const cv::Mat &mat, likelyToOpenCVMats(m)) + templates.append(mat); + likely_release_mat(m); + return templates; } void write(const Template &t) @@ -38,8 +46,8 @@ class lmatGallery : public Gallery } }; -BR_REGISTER(Gallery, lmatGallery) +BR_REGISTER(Gallery, lmGallery) } // namespace br -#include "gallery/lmat.moc" +#include "gallery/lm.moc" diff --git a/openbr/plugins/gallery/video.cpp b/openbr/plugins/gallery/video.cpp index 90fb2ff..2c9bba2 100644 --- a/openbr/plugins/gallery/video.cpp +++ b/openbr/plugins/gallery/video.cpp @@ -77,7 +77,7 @@ public: idx++; TemplateList rVal; - rVal.append(temp); + rVal.append(output); *done = false; return rVal; } diff --git a/share/openbr/likely/face_recognition.tex b/share/openbr/likely/face_recognition.tex new file mode 100644 index 0000000..09b10e3 --- /dev/null +++ b/share/openbr/likely/face_recognition.tex @@ -0,0 +1,39 @@ +\documentclass{article} +\usepackage{verbatim} + +\newenvironment{likely} +{ \verbatim } +{ \endverbatim } + +\title{Likely Port: Face Recognition} +\author{Joshua C. Klontz} +\date{\today} +\begin{document} +\maketitle + +\begin{abstract} +This document represents a long-term effort to port the OpenBR face recognition algorithm to Likely\footnote{www.liblikely.org}. +As Likely is a literate programming language, this document is both the source code \emph{and} the documentation. +\end{abstract} + +\section{Consolidated Algorithm} +The top level definition of the face recognition algorithm. + +\begin{likely} +face-recognition := + src :-> + { + dst := src.imitate + (dst src) :=> + dst :<- src + } +\end{likely} + +\section{Entry Point} +The entry point to the outside world is a single C function \texttt{face\_recognition} that takes as input a \texttt{likely\_mat} (the input image) and outputs a new \texttt{likely\_mat} (the feature vector). + +\begin{likely} +(extern u8CXY "face_recognition" u8CXY face-recognition) +\end{likely} + +\end{document} \ No newline at end of file