Commit 69df11eb405aef9bb0587f1ce6e2bd46843c2088

Authored by sklum
2 parents 9cf029b5 2cc56616

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

Conflicts:
	openbr/core/core.cpp
openbr/core/core.cpp
@@ -139,7 +139,6 @@ struct AlgorithmCore @@ -139,7 +139,6 @@ struct AlgorithmCore
139 downcast->transforms[0] = this->transform.data(); 139 downcast->transforms[0] = this->transform.data();
140 downcast->init(); 140 downcast->init();
141 141
142 -  
143 downcast->projectUpdate(i,i); 142 downcast->projectUpdate(i,i);
144 143
145 return i.files(); 144 return i.files();
openbr/core/qtutils.cpp
@@ -399,33 +399,31 @@ void showFile(const QString &file) @@ -399,33 +399,31 @@ void showFile(const QString &file)
399 399
400 QString toString(const QVariant &variant) 400 QString toString(const QVariant &variant)
401 { 401 {
402 - if (variant.canConvert(QVariant::String))  
403 - return variant.toString();  
404 - else if(variant.canConvert(QVariant::PointF)) {  
405 - QPointF pt = qvariant_cast<QPointF>(variant);  
406 - return QString("(%1,%2)").arg(QString::number(pt.x()),  
407 - QString::number(pt.y()));  
408 - }  
409 - else if (variant.canConvert(QVariant::RectF)) { 402 + if (variant.canConvert(QVariant::List)) return toString(qvariant_cast<QVariantList>(variant));
  403 + else if (variant.canConvert(QVariant::String)) return variant.toString();
  404 + else if (variant.canConvert(QVariant::PointF)) {
  405 + QPointF point = qvariant_cast<QPointF>(variant);
  406 + return QString("(%1,%2)").arg(QString::number(point.x()),QString::number(point.y()));
  407 + } else if (variant.canConvert(QVariant::RectF)) {
410 QRectF rect = qvariant_cast<QRectF>(variant); 408 QRectF rect = qvariant_cast<QRectF>(variant);
411 return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()), 409 return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()),
412 QString::number(rect.y()), 410 QString::number(rect.y()),
413 QString::number(rect.width()), 411 QString::number(rect.width()),
414 QString::number(rect.height())); 412 QString::number(rect.height()));
415 } 413 }
416 - else if (variant.canConvert(QVariant::List)) {  
417 - QString ret = QString("[");  
418 - bool first = true;  
419 - foreach (const QVariant &i, variant.toList()) {  
420 - if (!first)  
421 - ret += ",";  
422 - else  
423 - first = false;  
424 - ret += toString(i);  
425 - }  
426 - ret += "]";  
427 - return ret;  
428 - } 414 +
  415 + return QString();
  416 +}
  417 +
  418 +QString toString(const QVariantList &variantList)
  419 +{
  420 + QStringList variants;
  421 +
  422 + foreach(const QVariant &variant, variantList)
  423 + variants.append(toString(variant));
  424 +
  425 + if (!variants.isEmpty()) return "[" + variants.join(", ") + "]";
  426 +
429 return QString(); 427 return QString();
430 } 428 }
431 429
openbr/core/qtutils.h
@@ -74,6 +74,7 @@ namespace QtUtils @@ -74,6 +74,7 @@ namespace QtUtils
74 74
75 /**** Variant Utilities ****/ 75 /**** Variant Utilities ****/
76 QString toString(const QVariant &variant); 76 QString toString(const QVariant &variant);
  77 + QString toString(const QVariantList &variantList);
