Commit 9f89a05f088e6a5ff509b53929e081580b34d88e

Authored by Josh Klontz
1 parent bb446dfb

proposed implementation of #123

openbr/core/opencvutils.cpp
@@ -300,6 +300,16 @@ QList<QRectF> OpenCVUtils::fromRects(const QList<Rect> &cvRects) @@ -300,6 +300,16 @@ QList<QRectF> OpenCVUtils::fromRects(const QList<Rect> &cvRects)
300 return qRects; 300 return qRects;
301 } 301 }
302 302
  303 +bool OpenCVUtils::overlaps(const QList<Rect> &posRects, const Rect &negRect, double overlap)
  304 +{
  305 + foreach (const Rect &posRect, posRects) {
  306 + Rect intersect = negRect & posRect;
  307 + if (intersect.area() > overlap*posRect.area())
  308 + return true;
  309 + }
  310 + return false;
  311 +}
  312 +
303 QDataStream &operator<<(QDataStream &stream, const Mat &m) 313 QDataStream &operator<<(QDataStream &stream, const Mat &m)
304 { 314 {
305 // Write header 315 // Write header
openbr/core/opencvutils.h
@@ -87,6 +87,7 @@ namespace OpenCVUtils @@ -87,6 +87,7 @@ namespace OpenCVUtils
87 QRectF fromRect(const cv::Rect &cvRect); 87 QRectF fromRect(const cv::Rect &cvRect);
88 QList<cv::Rect> toRects(const QList<QRectF> &qRects); 88 QList<cv::Rect> toRects(const QList<QRectF> &qRects);
89 QList<QRectF> fromRects(const QList<cv::Rect> &cvRects); 89 QList<QRectF> fromRects(const QList<cv::Rect> &cvRects);
  90 + bool overlaps(const QList<cv::Rect> &posRects, const cv::Rect &negRect, double overlap);
90 91
91 int getFourcc(); 92 int getFourcc();
92 } 93 }
openbr/plugins/slidingwindow.cpp
@@ -101,12 +101,73 @@ private: @@ -101,12 +101,73 @@ private:
101 101
102 BR_REGISTER(Transform, SlidingWindowTransform) 102 BR_REGISTER(Transform, SlidingWindowTransform)
103 103
  104 +static TemplateList cropTrainingSamples(const TemplateList &data, const float aspectRatio, const int minSize, const float maxOverlap, const int negToPosRatio)
  105 +{
  106 + TemplateList result;
  107 + foreach (const Template &tmpl, data) {
  108 + QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());
  109 + QList<Rect> negRects;
  110 + for (int i=0; i<posRects.size(); i++) {
  111 + Rect &posRect = posRects[i];
  112 +
  113 + // Adjust for training samples that have different aspect ratios
  114 + const int diff = posRect.width - int(posRect.height * aspectRatio);
  115 + posRect.x += diff / 2;
  116 + posRect.width += diff;
  117 +
  118 + // Ignore samples larger than the image
  119 + if ((posRect.x + posRect.width >= tmpl.m().cols) ||
  120 + (posRect.y + posRect.height >= tmpl.m().rows) ||
  121 + (posRect.x < 0) ||
  122 + (posRect.y < 0))
  123 + continue;
  124 +
  125 + result += Template(tmpl.file, Mat(tmpl, posRect));
  126 +
  127 + // Add random negative samples
  128 + Mat m = tmpl.m();
  129 + int sample = 0;
  130 + while (sample < negToPosRatio) {
  131 + const int x = rand() % m.cols;
  132 + const int y = rand() % m.rows;
  133 + const int maxWidth = m.cols - x;
  134 + const int maxHeight = m.rows - y;
  135 + if (maxWidth <= minSize || maxHeight <= minSize)
  136 + continue;
  137 +
  138 + int height;
  139 + int width;
  140 + if (aspectRatio > (float) maxWidth / (float) maxHeight) {
  141 + width = rand() % (maxWidth - minSize) + minSize;
  142 + height = qRound(width / aspectRatio);
  143 + } else {
  144 + height = rand() % (maxHeight - minSize) + minSize;
  145 + width = qRound(height * aspectRatio);
  146 + }
  147 + Rect negRect(x, y, width, height);
  148 +
  149 + // The negative samples cannot overlap the positive samples at
  150 + // all, but they may partially overlap with other negatives.
  151 + if (OpenCVUtils::overlaps(posRects, negRect, 0) ||
  152 + OpenCVUtils::overlaps(negRects, negRect, maxOverlap))
  153 + continue;
  154 +
  155 + result += Template(tmpl.file, Mat(tmpl, negRect));
  156 + result.last().file.set("Label", QString("neg"));
  157 + sample++;
  158 + }
  159 + }
  160 + }
  161 +
  162 + return result;
  163 +}
  164 +
