Commit 6fcc63c6bddf62527d2ae28660e97b7208343047

Authored by Jordan Cheney
1 parent dfea239c

Integrating OpenCV frontend

openbr/openbr_plugin.h
... ... @@ -1411,9 +1411,6 @@ public:
1411 1411 virtual cv::Size postWindowSize() const = 0; // window size after preprocessing
1412 1412 virtual int numFeatures() const = 0;
1413 1413 virtual int maxCatCount() const = 0;
1414   -
1415   - // Temporary for OpenCV compatibility
1416   - virtual void write( cv::FileStorage &fs, const cv::Mat &featureMap ) { (void)fs; (void)featureMap; }
1417 1414 };
1418 1415  
1419 1416 class BR_EXPORT Classifier : public Object
... ...
openbr/plugins/classification/boostedforest.cpp
... ... @@ -23,7 +23,6 @@ static void buildTreeRecursive(Node *node, const CvDTreeNode *cv_node, int maxCa
23 23 {
24 24 if (!cv_node->left) {
25 25 node->value = cv_node->value;
26   -
27 26 node->left = node->right = NULL;
28 27 } else {
29 28 if (maxCatCount > 0)
... ... @@ -40,6 +39,29 @@ static void buildTreeRecursive(Node *node, const CvDTreeNode *cv_node, int maxCa
40 39 }
41 40 }
42 41  
  42 +static void readRecursive(const FileNode &fn, Node *node, int maxCatCount)
  43 +{
  44 + bool hasChildren = (int)fn["hasChildren"];
  45 + if (!hasChildren) {
  46 + node->value = (float)fn["value"];
  47 + node->left = node->right = NULL;
  48 + } else {
  49 + if (maxCatCount > 0) {
  50 + FileNode subset_fn = fn["subset"];
  51 + for (FileNodeIterator subset_it = subset_fn.begin(); subset_it != subset_fn.end(); ++subset_it)
  52 + node->subset.append((int)*subset_it);
  53 + } else {
  54 + node->threshold = (float)fn["threshold"];
  55 + }
  56 +
  57 + node->featureIdx = (int)fn["featureIdx"];
  58 +
  59 + node->left = new Node; node->right = new Node;
  60 + readRecursive(fn["left"], node->left, maxCatCount);
  61 + readRecursive(fn["right"], node->right, maxCatCount);
  62 + }
  63 +}
  64 +
43 65 static void writeRecursive(FileStorage &fs, const Node *node, int maxCatCount)
44 66 {
45 67 bool hasChildren = node->left ? true : false;
... ... @@ -119,16 +141,17 @@ class BoostedForestClassifier : public Classifier
119 141 while (node->left) {
120 142 if (representation->maxCatCount() > 1) {
121 143 int c = (int)representation->evaluate(image, node->featureIdx);
122   - node = (2*((node->subset[c >> 5] & (1 << (c & 31))) == 0) - 1) < 0 ? node->left : node->right;
  144 + node = (node->subset[c >> 5] & (1 << (c & 31))) ? node->left : node->right;
123 145 } else {
124 146 double val = representation->evaluate(image, node->featureIdx);
125 147 node = val <= node->threshold ? node->left : node->right;
126 148 }
127 149 }
  150 + qDebug("value: %f", node->value);
128 151 sum += node->value;
129 152 }
130 153  
131   - return sum < threshold - THRESHOLD_EPS ? 0.0f : 1.0f;
  154 + return sum < threshold - THRESHOLD_EPS ? -std::abs(sum) : std::abs(sum);
132 155 }
133 156  
134 157 int numFeatures() const
... ... @@ -146,6 +169,17 @@ class BoostedForestClassifier : public Classifier
146 169 return representation->preWindowSize();
147 170 }
148 171  
  172 + void read(const FileNode &node)
  173 + {
  174 + threshold = (float)node["stageThreshold"];
  175 + FileNode weaks_fn = node["weakClassifiers"];
  176 + for (FileNodeIterator weaks_it = weaks_fn.begin(); weaks_it != weaks_fn.end(); ++weaks_it) {
  177 + Node *root = new Node;
  178 + readRecursive(*weaks_it, root, representation->maxCatCount());
  179 + classifiers.append(root);
  180 + }
  181 + }
  182 +