77 78
78 template <typename T> 79 template <typename T>
79 QVariantList toVariantList(const QList<T> &list) 80 QVariantList toVariantList(const QList<T> &list)
openbr/openbr_plugin.cpp
@@ -58,16 +58,7 @@ QString File::flat() const @@ -58,16 +58,7 @@ QString File::flat() const
58 foreach (const QString &key, keys) { 58 foreach (const QString &key, keys) {
59 const QVariant value = this->value(key); 59 const QVariant value = this->value(key);
60 if (value.isNull()) values.append(key); 60 if (value.isNull()) values.append(key);
61 - else {  
62 - if (QString(value.typeName()) == "QVariantList") {  
63 - QStringList variants;  
64 - foreach(const QVariant &variant, qvariant_cast<QVariantList>(value)) {  
65 - variants.append(QtUtils::toString(variant));  
66 - }  
67 - if (!variants.isEmpty()) values.append(key + "=[" + variants.join(", ") + "]");  
68 - }  
69 - else values.append(key + "=" + QtUtils::toString(value));  
70 - } 61 + else values.append(key + "=" + QtUtils::toString(value));
71 } 62 }
72 63
73 QString flat = name; 64 QString flat = name;
openbr/plugins/regions.cpp
@@ -345,9 +345,12 @@ class RectFromPointsTransform : public UntrainableTransform @@ -345,9 +345,12 @@ class RectFromPointsTransform : public UntrainableTransform
345 345
346 dst.file.setPoints(points); 346 dst.file.setPoints(points);
347 347
348 - if (crop) dst.m() = src.m()(Rect(std::max(0.0, minX - deltaWidth/2.0), std::max(0.0, minY - deltaHeight/2.0), std::min((double)src.m().cols, width), std::min((double)src.m().rows, height))); 348 + const int x = std::max(0.0, minX - deltaWidth/2.0);
  349 + const int y = std::max(0.0, minY - deltaHeight/2.0);
  350 +
  351 + if (crop) dst.m() = src.m()(Rect(x, y, std::min((double)src.m().cols-x, width), std::min((double)src.m().rows-y, height)));