104 /*! 165 /*!
105 * \ingroup transforms 166 * \ingroup transforms
106 * \brief . 167 * \brief .
107 * \author Austin Blanton \cite imaus10 168 * \author Austin Blanton \cite imaus10
108 */ 169 */
109 -class BuildScalesTransform : public Transform 170 +class BuildScalesTransform : public MetaTransform
110 { 171 {
111 Q_OBJECT 172 Q_OBJECT
112 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) 173 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
@@ -117,7 +178,6 @@ class BuildScalesTransform : public Transform @@ -117,7 +178,6 @@ class BuildScalesTransform : public Transform
117 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) 178 Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false)
118 Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false) 179 Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false)
119 Q_PROPERTY(float minScale READ get_minScale WRITE set_minScale RESET reset_minScale STORED false) 180 Q_PROPERTY(float minScale READ get_minScale WRITE set_minScale RESET reset_minScale STORED false)
120 - Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false)  
121 BR_PROPERTY(br::Transform *, transform, NULL) 181 BR_PROPERTY(br::Transform *, transform, NULL)
122 BR_PROPERTY(double, scaleFactor, 0.75) 182 BR_PROPERTY(double, scaleFactor, 0.75)
123 BR_PROPERTY(bool, takeLargestScale, false) 183 BR_PROPERTY(bool, takeLargestScale, false)
@@ -126,92 +186,27 @@ class BuildScalesTransform : public Transform @@ -126,92 +186,27 @@ class BuildScalesTransform : public Transform
126 BR_PROPERTY(int, minSize, 8) 186 BR_PROPERTY(int, minSize, 8)
127 BR_PROPERTY(double, maxOverlap, 0) 187 BR_PROPERTY(double, maxOverlap, 0)
128 BR_PROPERTY(float, minScale, 1.0) 188 BR_PROPERTY(float, minScale, 1.0)
129 - BR_PROPERTY(bool, negSamples, true)  
130 189
131 -public:  
132 - BuildScalesTransform() : Transform(false, true) {}  
133 private: 190 private:
134 - int windowHeight;  
135 float aspectRatio; 191 float aspectRatio;
  192 + int windowHeight;
