Commit 27a5fc9bd8a19f313d9eaca35c1fdefa0ee6117e

Authored by Charles Otto
2 parents 9cf029b5 885c3ec1

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

Conflicts:
	openbr/core/core.cpp
app/br/br.cpp
... ... @@ -171,7 +171,11 @@ public:
171 171 check(parc == 1, "Incorrect parameter count for 'daemon'.");
172 172 daemon = true;
173 173 daemon_pipe = parv[0];
174   - } else if (!strcmp(fun, "exit")) {
  174 + } else if (!strcmp(fun,"slave")) {
  175 + check(parc == 1, "Incorrect parameter count for 'slave'");
  176 + br_slave_process(parv[0]);
  177 + }
  178 + else if (!strcmp(fun, "exit")) {
175 179 check(parc == 0, "No parameters expected for 'exit'.");
176 180 daemon = false;
177 181 } else if (!strcmp(fun, "getHeader")) {
... ...
openbr/core/core.cpp
... ... @@ -138,8 +138,6 @@ struct AlgorithmCore
138 138  
139 139 downcast->transforms[0] = this->transform.data();
140 140 downcast->init();
141   -
142   -
143 141 downcast->projectUpdate(i,i);
144 142  
145 143 return i.files();
... ...
openbr/core/qtutils.cpp
... ... @@ -399,33 +399,31 @@ void showFile(const QString &file)
399 399  
400 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 408 QRectF rect = qvariant_cast<QRectF>(variant);
411 409 return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()),
412 410 QString::number(rect.y()),
413 411 QString::number(rect.width()),
414 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 427 return QString();
430 428 }
431 429  
... ...
openbr/core/qtutils.h
... ... @@ -74,6 +74,7 @@ namespace QtUtils
74 74  
75 75 /**** Variant Utilities ****/
76 76 QString toString(const QVariant &variant);
  77 + QString toString(const QVariantList &variantList);
77 78  
78 79 template <typename T>
79 80 QVariantList toVariantList(const QList<T> &list)
... ...
openbr/openbr.cpp
... ... @@ -22,6 +22,7 @@
22 22 #include "core/fuse.h"
23 23 #include "core/plot.h"
24 24 #include "core/qtutils.h"
  25 +#include "plugins/openbr_internal.h"
25 26  
26 27 using namespace br;
27 28  
... ... @@ -279,3 +280,11 @@ const char *br_version()
279 280 static QByteArray version = Context::version().toLocal8Bit();
280 281 return version.data();
281 282 }
  283 +
  284 +void br_slave_process(const char * baseName)
  285 +{
  286 + WorkerProcess worker;
  287 + worker.transform = Globals->algorithm;
  288 + worker.baseName = baseName;
  289 + worker.mainLoop();
  290 +}
... ...
openbr/openbr.h
... ... @@ -408,6 +408,12 @@ BR_EXPORT void br_train_n(int num_inputs, const char *inputs[], const char *mode
408 408 */
409 409 BR_EXPORT const char *br_version();
410 410  
  411 +
  412 +/*!
  413 + * \brief For internal use via ProcessWrapperTransform
  414 + */
  415 +BR_EXPORT void br_slave_process(const char * baseKey);
  416 +
411 417 /*! @}*/
412 418  
413 419 #ifdef __cplusplus
... ...
openbr/openbr_plugin.cpp
... ... @@ -17,6 +17,7 @@
17 17 #include <QCoreApplication>
18 18 #include <QCryptographicHash>
19 19 #include <QFutureSynchronizer>
  20 +#include <QLocalSocket>
20 21 #include <QMetaProperty>
21 22 #include <QPointF>
22 23 #include <QProcess>
... ... @@ -58,16 +59,7 @@ QString File::flat() const
58 59 foreach (const QString &key, keys) {
59 60 const QVariant value = this->value(key);
60 61 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   - }
  62 + else values.append(key + "=" + QtUtils::toString(value));
71 63 }
72 64  
73 65 QString flat = name;
... ... @@ -942,6 +934,8 @@ void br::Context::initialize(int &amp;argc, char *argv[], QString sdkPath, bool use_
942 934 qRegisterMetaType< QList<float> >();
943 935 qRegisterMetaType< QList<br::Transform*> >();
944 936 qRegisterMetaType< QList<br::Distance*> >();
  937 + qRegisterMetaType< QAbstractSocket::SocketState> ();
  938 +
945 939  
946 940 Globals = new Context();
947 941 Globals->init(File());
... ...
openbr/plugins/eigen3.cpp
... ... @@ -493,7 +493,7 @@ class LDATransform : public Transform
493 493 outMap = projection.transpose() * (inMap - mean);
494 494  
495 495 if (isBinary) {
496   - dst.file.set("conf",dst.m().at<float>(0,0));
  496 + dst.file.set("Confidence",dst.m().at<float>(0,0));
497 497 }
498 498 }
499 499  
... ...
openbr/plugins/openbr_internal.h
... ... @@ -240,6 +240,18 @@ protected:
240 240 CompositeTransform() : TimeVaryingTransform(false) {}
241 241 };
242 242  
  243 +class EnrollmentWorker;
  244 +
  245 +// Implemented in plugins/process.cpp
  246 +struct WorkerProcess
  247 +{
  248 + QString transform;
  249 + QString baseName;
  250 + EnrollmentWorker * processInterface;
  251 +
  252 + void mainLoop();
  253 +};
  254 +
