Commit c1a1921a62621a0358b41c0c5950061e04bcec09

Authored by sklum
2 parents 3f40433a fe7a2c4d

Merge branch 'master' of https://github.com/biometrics/openbr

openbr/openbr_plugin.cpp
@@ -234,6 +234,11 @@ void File::appendRect(const QRectF &rect) @@ -234,6 +234,11 @@ void File::appendRect(const QRectF &rect)
234 m_metadata["Rects"] = newRects; 234 m_metadata["Rects"] = newRects;
235 } 235 }
236 236
  237 +void File::appendRect(const Rect &rect)
  238 +{
  239 + appendRect(OpenCVUtils::fromRect(rect));
  240 +}
  241 +
237 void File::appendRects(const QList<QRectF> &rects) 242 void File::appendRects(const QList<QRectF> &rects)
238 { 243 {
239 QList<QVariant> newRects = m_metadata["Rects"].toList(); 244 QList<QVariant> newRects = m_metadata["Rects"].toList();
@@ -242,6 +247,11 @@ void File::appendRects(const QList&lt;QRectF&gt; &amp;rects) @@ -242,6 +247,11 @@ void File::appendRects(const QList&lt;QRectF&gt; &amp;rects)
242 m_metadata["Rects"] = newRects; 247 m_metadata["Rects"] = newRects;
243 } 248 }
244 249
  250 +void File::appendRects(const QList<Rect> &rects)
  251 +{
  252 + appendRects(OpenCVUtils::fromRects(rects));
  253 +}
  254 +
245 /* File - private methods */ 255 /* File - private methods */
246 void File::init(const QString &file) 256 void File::init(const QString &file)
247 { 257 {
openbr/openbr_plugin.h
@@ -41,8 +41,6 @@ @@ -41,8 +41,6 @@
41 #include <QVector> 41 #include <QVector>
42 #include <opencv2/core/core.hpp> 42 #include <opencv2/core/core.hpp>
43 #include <openbr/openbr.h> 43 #include <openbr/openbr.h>
44 -#include <openbr/core/qtutils.h>  
45 -#include <openbr/core/opencvutils.h>  
46 44
47 /*! 45 /*!
48 * \defgroup cpp_plugin_sdk C++ Plugin SDK 46 * \defgroup cpp_plugin_sdk C++ Plugin SDK
@@ -222,7 +220,11 @@ struct BR_EXPORT File @@ -222,7 +220,11 @@ struct BR_EXPORT File
222 template <typename T> 220 template <typename T>
223 void setList(const QString &key, const QList<T> &value) 221 void setList(const QString &key, const QList<T> &value)
224 { 222 {
225 - set(key, QtUtils::toVariantList(value)); 223 + QVariantList variantList;
  224 + variantList.reserve(value.size());
  225 + foreach (const T &item, value)
  226 + variantList << item;
  227 + set(key, variantList);
226 } 228 }
227 229
228 inline void remove(const QString &key) { m_metadata.remove(key); } /*!< \brief Remove the metadata key. */ 230 inline void remove(const QString &key) { m_metadata.remove(key); } /*!< \brief Remove the metadata key. */
@@ -315,9 +317,9 @@ struct BR_EXPORT File @@ -315,9 +317,9 @@ struct BR_EXPORT File
315 QList<QRectF> namedRects() const; /*!< \brief Returns rects convertible from metadata values. */ 317 QList<QRectF> namedRects() const; /*!< \brief Returns rects convertible from metadata values. */
316 QList<QRectF> rects() const; /*!< \brief Returns the file's rects list. */ 318 QList<QRectF> rects() const; /*!< \brief Returns the file's rects list. */
317 void appendRect(const QRectF &rect); /*!< \brief Adds a rect to the file's rect list. */ 319 void appendRect(const QRectF &rect); /*!< \brief Adds a rect to the file's rect list. */
318 - void appendRect(const cv::Rect &rect) { appendRect(OpenCVUtils::fromRect(rect)); } /*!< \brief Adds a rect to the file's rect list. */ 320 + void appendRect(const cv::Rect &rect); /*!< \brief Adds a rect to the file's rect list. */
319 void appendRects(const QList<QRectF> &rects); /*!< \brief Adds rects to the file's rect list. */ 321 void appendRects(const QList<QRectF> &rects); /*!< \brief Adds rects to the file's rect list. */
320 - void appendRects(const QList<cv::Rect> &rects) { appendRects(OpenCVUtils::fromRects(rects)); } /*!< \brief Adds rects to the file's rect list. */ 322 + void appendRects(const QList<cv::Rect> &rects); /*!< \brief Adds rects to the file's rect list. */
321 inline void clearRects() { m_metadata["Rects"] = QList<QVariant>(); } /*!< \brief Clears the file's rect list. */ 323 inline void clearRects() { m_metadata["Rects"] = QList<QVariant>(); } /*!< \brief Clears the file's rect list. */
322 inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ 324 inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
323 inline void setRects(const QList<cv::Rect> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ 325 inline void setRects(const QList<cv::Rect> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
openbr/plugins/eigen3.cpp
@@ -302,11 +302,13 @@ class LDATransform : public Transform @@ -302,11 +302,13 @@ class LDATransform : public Transform
302 Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false) 302 Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false)
303 Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false) 303 Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false)
304 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) 304 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  305 + Q_PROPERTY(bool isBinary READ get_isBinary WRITE set_isBinary RESET reset_isBinary STORED false)
305 BR_PROPERTY(float, pcaKeep, 0.98) 306 BR_PROPERTY(float, pcaKeep, 0.98)
306 BR_PROPERTY(bool, pcaWhiten, false) 307 BR_PROPERTY(bool, pcaWhiten, false)
307 BR_PROPERTY(int, directLDA, 0) 308 BR_PROPERTY(int, directLDA, 0)
308 BR_PROPERTY(float, directDrop, 0.1) 309 BR_PROPERTY(float, directDrop, 0.1)
309 BR_PROPERTY(QString, inputVariable, "Label") 310 BR_PROPERTY(QString, inputVariable, "Label")
  311 + BR_PROPERTY(bool, isBinary, false)