149 183 void write(FileStorage &fs) const
150 184 {
151 185 fs << "stageThreshold" << threshold;
... ...
openbr/plugins/classification/cascade.cpp
... ... @@ -154,10 +154,16 @@ class CascadeClassifier : public Classifier
154 154  
155 155 float classify(const Mat &image) const
156 156 {
157   - foreach (const Classifier *stage, stages)
158   - if (stage->classify(image) == 0.0f)
159   - return 0.0f;
160   - return 1.0f;
  157 + if (stages.empty())
  158 + return 1.0f;
  159 +
  160 + float val = 0.0f;
  161 + for (int i = 0; i < stages.size(); i++) {
  162 + val = stages[i]->classify(image);
  163 + if (val < 0.0f)
  164 + return stages.size() - i < 4 ? i * val : 0.0f;
  165 + }
  166 + return stages.size() * val;
161 167 }
162 168  
163 169 int numFeatures() const
... ... @@ -175,6 +181,16 @@ class CascadeClassifier : public Classifier
175 181 return stages.first()->windowSize();
176 182 }
177 183  
  184 + void read(const FileNode &node)
  185 + {
  186 + FileNode stages_fn = node["stages"];
  187 + for (FileNodeIterator stages_it = stages_fn.begin(); stages_it != stages_fn.end(); ++stages_it) {
  188 + Classifier *nextStage = Classifier::make(stageDescription, NULL);
  189 + nextStage->read(*stages_it);
  190 + stages.append(nextStage);
  191 + }
  192 + }
  193 +