243 255 }
244 256  
245 257 #endif // OPENBR_INTERNAL_H
... ...
openbr/plugins/process.cpp 0 โ†’ 100644
  1 +
  2 +#include <QBuffer>
  3 +#include <QLocalServer>
  4 +#include <QLocalSocket>
  5 +#include <QProcess>
  6 +#include <QUuid>
  7 +
  8 +#include <iostream>
  9 +#include <fstream>
  10 +
  11 +#include "openbr_internal.h"
  12 +#include "openbr/core/opencvutils.h"
  13 +
  14 +using namespace cv;
  15 +
  16 +namespace br
  17 +{
  18 +
  19 +enum SignalType
  20 +{
  21 + INPUT_AVAILABLE,
  22 + OUTPUT_AVAILABLE,
  23 + SHOULD_END
  24 +};
  25 +
  26 +class EnrollmentWorker
  27 +{
  28 +public:
  29 + QLocalServer inbound;
  30 + QLocalSocket outbound;
  31 + QLocalSocket * receiver;
  32 +
  33 + ~EnrollmentWorker()
  34 + {
  35 + delete transform;
  36 + }
  37 +
  38 + br::Transform * transform;
  39 +
  40 + void connections(const QString & baseName)
  41 + {
  42 + inbound.listen(baseName+"_worker");
  43 + outbound.connectToServer(baseName+"_master");
  44 + inbound.waitForNewConnection(-1);
  45 + receiver = inbound.nextPendingConnection();
  46 + outbound.waitForConnected(-1);
  47 + }
  48 +
  49 + void workerLoop()
  50 + {
  51 + SignalType signal;
  52 +
  53 + forever
  54 + {
  55 + while (receiver->bytesAvailable() < qint64(sizeof(signal))) {
  56 + receiver->waitForReadyRead(-1);
  57 + }
  58 + receiver->read((char *) &signal, sizeof(signal));
  59 +
  60 + if (signal == SHOULD_END) {
  61 + outbound.close();
  62 + inbound.close();
  63 + break;
  64 + }
  65 +
  66 + qint64 inBufferSize;
  67 + while (receiver->bytesAvailable() < qint64(sizeof(inBufferSize))) {
  68 + receiver->waitForReadyRead(-1);
  69 + }
  70 + receiver->read((char *) &inBufferSize, sizeof(inBufferSize));
  71 +
  72 + QByteArray inArray(inBufferSize,'0');
  73 +
  74 + qint64 arrayPosition = 0;
  75 + while (arrayPosition < inBufferSize) {
  76 + if (!receiver->bytesAvailable())
  77 + receiver->waitForReadyRead(-1);
  78 + arrayPosition += receiver->read(inArray.data()+arrayPosition, receiver->bytesAvailable());
  79 + }
  80 +
  81 + TemplateList inList;
  82 + TemplateList outList;
  83 + // deserialize the template list
  84 + QDataStream deserializer(inArray);
  85 + deserializer >> inList;
  86 +
  87 + // and project it
  88 + transform->projectUpdate(inList,outList);
  89 +
  90 + // serialize the output list
  91 + QBuffer outBuff;
  92 + outBuff.open(QBuffer::ReadWrite);
  93 + QDataStream serializer(&outBuff);
  94 + serializer << outList;
  95 +
  96 + // send the size of the buffer
  97 + //qint64 bufferSize = outBuff.size();
  98 + qint64 bufferSize = outBuff.data().size();
  99 + outbound.write((char *) &bufferSize, sizeof(bufferSize));
  100 +
  101 + outbound.write(outBuff.data().data(), bufferSize);
  102 + while (outbound.bytesToWrite() > 0) {
  103 + outbound.waitForBytesWritten(-1);
  104 + }
  105 + }
  106 + }
  107 +};
  108 +
  109 +void WorkerProcess::mainLoop()
  110 +{
  111 + processInterface = new EnrollmentWorker();
  112 + processInterface->transform = Transform::make(this->transform,NULL);
  113 + processInterface->connections(baseName);
  114 + processInterface->workerLoop();
  115 + delete processInterface;
  116 +}
  117 +
  118 +/*!
  119 + * \ingroup transforms
  120 + * \brief Interface to a separate process
  121 + * \author Charles Otto \cite caotto
  122 + */
  123 +class ProcessWrapperTransform : public TimeVaryingTransform
  124 +{
  125 + Q_OBJECT
  126 +
  127 + Q_PROPERTY(QString transform READ get_transform WRITE set_transform RESET reset_transform)
  128 + BR_PROPERTY(QString, transform, "")
  129 +
  130 + QString baseKey;
  131 + QProcess workerProcess;
  132 +
  133 + QLocalServer inbound;
  134 + QLocalSocket outbound;
  135 + QLocalSocket * receiver;
  136 +
  137 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  138 + {
  139 + if (!processActive)
  140 + {
  141 + activateProcess();
  142 + }
  143 +
  144 + SignalType signal = INPUT_AVAILABLE;
  145 + outbound.write((char *) &signal, sizeof(SignalType));
  146 +
  147 + QBuffer inBuffer;
  148 + inBuffer.open(QBuffer::ReadWrite);
  149 + QDataStream serializer(&inBuffer);
  150 + serializer << src;
  151 +
  152 + qint64 in_size = inBuffer.size();
  153 + outbound.write((char *) &in_size, sizeof(in_size));
  154 +
  155 + outbound.write(inBuffer.data(), in_size);
  156 +
  157 + while (outbound.bytesToWrite() > 0) {
  158 + outbound.waitForBytesWritten(-1);
  159 + }
  160 +
  161 + qint64 out_size;
  162 +
  163 + // read the size
  164 + receiver->waitForReadyRead(-1);
  165 + receiver->read((char *) &out_size, sizeof(out_size));
  166 + QByteArray outBuffer(out_size,'0');
  167 +
  168 + // read the (serialized) output templatelist
  169 + qint64 arrayPosition = 0;
  170 + while (arrayPosition < out_size) {
  171 + if (!receiver->bytesAvailable())
  172 + receiver->waitForReadyRead(-1);
  173 + arrayPosition += receiver->read(outBuffer.data()+arrayPosition, receiver->bytesAvailable());
  174 + }
  175 + // and deserialize it.
  176 + QDataStream deserialize(outBuffer);
  177 + deserialize >> dst;
  178 + }
  179 +
  180 +
  181 + void train(const TemplateList& data)
  182 + {
  183 + (void) data;
  184 + }
  185 +
  186 + // create the process
  187 + void init()
  188 + {
  189 + processActive = false;
  190 + }
  191 +
  192 + void activateProcess()
  193 + {
  194 + processActive = true;
  195 +
  196 + // generate a uuid for our local servers
  197 + QUuid id = QUuid::createUuid();
  198 + baseKey = id.toString();
  199 +
  200 + QStringList argumentList;
  201 + argumentList.append("-useGui");
  202 + argumentList.append("0");
  203 + argumentList.append("-algorithm");
  204 + argumentList.append(transform);
  205 + argumentList.append("-path");
  206 + argumentList.append(Globals->path);
  207 + argumentList.append("-parallelism");
  208 + argumentList.append(QString::number(0));
  209 + argumentList.append("-slave");
  210 + argumentList.append(baseKey);
  211 +
  212 + // start listening
  213 + inbound.listen(baseKey+"_master");
  214 +
  215 + workerProcess.setProcessChannelMode(QProcess::ForwardedChannels);
  216 + workerProcess.start("br", argumentList);
  217 + workerProcess.waitForStarted(-1);
  218 +
  219 + // blocking wait for the connection from the worker process
  220 + inbound.waitForNewConnection(-1);
  221 + receiver = inbound.nextPendingConnection();
  222 +
  223 + // Now, create our connection to the worker process.
  224 + outbound.connectToServer(baseKey+"_worker");
  225 + outbound.waitForConnected(-1);
  226 + }
  227 +
  228 + bool timeVarying() const {
  229 + return false;
  230 + }
  231 +
  232 + ~ProcessWrapperTransform()
  233 + {
  234 + // end the process
  235 + if (this->processActive) {
  236 +
  237 + SignalType signal = SHOULD_END;
  238 + outbound.write((char *) &signal, sizeof(SignalType));
  239 + outbound.waitForBytesWritten(-1);
  240 + outbound.close();
  241 +
  242 + workerProcess.waitForFinished(-1);
  243 + inbound.close();
  244 + processActive = false;
  245 + }
  246 + }
  247 +
  248 +public:
  249 + bool processActive;
  250 + ProcessWrapperTransform() : TimeVaryingTransform(false,false) { processActive = false; }
  251 +};
  252 +
  253 +BR_REGISTER(Transform, ProcessWrapperTransform)
  254 +
  255 +}
  256 +
  257 +#include "process.moc"