310 312
311 int dimsOut; 313 int dimsOut;
312 Eigen::VectorXf mean; 314 Eigen::VectorXf mean;
@@ -316,7 +318,6 @@ class LDATransform : public Transform @@ -316,7 +318,6 @@ class LDATransform : public Transform
316 { 318 {
317 // creates "Label" 319 // creates "Label"
318 TemplateList trainingSet = TemplateList::relabel(_trainingSet, inputVariable); 320 TemplateList trainingSet = TemplateList::relabel(_trainingSet, inputVariable);
319 -  
320 int instances = trainingSet.size(); 321 int instances = trainingSet.size();
321 322
322 // Perform PCA dimensionality reduction 323 // Perform PCA dimensionality reduction
@@ -450,6 +451,34 @@ class LDATransform : public Transform @@ -450,6 +451,34 @@ class LDATransform : public Transform
450 // Compute final projection matrix 451 // Compute final projection matrix
451 projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); 452 projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose();
452 dimsOut = dim2; 453 dimsOut = dim2;
  454 +
  455 + if (isBinary) {
  456 + assert(dimsOut == 1);
  457 + TemplateList projected;
  458 + float posVal = 0;
  459 + float negVal = 0;
  460 + for (int i = 0; i < trainingSet.size(); i++) {
  461 + Template t;
  462 + project(trainingSet[i],t);
  463 + //Note: the positive class is assumed to be 0 b/c it will
  464 + // typically be the first gallery template in the TemplateList structure
  465 + if (classes[i] == 0)
  466 + posVal += t.m().at<float>(0,0);
  467 + else if (classes[i] == 1)
  468 + negVal += t.m().at<float>(0,0);
  469 + else
  470 + qFatal("Binary mode only supports two class problems.");
  471 + }
  472 + posVal /= classCounts[0];
  473 + negVal /= classCounts[1];
  474 +
  475 + if (posVal < negVal) {
  476 + //Ensure positive value is supposed to be > 0 after projection
  477 + Eigen::MatrixXf invert = Eigen::MatrixXf::Ones(dimsIn,1);
  478 + invert *= -1;
  479 + projection = invert.transpose() * projection;
  480 + }
  481 + }
453 } 482 }
454 483
455 void project(const Template &src, Template &dst) const 484 void project(const Template &src, Template &dst) const
@@ -462,6 +491,10 @@ class LDATransform : public Transform @@ -462,6 +491,10 @@ class LDATransform : public Transform
462 491
463 // Do projection 492 // Do projection
464 outMap = projection.transpose() * (inMap - mean); 493 outMap = projection.transpose() * (inMap - mean);
  494 +
  495 + if (isBinary) {
  496 + dst.file.set("conf",dst.m().at<float>(0,0));
  497 + }