349 else { 352 else {
350 - dst.file.appendRect(QRectF(std::max(0.0, minX - deltaWidth/2.0), std::max(0.0, minY - deltaHeight/2.0), std::min((double)src.m().cols, width), std::min((double)src.m().rows, height))); 353 + dst.file.appendRect(QRectF(x, y, std::min((double)src.m().cols-x, width), std::min((double)src.m().rows-y, height)));
351 dst.m() = src.m(); 354 dst.m() = src.m();
352 } 355 }
353 } 356 }
openbr/plugins/slidingwindow.cpp
@@ -8,12 +8,28 @@ @@ -8,12 +8,28 @@
8 8
9 using namespace cv; 9 using namespace cv;
10 10
11 -// Because MSVC doesn't provide a round() function in math.h  
12 -static int round(float x) { return (floor(x + 0.5)); }  
13 -  
14 namespace br 11 namespace br
15 { 12 {
16 13
  14 +// Find avg aspect ratio
  15 +static float getAspectRatio(const TemplateList &data)
  16 +{
  17 + double tempRatio = 0;
  18 + int ratioCnt = 0;
  19 +
  20 + foreach (const Template &tmpl, data) {
  21 + QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
  22 + foreach (const Rect &posRect, posRects) {
  23 + if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) {
  24 + continue;
  25 + }
  26 + tempRatio += (float)posRect.width / (float)posRect.height;
  27 + ratioCnt += 1;
  28 + }
  29 + }
  30 + return tempRatio / (double)ratioCnt;
  31 +}
  32 +
17 /*! 33 /*!
18 * \ingroup transforms 34 * \ingroup transforms
19 * \brief Applies a transform to a sliding window. 35 * \brief Applies a transform to a sliding window.
@@ -25,23 +41,19 @@ class SlidingWindowTransform : public Transform @@ -25,23 +41,19 @@ class SlidingWindowTransform : public Transform
25 Q_OBJECT 41 Q_OBJECT
26 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) 42 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) 43 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) 44 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) 45 + 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) 46 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) 47 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) 48 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) 49 Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
36 BR_PROPERTY(br::Transform *, transform, NULL) 50 BR_PROPERTY(br::Transform *, transform, NULL)
37 BR_PROPERTY(int, minSize, 8) 51 BR_PROPERTY(int, minSize, 8)
38 - BR_PROPERTY(double, scaleFactor, 0.75)  
39 BR_PROPERTY(int, stepSize, 1) 52 BR_PROPERTY(int, stepSize, 1)
40 - BR_PROPERTY(bool, takeLargestScale, true) 53 + BR_PROPERTY(bool, takeFirst, true)
41 BR_PROPERTY(bool, negSamples, true) 54 BR_PROPERTY(bool, negSamples, true)
42 BR_PROPERTY(int, negToPosRatio, 1) 55 BR_PROPERTY(int, negToPosRatio, 1)
43 BR_PROPERTY(double, maxOverlap, 0) 56 BR_PROPERTY(double, maxOverlap, 0)
44 - BR_PROPERTY(float, aspectRatio, 1)  
45 BR_PROPERTY(int, windowWidth, 24) 57 BR_PROPERTY(int, windowWidth, 24)
46 58
47 public: 59 public:
@@ -50,24 +62,14 @@ private: @@ -50,24 +62,14 @@ private:
50 62
51 void train(const TemplateList &data) 63 void train(const TemplateList &data)
52 { 64 {
  65 + // only calculate if the work hasn't been done
  66 + aspectRatio = data.first().file.get<float>("aspectRatio", -1);
  67 + if (aspectRatio == -1)
  68 + aspectRatio = getAspectRatio(data);
  69 +
53 if (transform->trainable) { 70 if (transform->trainable) {
54 - double tempRatio = 0;  
55 - int ratioCnt = 0;  
56 TemplateList full; 71 TemplateList full;
57 72
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) { 73 foreach (const Template &tmpl, data) {
72 QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects()); 74 QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
73 QList<Rect> negRects; 75 QList<Rect> negRects;
@@ -83,7 +85,7 @@ private: @@ -83,7 +85,7 @@ private:
83 } 85 }
84 86
85 Mat scaledImg; 87 Mat scaledImg;
86 - resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,round(windowWidth / aspectRatio))); 88 + resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,qRound(windowWidth / aspectRatio)));
87 Template pos(tmpl.file, scaledImg); 89 Template pos(tmpl.file, scaledImg);
88 full += pos; 90 full += pos;
89 91
@@ -132,43 +134,94 @@ private: @@ -132,43 +134,94 @@ private:
132 if (src.file.getBool("Train", false)) return; 134 if (src.file.getBool("Train", false)) return;
133 135
134 dst.file.clearRects(); 136 dst.file.clearRects();
  137 + int windowHeight = (int) qRound((float) windowWidth / aspectRatio);
  138 + int scale = src.file.get<float>("scale", 1);
  139 +
  140 + for (double y = 0; y + windowHeight < src.m().rows; y += stepSize) {
  141 + for (double x = 0; x + windowWidth < src.m().cols; x += stepSize) {
  142 + Rect window(x, y, windowWidth, windowHeight);
  143 + Template windowMat(src.file, Mat(src, window));
  144 + Template detect;
  145 + transform->project(windowMat, detect);
  146 + float conf = detect.file.get<float>("conf");
  147 +
  148 + // the result will be in the Label
  149 + if (conf > 0) {
  150 + dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale));
  151 + QList<float> confidences = dst.file.getList<float>("Confidences", QList<float>());
  152 + confidences.append(conf);
  153 + dst.file.setList<float>("Confidences", confidences);
  154 + if (takeFirst)
  155 + return;
  156 + }
  157 + }
  158 + }
  159 + }
  160 +
  161 + float aspectRatio;
  162 +};
  163 +
  164 +BR_REGISTER(Transform, SlidingWindowTransform)
  165 +
  166 +/*!
  167 + * \ingroup transforms
  168 + * \brief .
  169 + * \author Austin Blanton \cite imaus10
  170 + */
  171 +class BuildScalesTransform : public Transform
  172 +{
  173 + Q_OBJECT
  174 + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
  175 + Q_PROPERTY(double scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
  176 + Q_PROPERTY(bool takeLargestScale READ get_takeLargestScale WRITE set_takeLargestScale RESET reset_takeLargestScale STORED false)
  177 + Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
  178 + BR_PROPERTY(br::Transform *, transform, NULL)
  179 + BR_PROPERTY(double, scaleFactor, 0.75)
  180 + BR_PROPERTY(bool, takeLargestScale, true)
  181 + BR_PROPERTY(int, windowWidth, 24)
  182 +
  183 +public:
  184 + BuildScalesTransform() : Transform(false, true) {}
  185 +private:
  186 +
  187 + void train(const TemplateList &data)
  188 + {
  189 + aspectRatio = getAspectRatio(data);
  190 + // have to make a copy b/c data is const
  191 + TemplateList cp = data;
  192 + cp.first().file.set("aspectRatio", aspectRatio);
  193 + if (transform->trainable)
  194 + transform->train(cp);
  195 + }
  196 +
  197 + void project(const Template &src, Template &dst) const
  198 + {
  199 + dst = src;
  200 + // do not scale images during training
  201 + if (src.file.getBool("Train", false)) return;
  202 +
135 int rows = src.m().rows; 203 int rows = src.m().rows;
136 int cols = src.m().cols; 204 int cols = src.m().cols;
137 - int windowHeight = (int) round((float) windowWidth / aspectRatio); 205 + int windowHeight = (int) qRound((float) windowWidth / aspectRatio);
138 float startScale; 206 float startScale;
139 if ((cols / rows) > aspectRatio) 207 if ((cols / rows) > aspectRatio)
140 - startScale = round((float) rows / (float) windowHeight); 208 + startScale = qRound((float) rows / (float) windowHeight);
141 else 209 else
142 - startScale = round((float) cols / (float) windowWidth);  
143 - 210 + startScale = qRound((float) cols / (float) windowWidth);
144 for (float scale = startScale; scale >= 1.0; scale -= (1.0 - scaleFactor)) { 211 for (float scale = startScale; scale >= 1.0; scale -= (1.0 - scaleFactor)) {
145 - Mat scaleImg;  
146 - 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 - Rect window(x, y, windowWidth, windowHeight);  
151 - Template windowMat(src.file, Mat(scaleImg, window));  
152 - Template detect;  
153 - transform->project(windowMat, detect);  
154 - float conf = detect.file.get<float>("conf");  
155 -  
156 - // the result will be in the Label  
157 - if (conf > 0) {  
158 - dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale));  
159 - QList<float> confidences = dst.file.getList<float>("Confidences", QList<float>());  
160 - confidences.append(conf);  
161 - dst.file.setList<float>("Confidences", confidences);  
162 - if (takeLargestScale)  
163 - return;  
164 - }  
165 - }  
166 - } 212 + Template scaleImg(src.file, Mat());
  213 + scaleImg.file.set("scale", scale);
  214 + resize(src, scaleImg, Size(qRound(cols / scale), qRound(rows / scale)));
  215 + transform->project(scaleImg, dst);
  216 + if (takeLargestScale && !dst.file.rects().empty())
  217 + return;
167 } 218 }
168 } 219 }
  220 +
  221 + float aspectRatio;