... ...
openbr/plugins/regions.cpp
... ... @@ -345,9 +345,12 @@ class RectFromPointsTransform : public UntrainableTransform
345 345  
346 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 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 354 dst.m() = src.m();
352 355 }
353 356 }
... ...
openbr/plugins/slidingwindow.cpp
... ... @@ -8,12 +8,28 @@
8 8  
9 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 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 34 * \ingroup transforms
19 35 * \brief Applies a transform to a sliding window.
... ... @@ -25,23 +41,19 @@ class SlidingWindowTransform : public Transform
25 41 Q_OBJECT
26 42 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
27 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 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 46 Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false)
32 47 Q_PROPERTY(int negToPosRatio READ get_negToPosRatio WRITE set_negToPosRatio RESET reset_negToPosRatio STORED false)
33 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 49 Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
36 50 BR_PROPERTY(br::Transform *, transform, NULL)
37 51 BR_PROPERTY(int, minSize, 8)
38   - BR_PROPERTY(double, scaleFactor, 0.75)
39 52 BR_PROPERTY(int, stepSize, 1)
40   - BR_PROPERTY(bool, takeLargestScale, true)
  53 + BR_PROPERTY(bool, takeFirst, false)
41 54 BR_PROPERTY(bool, negSamples, true)
42 55 BR_PROPERTY(int, negToPosRatio, 1)
43 56 BR_PROPERTY(double, maxOverlap, 0)
44   - BR_PROPERTY(float, aspectRatio, 1)
45 57 BR_PROPERTY(int, windowWidth, 24)
46 58  
47 59 public:
... ... @@ -50,24 +62,14 @@ private:
50 62  
51 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 70 if (transform->trainable) {
54   - double tempRatio = 0;
55   - int ratioCnt = 0;
56 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 73 foreach (const Template &tmpl, data) {
72 74 QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
73 75 QList<Rect> negRects;
... ... @@ -83,7 +85,7 @@ private:
83 85 }
84 86  
85 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 89 Template pos(tmpl.file, scaledImg);
88 90 full += pos;
89 91  
... ... @@ -132,43 +134,94 @@ private:
132 134 if (src.file.getBool("Train", false)) return;
133 135  
134 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>("Confidence");
  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, false)
  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 203 int rows = src.m().rows;