465 } 498 }
466 499
467 void store(QDataStream &stream) const 500 void store(QDataStream &stream) const
openbr/plugins/slidingwindow.cpp
@@ -8,11 +8,29 @@ @@ -8,11 +8,29 @@
8 8
9 using namespace cv; 9 using namespace cv;
10 10
  11 +namespace br
  12 +{
  13 +
11 // Because MSVC doesn't provide a round() function in math.h 14 // Because MSVC doesn't provide a round() function in math.h
12 static int round(float x) { return (floor(x + 0.5)); } 15 static int round(float x) { return (floor(x + 0.5)); }
13 -  
14 -namespace br 16 +// Find avg aspect ratio
  17 +static float getAspectRatio(const TemplateList &data)
15 { 18 {
  19 + double tempRatio = 0;
  20 + int ratioCnt = 0;
  21 +
  22 + foreach (const Template &tmpl, data) {
  23 + QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
  24 + foreach (const Rect &posRect, posRects) {
  25 + if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) {
  26 + continue;
  27 + }
  28 + tempRatio += (float)posRect.width / (float)posRect.height;
  29 + ratioCnt += 1;
  30 + }
  31 + }
  32 + return tempRatio / (double)ratioCnt;
  33 +}
16 34
17 /*! 35 /*!
18 * \ingroup transforms 36 * \ingroup transforms
@@ -25,23 +43,19 @@ class SlidingWindowTransform : public Transform @@ -25,23 +43,19 @@ class SlidingWindowTransform : public Transform
25 Q_OBJECT 43 Q_OBJECT
26 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) 44 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
27 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) 45 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false)
28 - Q_PROPERTY(double scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)  
29 Q_PROPERTY(int stepSize READ get_stepSize WRITE set_stepSize RESET reset_stepSize STORED false) 46 Q_PROPERTY(int stepSize READ get_stepSize WRITE set_stepSize RESET reset_stepSize STORED false)
30 - Q_PROPERTY(bool takeLargestScale READ get_takeLargestScale WRITE set_takeLargestScale RESET reset_takeLargestScale STORED false) 47 + Q_PROPERTY(bool takeFirst READ get_takeFirst WRITE set_takeFirst RESET reset_takeFirst STORED false)
31 Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false) 48 Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false)
32 Q_PROPERTY(int negToPosRatio READ get_negToPosRatio WRITE set_negToPosRatio RESET reset_negToPosRatio STORED false) 49 Q_PROPERTY(int negToPosRatio READ get_negToPosRatio WRITE set_negToPosRatio RESET reset_negToPosRatio STORED false)
33 Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false) 50 Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false)
34 - Q_PROPERTY(float aspectRatio READ get_aspectRatio WRITE set_aspectRatio RESET reset_aspectRatio STORED true)  
35 Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false) 51 Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
36 BR_PROPERTY(br::Transform *, transform, NULL) 52 BR_PROPERTY(br::Transform *, transform, NULL)
37 BR_PROPERTY(int, minSize, 8) 53 BR_PROPERTY(int, minSize, 8)
38 - BR_PROPERTY(double, scaleFactor, 0.75)  
39 BR_PROPERTY(int, stepSize, 1) 54 BR_PROPERTY(int, stepSize, 1)
40 - BR_PROPERTY(bool, takeLargestScale, true) 55 + BR_PROPERTY(bool, takeFirst, true)
41 BR_PROPERTY(bool, negSamples, true) 56 BR_PROPERTY(bool, negSamples, true)
42 BR_PROPERTY(int, negToPosRatio, 1) 57 BR_PROPERTY(int, negToPosRatio, 1)
43 BR_PROPERTY(double, maxOverlap, 0) 58 BR_PROPERTY(double, maxOverlap, 0)
44 - BR_PROPERTY(float, aspectRatio, 1)  
45 BR_PROPERTY(int, windowWidth, 24) 59 BR_PROPERTY(int, windowWidth, 24)
46 60
47 public: 61 public:
@@ -50,24 +64,14 @@ private: @@ -50,24 +64,14 @@ private:
50 64
51 void train(const TemplateList &data) 65 void train(const TemplateList &data)
52 { 66 {
  67 + // only calculate if the work hasn't been done
  68 + aspectRatio = data.first().file.get<float>("aspectRatio", -1);
  69 + if (aspectRatio == -1)
  70 + aspectRatio = getAspectRatio(data);
  71 +
53 if (transform->trainable) { 72 if (transform->trainable) {
54 - double tempRatio = 0;  
55 - int ratioCnt = 0;  
56 TemplateList full; 73 TemplateList full;
57 74
58 - //First find avg aspect ratio  
59 - foreach (const Template &tmpl, data) {  
60 - QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());  
61 - foreach (const Rect &posRect, posRects) {  
62 - if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) {  
63 - continue;  
64 - }  
65 - tempRatio += (float)posRect.width / (float)posRect.height;  
66 - ratioCnt += 1;  
67 - }  
68 - }  
69 - aspectRatio = tempRatio / (double)ratioCnt;  
70 -  
71 foreach (const Template &tmpl, data) { 75 foreach (const Template &tmpl, data) {
72 QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects()); 76 QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
73 QList<Rect> negRects; 77 QList<Rect> negRects;
@@ -132,6 +136,72 @@ private: @@ -132,6 +136,72 @@ private:
132 if (src.file.getBool("Train", false)) return; 136 if (src.file.getBool("Train", false)) return;
133 137
134 dst.file.clearRects(); 138 dst.file.clearRects();
  139 + int windowHeight = (int) round((float) windowWidth / aspectRatio);
  140 + int scale = src.file.get<float>("scale", 1);
  141 +
  142 + for (double y = 0; y + windowHeight < src.m().rows; y += stepSize) {
  143 + for (double x = 0; x + windowWidth < src.m().cols; x += stepSize) {
  144 + Rect window(x, y, windowWidth, windowHeight);
  145 + Template windowMat(src.file, Mat(src, window));
  146 + Template detect;
  147 + transform->project(windowMat, detect);
  148 + float conf = detect.file.get<float>("conf");
  149 +
  150 + // the result will be in the Label
  151 + if (conf > 0) {
  152 + dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale));
  153 + QList<float> confidences = dst.file.getList<float>("Confidences", QList<float>());
  154 + confidences.append(conf);
  155 + dst.file.setList<float>("Confidences", confidences);
  156 + if (takeFirst)
  157 + return;
  158 + }
  159 + }
  160 + }
  161 + }
  162 +
  163 + float aspectRatio;
  164 +};
  165 +
  166 +BR_REGISTER(Transform, SlidingWindowTransform)
  167 +
  168 +/*!
  169 + * \ingroup transforms
  170 + * \brief .
  171 + * \author Austin Blanton \cite imaus10
  172 + */
  173 +class BuildScalesTransform : public Transform
  174 +{
  175 + Q_OBJECT
  176 + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
  177 + Q_PROPERTY(double scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
  178 + Q_PROPERTY(bool takeLargestScale READ get_takeLargestScale WRITE set_takeLargestScale RESET reset_takeLargestScale STORED false)
  179 + Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
  180 + BR_PROPERTY(br::Transform *, transform, NULL)
  181 + BR_PROPERTY(double, scaleFactor, 0.75)
  182 + BR_PROPERTY(bool, takeLargestScale, true)
  183 + BR_PROPERTY(int, windowWidth, 24)
  184 +
  185 +public:
  186 + BuildScalesTransform() : Transform(false, true) {}
  187 +private:
  188 +
  189 + void train(const TemplateList &data)
  190 + {
  191 + aspectRatio = getAspectRatio(data);
  192 + // have to make a copy b/c data is const
  193 + TemplateList cp = data;
  194 + cp.first().file.set("aspectRatio", aspectRatio);
  195 + if (transform->trainable)
  196 + transform->train(cp);
  197 + }
  198 +
  199 + void project(const Template &src, Template &dst) const
  200 + {
  201 + dst = src;
  202 + // do not scale images during training
  203 + if (src.file.getBool("Train", false)) return;
  204 +
135 int rows = src.m().rows; 205 int rows = src.m().rows;
136 int cols = src.m().cols; 206 int cols = src.m().cols;
137 int windowHeight = (int) round((float) windowWidth / aspectRatio); 207 int windowHeight = (int) round((float) windowWidth / aspectRatio);
@@ -140,34 +210,20 @@ private: @@ -140,34 +210,20 @@ private:
140 startScale = round((float) rows / (float) windowHeight); 210 startScale = round((float) rows / (float) windowHeight);
141 else 211 else
142 startScale = round((float) cols / (float) windowWidth); 212 startScale = round((float) cols / (float) windowWidth);
143 -  
144 for (float scale = startScale; scale >= 1.0; scale -= (1.0 - scaleFactor)) { 213 for (float scale = startScale; scale >= 1.0; scale -= (1.0 - scaleFactor)) {
145 - Mat scaleImg; 214 + Template scaleImg(src.file, Mat());
  215 + scaleImg.file.set("scale", scale);
146 resize(src, scaleImg, Size(round(cols / scale), round(rows / scale))); 216 resize(src, scaleImg, Size(round(cols / scale), round(rows / scale)));
147 -  
148 - for (double y = 0; y + windowHeight < scaleImg.rows; y += stepSize) {  
149 - for (double x = 0; x + windowWidth < scaleImg.cols; x += stepSize) {  
150 -qDebug() << "x=" << x << "\ty=" << y;  
151 - Rect window(x, y, windowWidth, windowHeight);  
152 - Template windowMat(src.file, Mat(scaleImg, window));  
153 - Template detect;  
154 - transform->project(windowMat, detect);  
155 - // the result will be in the Label  
156 - if (detect.file.get<QString>("Label") == "pos") {  
157 - dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale));  
158 - float confidence = detect.file.get<float>("Dist");  
159 - QList<float> confidences = dst.file.getList<float>("Confidences", QList<float>());  
160 - confidences.append(confidence);  
161 - dst.file.setList<float>("Confidences", confidences);  
162 - if (takeLargestScale) return;  
163 - }  
164 - }  
165 - } 217 + transform->project(scaleImg, dst);
  218 + if (takeLargestScale && !dst.file.rects().empty())
  219 + return;
166 } 220 }
167 } 221 }
  222 +
  223 + float aspectRatio;
168 }; 224 };
169 225
170 -BR_REGISTER(Transform, SlidingWindowTransform) 226 +BR_REGISTER(Transform, BuildScalesTransform)
171 227
172 /*! 228 /*!
173 * \ingroup transforms 229 * \ingroup transforms
openbr/plugins/svm.cpp
@@ -157,7 +157,7 @@ private: @@ -157,7 +157,7 @@ private:
157 dst = src; 157 dst = src;
158 float prediction = svm.predict(src.m().reshape(1, 1), returnDFVal); 158 float prediction = svm.predict(src.m().reshape(1, 1), returnDFVal);
159 if (returnDFVal) { 159 if (returnDFVal) {
160 - dst.file.set("Dist", prediction); 160 + dst.file.set("conf", prediction);
161 // positive values ==> first class 161 // positive values ==> first class
162 // negative values ==> second class 162 // negative values ==> second class
163 prediction = prediction > 0 ? 0 : 1; 163 prediction = prediction > 0 ? 0 : 1;