169 }; 222 };
170 223
171 -BR_REGISTER(Transform, SlidingWindowTransform) 224 +BR_REGISTER(Transform, BuildScalesTransform)
172 225
173 /*! 226 /*!
174 * \ingroup transforms 227 * \ingroup transforms
openbr/plugins/stasm4.cpp
@@ -132,13 +132,16 @@ class StasmTransform : public UntrainableTransform @@ -132,13 +132,16 @@ class StasmTransform : public UntrainableTransform
132 132
133 if (!foundFace) { 133 if (!foundFace) {
134 qWarning("No face found in %s.", qPrintable(src.file.fileName())); 134 qWarning("No face found in %s.", qPrintable(src.file.fileName()));
  135 + dst.file.set("FTE",true);
135 } else { 136 } else {
  137 + QList<QPointF> points;
136 for (int i = 0; i < nLandmarks; i++) { 138 for (int i = 0; i < nLandmarks; i++) {
137 QPointF point(landmarks[2 * i], landmarks[2 * i + 1]); 139 QPointF point(landmarks[2 * i], landmarks[2 * i + 1]);
138 - dst.file.appendPoint(point);  
139 - if (i == 38) dst.file.set("StasmRightEye",point);  
140 - else if (i == 39) dst.file.set("StasmLeftEye", point); 140 + points.append(point);
141 } 141 }
  142 + dst.file.set("StasmRightEye", points[38]);
  143 + dst.file.set("StasmLeftEye", points[39]);
  144 + dst.file.appendPoints(points);
142 } 145 }
143 } 146 }
144 }; 147 };
openbr/plugins/template.cpp
@@ -9,7 +9,7 @@ namespace br @@ -9,7 +9,7 @@ namespace br
9 * \brief Retains only the values for the keys listed, to reduce template size 9 * \brief Retains only the values for the keys listed, to reduce template size
10 * \author Scott Klum \cite sklum 10 * \author Scott Klum \cite sklum
11 */ 11 */
12 -class RetainTransform : public UntrainableTransform 12 +class KeepMetadataTransform : public UntrainableTransform
13 { 13 {
14 Q_OBJECT 14 Q_OBJECT
15 Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) 15 Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
@@ -24,7 +24,7 @@ class RetainTransform : public UntrainableTransform @@ -24,7 +24,7 @@ class RetainTransform : public UntrainableTransform
24 } 24 }
25 }; 25 };
26 26
27 -BR_REGISTER(Transform, RetainTransform) 27 +BR_REGISTER(Transform, KeepMetadataTransform)
28 28
29 /*! 29 /*!
30 * \ingroup transforms 30 * \ingroup transforms
openbr/plugins/validate.cpp
@@ -255,7 +255,7 @@ class RejectDistance : public Distance @@ -255,7 +255,7 @@ class RejectDistance : public Distance
255 { 255 {
256 // We don't look at the query 256 // We don't look at the query
257 (void) b; 257 (void) b;
258 - 258 +
259 foreach (const QString &key, keys) 259 foreach (const QString &key, keys)
260 if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key))) 260 if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
261 return -std::numeric_limits<float>::max(); 261 return -std::numeric_limits<float>::max();