136 204 int cols = src.m().cols;
137   - int windowHeight = (int) round((float) windowWidth / aspectRatio);
  205 + int windowHeight = (int) qRound((float) windowWidth / aspectRatio);
138 206 float startScale;
139 207 if ((cols / rows) > aspectRatio)
140   - startScale = round((float) rows / (float) windowHeight);
  208 + startScale = qRound((float) rows / (float) windowHeight);
141 209 else
142   - startScale = round((float) cols / (float) windowWidth);
143   -
  210 + startScale = qRound((float) cols / (float) windowWidth);
144 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 227 * \ingroup transforms
... ...
openbr/plugins/stasm4.cpp
... ... @@ -132,13 +132,16 @@ class StasmTransform : public UntrainableTransform
132 132  
133 133 if (!foundFace) {
134 134 qWarning("No face found in %s.", qPrintable(src.file.fileName()));
  135 + dst.file.set("FTE",true);
135 136 } else {
  137 + QList<QPointF> points;
136 138 for (int i = 0; i < nLandmarks; i++) {
137 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/svm.cpp
... ... @@ -157,7 +157,7 @@ private:
157 157 dst = src;
158 158 float prediction = svm.predict(src.m().reshape(1, 1), returnDFVal);
159 159 if (returnDFVal) {
160   - dst.file.set("conf", prediction);
  160 + dst.file.set("Confidence", prediction);
161 161 // positive values ==> first class
162 162 // negative values ==> second class
163 163 prediction = prediction > 0 ? 0 : 1;
... ...
openbr/plugins/template.cpp
... ... @@ -9,7 +9,7 @@ namespace br
9 9 * \brief Retains only the values for the keys listed, to reduce template size
10 10 * \author Scott Klum \cite sklum
11 11 */
12   -class RetainTransform : public UntrainableTransform
  12 +class KeepMetadataTransform : public UntrainableTransform
13 13 {
14 14 Q_OBJECT
15 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 24 }
25 25 };
26 26  
27   -BR_REGISTER(Transform, RetainTransform)
  27 +BR_REGISTER(Transform, KeepMetadataTransform)
28 28  
29 29 /*!
30 30 * \ingroup transforms
... ...
openbr/plugins/validate.cpp
... ... @@ -255,7 +255,7 @@ class RejectDistance : public Distance
255 255 {
256 256 // We don't look at the query
257 257 (void) b;
258   -
  258 +
259 259 foreach (const QString &key, keys)
260 260 if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
261 261 return -std::numeric_limits<float>::max();
... ...