178 194 void write(FileStorage &fs) const
179 195 {
180 196 fs << "stages" << "[";
... ... @@ -196,7 +212,7 @@ private:
196 212 if (!imgHandler.getPos(pos))
197 213 qFatal("Cannot get another positive sample!");
198 214  
199   - if (classify(pos) == 1.0f) {
  215 + if (classify(pos) > 0.0f) {
200 216 printf("POS current samples: %d\r", images.size());
201 217 images.append(pos);
202 218 labels.append(1.0f);
... ... @@ -212,7 +228,7 @@ private:
212 228 if (!imgHandler.getNeg(neg))
213 229 qFatal("Cannot get another negative sample!");
214 230  
215   - if (classify(neg) == 1.0f) {
  231 + if (classify(neg) > 0.0f) {
216 232 printf("NEG current samples: %d\r", images.size() - posCount);
217 233 images.append(neg);
218 234 labels.append(0.0f);
... ...
openbr/plugins/imgproc/slidingwindow.cpp
... ... @@ -19,8 +19,10 @@
19 19 #include <openbr/plugins/openbr_internal.h>
20 20 #include <openbr/core/opencvutils.h>
21 21 #include <openbr/core/qtutils.h>
  22 +#include <openbr/core/cascade.h>
22 23  
23 24 #include <opencv2/highgui/highgui.hpp>
  25 +#include <opencv2/imgproc/imgproc.hpp>
24 26  
25 27 using namespace cv;
26 28  
... ... @@ -38,8 +40,20 @@ class SlidingWindowTransform : public Transform
38 40 Q_OBJECT
39 41  
40 42 Q_PROPERTY(br::Classifier *classifier READ get_classifier WRITE set_classifier RESET reset_classifier STORED false)
  43 + Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false)
  44 + Q_PROPERTY(int maxSize READ get_maxSize WRITE set_maxSize RESET reset_maxSize STORED false)
  45 + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false)
  46 + Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false)
  47 + Q_PROPERTY(float eps READ get_eps WRITE set_eps RESET reset_eps STORED false)
  48 +
41 49 Q_PROPERTY(QString cascadeDir READ get_cascadeDir WRITE set_cascadeDir RESET reset_cascadeDir STORED false)
42 50 BR_PROPERTY(br::Classifier *, classifier, NULL)
  51 + BR_PROPERTY(int, minSize, 20)
  52 + BR_PROPERTY(int, maxSize, -1)
  53 + BR_PROPERTY(float, scaleFactor, 1.2)
  54 + BR_PROPERTY(int, minNeighbors, 5)
  55 + BR_PROPERTY(float, eps, 0.2)
  56 +
43 57 BR_PROPERTY(QString, cascadeDir, "")
44 58  
45 59 void train(const TemplateList &data)
... ... @@ -49,12 +63,104 @@ class SlidingWindowTransform : public Transform
49 63  
50 64 void project(const Template &src, Template &dst) const
51 65 {
52   - (void)src; (void)dst;
  66 + TemplateList temp;
  67 + project(TemplateList() << src, temp);
  68 + if (!temp.isEmpty()) dst = temp.first();
53 69 }
54 70  
  71 + void project(const TemplateList &src, TemplateList &dst) const
  72 + {
  73 + foreach (const Template &t, src) {
  74 + const bool enrollAll = t.file.getBool("enrollAll");
  75 +
  76 + // Mirror the behavior of ExpandTransform in the special case
  77 + // of an empty template.
  78 + if (t.empty() && !enrollAll) {
  79 + dst.append(t);
  80 + continue;
  81 + }
  82 +
  83 + for (int i = 0; i < t.size(); i++) {
  84 + Mat image;
  85 + OpenCVUtils::cvtUChar(t[i], image);
  86 +
  87 + std::vector<Rect> rects;
  88 + std::vector<int> rejectLevels;
  89 + std::vector<double> levelWeights;
  90 +
  91 + Size minObjectSize(minSize, minSize);
  92 + Size maxObjectSize(maxSize, maxSize);
  93 + if (maxObjectSize.height <= 0 || maxObjectSize.width <= 0)
  94 + maxObjectSize = image.size();
  95 +
  96 + Mat imageBuffer(image.rows + 1, image.cols + 1, CV_8U);
  97 +
  98 + for (double factor = 1; ; factor *= scaleFactor) {
  99 + Size originalWindowSize = classifier->windowSize();
  100 +
  101 + Size windowSize(cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
  102 + Size scaledImageSize(cvRound(image.cols/factor ), cvRound(image.rows/factor));
  103 + Size processingRectSize(scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height);
  104 +
  105 + if (processingRectSize.width <= 0 || processingRectSize.height <= 0)
  106 + break;
  107 + if (windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height)
  108 + break;
  109 + if (windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height)
  110 + continue;
  111 +
  112 + Mat scaledImage(scaledImageSize, CV_8U, imageBuffer.data);
  113 + resize(image, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR);
  114 +
  115 + int yStep = factor > 2. ? 1 : 2;
  116 + for (int y = 0; y < processingRectSize.height; y += yStep) {
  117 + for (int x = 0; x < processingRectSize.width; x += yStep) {
  118 + Mat window = scaledImage(Rect(Point(x, y), classifier->windowSize())).clone();
  119 +
  120 + float result = classifier->classify(window);
  121 + qDebug("result: %f", result);
  122 + if (result > 0) {
  123 + rects.push_back(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height));
  124 + rejectLevels.push_back(1);
  125 + levelWeights.push_back(result);
  126 + }
  127 + if (result == 0)
  128 + x = yStep;
  129 + }
  130 + }
  131 + }
  132 +
  133 + groupRectangles(rects, rejectLevels, levelWeights, minNeighbors, eps);
  134 +
  135 + if (!enrollAll && rects.empty())
  136 + rects.push_back(Rect(0, 0, image.cols, image.rows));
  137 +
  138 + for (size_t j = 0; j < rects.size(); j++) {
  139 + Template u(t.file, image);
  140 + if (rejectLevels.size() > j)
  141 + u.file.set("Confidence", rejectLevels[j]*levelWeights[j]);
  142 + else
  143 + u.file.set("Confidence", 1);
  144 + const QRectF rect = OpenCVUtils::fromRect(rects[j]);
  145 + u.file.appendRect(rect);
  146 + u.file.set("Face", rect);
  147 + dst.append(u);
  148 + }
  149 + }
  150 + }
  151 + }
  152 +
55 153 void load(QDataStream &stream)
56 154 {
57 155 (void) stream;
  156 +
  157 + QString filename = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + cascadeDir + "/cascade.xml";
  158 + FileStorage fs(filename.toStdString(), FileStorage::READ);
  159 + if (!fs.isOpened())
  160 + return;
  161 +
  162 + classifier->read(fs.getFirstTopLevelNode());
  163 +
58 164 return;
59 165 }
60 166  
... ... @@ -62,17 +168,17 @@ class SlidingWindowTransform : public Transform
62 168 {
63 169 (void) stream;
64 170  
65   - QString path = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + cascadeDir;
66   - QtUtils::touchDir(QDir(path));
  171 + QString path = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + cascadeDir;
  172 + QtUtils::touchDir(QDir(path));
67 173  
68   - QString filename = path + "/cascade.xml";
  174 + QString filename = path + "/cascade.xml";
69 175 FileStorage fs(filename.toStdString(), FileStorage::WRITE);
70 176  
71 177 if (!fs.isOpened()) {
72   - qWarning("Unable to open file: %s", qPrintable(filename));
  178 + qWarning("Unable to open file: %s", qPrintable(filename));
73 179 return;
74   - }
75   -
  180 + }
  181 +
76 182 fs << FileStorage::getDefaultObjectName(filename.toStdString()) << "{";
77 183  
78 184 classifier->write(fs);
... ...
openbr/plugins/representation/mblbp.cpp
... ... @@ -58,7 +58,6 @@ class MBLBPRepresentation : public Representation
58 58 return result;
59 59 }
60 60  
61   - void write(FileStorage &fs, const Mat &featureMap);
62 61 int numFeatures() const { return features.size(); }
63 62 Size preWindowSize() const { return Size(winWidth, winHeight); }
64 63 Size postWindowSize() const { return Size(winWidth + 1, winHeight + 1); }
... ... @@ -69,7 +68,6 @@ class MBLBPRepresentation : public Representation
69 68 Feature() { rect = Rect(0, 0, 0, 0); }
70 69 Feature( int offset, int x, int y, int _block_w, int _block_h );
71 70 uchar calc(const Mat &img) const;
72   - void write( FileStorage &fs ) const { fs << "rect" << "[:" << rect.x << rect.y << rect.width << rect.height << "]"; }
73 71  
74 72 Rect rect;
75 73 int p[16];
... ... @@ -79,20 +77,6 @@ class MBLBPRepresentation : public Representation
79 77  
80 78 BR_REGISTER(Representation, MBLBPRepresentation)
81 79  
82   -void MBLBPRepresentation::write(FileStorage &fs, const Mat &featureMap)
83   -{
84   - fs << "features" << "[";
85   - const Mat_<int>& featureMap_ = (const Mat_<int>&)featureMap;
86   - for ( int fi = 0; fi < featureMap.cols; fi++ )
87   - if ( featureMap_(0, fi) >= 0 )
88   - {
89   - fs << "{";
90   - features[fi].write( fs );
91   - fs << "}";
92   - }
93   - fs << "]";
94   -}
95   -
96 80 MBLBPRepresentation::Feature::Feature( int offset, int x, int y, int _blockWidth, int _blockHeight )
97 81 {
98 82 Rect tr = rect = cvRect(x, y, _blockWidth, _blockHeight);
... ...