136 193
137 - void train(const TemplateList &_data) 194 + void train(const TemplateList &data)
138 { 195 {
139 - TemplateList data(_data); // have to make a copy b/c data is const  
140 aspectRatio = getAspectRatio(data); 196 aspectRatio = getAspectRatio(data);
141 - data.first().file.set("aspectRatio", aspectRatio);  
142 - windowHeight = (int) qRound((float) windowWidth / aspectRatio);  
143 - 197 + windowHeight = qRound(windowWidth / aspectRatio);
144 if (transform->trainable) { 198 if (transform->trainable) {
145 TemplateList full; 199 TemplateList full;
146 - foreach (const Template &tmpl, data) {  
147 - QList<Rect> posRects = OpenCVUtils::toRects(tmpl.file.rects());  
148 - QList<Rect> negRects;  
149 - foreach (Rect posRect, posRects) {  
150 -  
151 - //Adjust for training samples that have different aspect ratios  
152 - int diff = posRect.width - (int)((float) posRect.height * aspectRatio);  
153 - posRect.x += diff / 2;  
154 - posRect.width += diff;  
155 -  
156 - if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) {  
157 - continue;  
158 - }  
159 -  
160 - Mat scaledImg;  
161 - resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,qRound(windowWidth / aspectRatio)));  
162 - Template pos(tmpl.file, scaledImg);  
163 - full += pos;  
164 -  
165 - // add random negative samples  
166 - if (negSamples) {  
167 - Mat m = tmpl.m();  
168 - int sample = 0;  
169 - while (sample < negToPosRatio) {  
170 - int x = Common::RandSample(1, m.cols)[0];  
171 - int y = Common::RandSample(1, m.rows)[0];  
172 - int maxWidth = m.cols - x;  
173 - int maxHeight = m.rows - y;  
174 - if (maxWidth <= minSize || maxHeight <= minSize)  
175 - continue;  
176 - int height;  
177 - int width;  
178 - if (aspectRatio > (float) maxWidth / (float) maxHeight) {  
179 - width = Common::RandSample(1,maxWidth,minSize)[0];  
180 - height = (int) qRound(width / aspectRatio);  
181 - } else {  
182 - height = Common::RandSample(1,maxHeight,minSize)[0];  
183 - width = (int) qRound(height * aspectRatio);  
184 - }  
185 - Rect negRect(x, y, width, height);  
186 - // the negative samples cannot overlap the positive at all  
187 - // but they may overlap with other negatives  
188 - if (overlaps(posRects, negRect, 0) || overlaps(negRects, negRect, maxOverlap))  
189 - continue;  
190 - negRects.append(negRect);  
191 - Template neg(tmpl.file, Mat());  
192 - resize(Mat(tmpl, negRect), neg, Size(windowWidth, windowHeight));  
193 - neg.file.set("Label", QString("neg"));  
194 - full += neg;  
195 - sample++;  
196 - }  
197 - }  
198 - } 200 + foreach (const Template &roi, cropTrainingSamples(data, aspectRatio, minSize, maxOverlap, negToPosRatio)) {
  201 + Mat resized;
  202 + resize(roi, resized, Size(windowWidth, windowHeight));
  203 + full += Template(roi.file, resized);
199 } 204 }
  205 + full.first().file.set("aspectRatio", aspectRatio);
200 transform->train(full); 206 transform->train(full);
201 } 207 }
202 } 208 }
203 209
204 - bool overlaps(QList<Rect> posRects, Rect negRect, double overlap)  
205 - {  
206 - foreach (const Rect posRect, posRects) {  
207 - Rect intersect = negRect & posRect;  
208 - if (intersect.area() > overlap*posRect.area())  
209 - return true;  
210 - }  
211 - return false;  
212 - }  
213 -  
214 -  
215 void project(const Template &src, Template &dst) const 210 void project(const Template &src, Template &dst) const
216 { 211 {
217 dst = src; 212 dst = src;
scripts/pedestrianBaselineLBP.sh
1 #!/bin/bash 1 #!/bin/bash
2 2
3 -#Right now this is just a simple proof of concept. No quanititative eval is performed 3 +# Right now this is just a simple proof of concept. No quantitative eval is performed
4 # but instead the qualitative results are displayed. 4 # but instead the qualitative results are displayed.
5 5
6 -#Make sure you set your data path. This will likely by your openbr/data directory.  
7 -INRIA_PATH=$DATA/INRIAPerson 6 +# Make sure you set your data path. This will likely by your openbr/data directory.
  7 +if [ -z "$DATA" ]; then
  8 + INRIA_PATH=../data/INRIAPerson
  9 +else
  10 + INRIA_PATH=$DATA/INRIAPerson
  11 +fi
8 12
9 ALG="Open+Cvt(Gray)+Rename(neg,0)+BuildScales(Blur(2)+LBP(1,2)+SlidingWindow(Hist(59)+Cat+LDA(isBinary=true),windowWidth=10,takeLargestScale=false,threshold=2),windowWidth=10,takeLargestScale=false,minScale=4)+ConsolidateDetections+Discard" 13 ALG="Open+Cvt(Gray)+Rename(neg,0)+BuildScales(Blur(2)+LBP(1,2)+SlidingWindow(Hist(59)+Cat+LDA(isBinary=true),windowWidth=10,takeLargestScale=false,threshold=2),windowWidth=10,takeLargestScale=false,minScale=4)+ConsolidateDetections+Discard"
10 14