Commit 37f46fbf401996f9bc827878786cccbf292bf807

Authored by Scott Klum
2 parents 7c7a4a39 5020073a

Looks like caotto beat me to it

openbr/openbr_plugin.cpp
... ... @@ -476,13 +476,18 @@ TemplateList TemplateList::fromGallery(const br::File &gallery)
476 476  
477 477 // indexes some property, assigns an integer id to each unique value of propName
478 478 // stores the index values in "Label" of the output template list
479   -TemplateList TemplateList::relabel(const TemplateList &tl, const QString & propName)
  479 +TemplateList TemplateList::relabel(const TemplateList &tl, const QString &propName, bool preserveIntegers)
480 480 {
481 481 const QList<QString> originalLabels = File::get<QString>(tl, propName);
482 482 QHash<QString,int> labelTable;
483   - foreach (const QString & label, originalLabels)
484   - if (!labelTable.contains(label))
485   - labelTable.insert(label, labelTable.size());
  483 + foreach (const QString &label, originalLabels)
  484 + if (!labelTable.contains(label)) {
  485 + int value; bool ok;
  486 + value = label.toInt(&ok);
  487 + // If the label is already an integer value we don't want to change it.
  488 + if (ok && preserveIntegers) labelTable.insert(label, value);
  489 + else labelTable.insert(label, labelTable.size());
  490 + }
486 491  
487 492 TemplateList result = tl;
488 493 for (int i=0; i<result.size(); i++)
... ...
openbr/openbr_plugin.h
... ... @@ -438,7 +438,7 @@ struct TemplateList : public QList&lt;Template&gt;
438 438 BR_EXPORT static TemplateList fromGallery(const File &gallery); /*!< \brief Create a template list from a br::Gallery. */
439 439  
440 440 /*!< \brief Ensure labels are in the range [0,numClasses-1]. */
441   - BR_EXPORT static TemplateList relabel(const TemplateList & tl, const QString & propName);
  441 + BR_EXPORT static TemplateList relabel(const TemplateList &tl, const QString &propName, bool preserveIntegers);
442 442  
443 443 QList<int> indexProperty(const QString & propName, QHash<QString, int> * valueMap=NULL,QHash<int, QVariant> * reverseLookup = NULL) const;
444 444 QList<int> indexProperty(const QString & propName, QHash<QString, int> & valueMap, QHash<int, QVariant> & reverseLookup) const;
... ...
openbr/plugins/eigen3.cpp
... ... @@ -317,7 +317,7 @@ class LDATransform : public Transform
317 317 void train(const TemplateList &_trainingSet)
318 318 {
319 319 // creates "Label"
320   - TemplateList trainingSet = TemplateList::relabel(_trainingSet, inputVariable);
  320 + TemplateList trainingSet = TemplateList::relabel(_trainingSet, inputVariable, isBinary);
321 321 int instances = trainingSet.size();
322 322  
323 323 // Perform PCA dimensionality reduction
... ...
openbr/plugins/gui.cpp
... ... @@ -447,7 +447,8 @@ public:
447 447 }
448 448 emit this->changeTitle(newTitle);
449 449  
450   - foreach(const cv::Mat & m, t) {
  450 + foreach (const cv::Mat &m, t) {
  451 + if (!m.data) continue;
451 452 qImageBuffer = toQImage(m);
452 453 displayBuffer->convertFromImage(qImageBuffer);
453 454  
... ...
openbr/plugins/slidingwindow.cpp
... ... @@ -42,15 +42,15 @@ class SlidingWindowTransform : public MetaTransform
42 42 {
43 43 Q_OBJECT
44 44 Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
45   - Q_PROPERTY(int stepSize READ get_stepSize WRITE set_stepSize RESET reset_stepSize STORED false)
46   - Q_PROPERTY(bool takeFirst READ get_takeFirst WRITE set_takeFirst RESET reset_takeFirst STORED false)
47 45 Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false)
  46 + Q_PROPERTY(bool takeFirst READ get_takeFirst WRITE set_takeFirst RESET reset_takeFirst STORED false)
48 47 Q_PROPERTY(float threshold READ get_threshold WRITE set_threshold RESET reset_threshold STORED false)
  48 + Q_PROPERTY(float stepFraction READ get_stepFraction WRITE set_stepFraction RESET reset_stepFraction STORED false)
49 49 BR_PROPERTY(br::Transform *, transform, NULL)
50   - BR_PROPERTY(int, stepSize, 1)
51   - BR_PROPERTY(bool, takeFirst, false)
52 50 BR_PROPERTY(int, windowWidth, 24)
  51 + BR_PROPERTY(bool, takeFirst, false)
53 52 BR_PROPERTY(float, threshold, 0)
  53 + BR_PROPERTY(float, stepFraction, 0.25)
54 54  
55 55 private:
56 56 int windowHeight;
... ... @@ -66,36 +66,6 @@ private:
66 66 }
67 67 }
68 68  
69   - void project(const Template &src, Template &dst) const
70   - {
71   - dst = src;
72   - // no need to slide a window over ground truth data
73   - if (src.file.getBool("Train", false)) return;
74   -
75   - dst.file.clearRects();
76   - float scale = src.file.get<float>("scale", 1);
77   - Template windowTemplate(src.file, src);
78   - QList<float> confidences = dst.file.getList<float>("Confidences", QList<float>());
79   - for (double y = 0; y + windowHeight < src.m().rows; y += stepSize) {
80   - for (double x = 0; x + windowWidth < src.m().cols; x += stepSize) {
81   - Mat windowMat(src, Rect(x, y, windowWidth, windowHeight));
82   - windowTemplate.replace(0,windowMat);
83   - Template detect;
84   - transform->project(windowTemplate, detect);
85   - float conf = detect.m().at<float>(0);
86   -
87   - // the result will be in the Label
88   - if (conf > threshold) {
89   - dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale));
90   - confidences.append(conf);
91   - if (takeFirst)
92   - return;
93   - }
94   - }
95   - }
96   - dst.file.setList<float>("Confidences", confidences);
97   - }
98   -
99 69 void store(QDataStream &stream) const
100 70 {
101 71 transform->store(stream);
... ... @@ -107,11 +77,71 @@ private:
107 77 transform->load(stream);
108 78 stream >> windowHeight;
109 79 }
  80 +
  81 + void project(const Template &src, Template &dst) const
  82 + {
  83 + (void)src;(void)dst;qFatal("don't do that");
  84 + }
  85 +
  86 + void project(const TemplateList &src, TemplateList &dst) const
  87 + {
  88 + float scale = src.first().file.get<float>("scale", 1);
  89 + projectHelp(src, dst, windowWidth, windowHeight, scale);
  90 + }
  91 +
  92 +protected:
  93 + void projectHelp(const TemplateList &src, TemplateList &dst, int windowWidth, int windowHeight, float scale = 1) const
  94 + {
  95 + // no need to slide a window over ground truth data
  96 + if (src.first().file.getBool("Train", false)) {
  97 + dst = src;
  98 + return;
  99 + }
  100 +
  101 + foreach (const Template &t, src) {
  102 + for (float y = 0; y + windowHeight < t.m().rows; y += windowHeight*stepFraction) {
  103 + for (float x = 0; x + windowWidth < t.m().cols; x += windowWidth*stepFraction) {
  104 + Mat windowMat(t.m(), Rect(x, y, windowWidth, windowHeight));
  105 + Template detect;
  106 + transform->project(Template(t.file, windowMat), detect);
  107 +
  108 + // the result will be the only value in the Mat
  109 + float conf = detect.m().at<float>(0);
  110 + if (conf > threshold) {
  111 + detect.file.set("Detection", QRectF(x*scale, y*scale, windowWidth*scale, windowHeight*scale));
  112 + detect.file.set("Confidence", conf);
  113 + dst.append(detect);
  114 + if (takeFirst)
  115 + return;
  116 + }
  117 + }
  118 + }
  119 + }
  120 + }
110 121 };
111 122  
112 123 BR_REGISTER(Transform, SlidingWindowTransform)
113 124  
114   -static TemplateList cropTrainingSamples(const TemplateList &data, const float aspectRatio, const int minSize = 0, const float maxOverlap = 0.5, const int negToPosRatio = 1)
  125 +/*!
  126 + * \ingroup transforms
  127 + * \brief Overloads SlidingWindowTransform for integral images that should be
  128 + * sampled at multiple scales.
  129 + * \author Josh Klontz \cite jklontz
  130 + */
  131 +class IntegralSlidingWindowTransform : public SlidingWindowTransform
  132 +{
  133 + Q_OBJECT
  134 +
  135 + void project(const TemplateList &src, TemplateList &dst) const
  136 + {
  137 + // TODO: call SlidingWindowTransform::project on multiple scales
  138 + SlidingWindowTransform::projectHelp(src, dst, 24, 24);
  139 + }
  140 +};
  141 +
  142 +BR_REGISTER(Transform, IntegralSlidingWindowTransform)
  143 +
  144 +static TemplateList cropTrainingSamples(const TemplateList &data, const float aspectRatio, const int minSize = 32, const float maxOverlap = 0.5, const int negToPosRatio = 1)
115 145 {
116 146 TemplateList result;
117 147 foreach (const Template &tmpl, data) {
... ... @@ -121,8 +151,8 @@ static TemplateList cropTrainingSamples(const TemplateList &amp;data, const float as
121 151 Rect &posRect = posRects[i];
122 152  
123 153 // Adjust for training samples that have different aspect ratios
124   - const int diff = posRect.width - int(posRect.height * aspectRatio);
125   - posRect.x += diff / 2;
  154 + const int diff = int(posRect.height * aspectRatio) - posRect.width;
  155 + posRect.x -= diff / 2;
126 156 posRect.width += diff;
127 157  
128 158 // Ignore samples larger than the image
... ... @@ -174,7 +204,7 @@ static TemplateList cropTrainingSamples(const TemplateList &amp;data, const float as
174 204  
175 205 /*!
176 206 * \ingroup transforms
177   - * \brief .
  207 + * \brief Pass along images at different scales.
178 208 * \author Austin Blanton \cite imaus10
179 209 */
180 210 class BuildScalesTransform : public MetaTransform
... ... @@ -219,25 +249,38 @@ private:
219 249  
220 250 void project(const Template &src, Template &dst) const
221 251 {
222   - dst = src;
  252 + (void)src;(void)dst;qFatal("please don't");
  253 + }
  254 +
  255 + void project(const TemplateList &src, TemplateList &dst) const
  256 + {
223 257 // do not scale images during training
224   - if (src.file.getBool("Train", false)) return;
225   -
226   - int rows = src.m().rows;
227   - int cols = src.m().cols;
228   - int windowHeight = (int) qRound((float) windowWidth / aspectRatio);
229   - float startScale;
230   - if ((cols / rows) > aspectRatio)
231   - startScale = qRound((float) rows / (float) windowHeight);
232   - else
233   - startScale = qRound((float) cols / (float) windowWidth);
234   - for (float scale = startScale; scale >= minScale; scale -= (1.0 - scaleFactor)) {
235   - Template scaleImg(src.file, Mat());
236   - scaleImg.file.set("scale", scale);
237   - resize(src, scaleImg, Size(qRound(cols / scale), qRound(rows / scale)));
238   - transform->project(scaleImg, dst);
239   - if (takeLargestScale && !dst.file.rects().empty())
240   - return;
  258 + if (src.first().file.getBool("Train", false)) {
  259 + dst = src;
  260 + return;
  261 + }
  262 +
  263 + foreach(const Template &t, src) {
  264 + int rows = t.m().rows;
  265 + int cols = t.m().cols;
  266 + int windowHeight = (int) qRound((float) windowWidth / aspectRatio);
  267 + float startScale;
  268 + if ((cols / rows) > aspectRatio)
  269 + startScale = qRound((float) rows / (float) windowHeight);
  270 + else
  271 + startScale = qRound((float) cols / (float) windowWidth);
  272 + for (float scale = startScale; scale >= minScale; scale -= (1.0 - scaleFactor)) {
  273 + Template scaleImg(t.file, Mat());
  274 + scaleImg.file.set("scale", scale);
  275 + resize(t.m(), scaleImg.m(), Size(qRound(cols / scale), qRound(rows / scale)));
  276 + TemplateList results;
  277 + TemplateList input;
  278 + input.append(scaleImg);
  279 + transform->project(input, results);
  280 + dst.append(results);
  281 + if (takeLargestScale && !dst.empty())
  282 + return;
  283 + }
241 284 }
242 285 }
243 286  
... ... @@ -270,6 +313,7 @@ class Detector : public Transform
270 313 {
271 314 const float aspectRatio = getAspectRatio(data);
272 315 TemplateList cropped = cropTrainingSamples(data, aspectRatio);
  316 + qDebug("Detector using: %d training samples.", cropped.size());
273 317 cropped.first().file.set("aspectRatio", aspectRatio);
274 318 transform->train(cropped);
275 319 }
... ... @@ -327,12 +371,19 @@ private:
327 371  
328 372 void project(const Template &src, Template &dst) const
329 373 {
330   - dst = src;
331   - if (!dst.file.contains("Confidences"))
332   - return;
  374 + (void)src;(void)dst;qFatal("nope");
  375 + }
333 376  
334   - //Compute overlap between rectangles and create discrete Laplacian matrix
335   - QList<Rect> rects = OpenCVUtils::toRects(src.file.rects());
  377 + void project(const TemplateList &src, TemplateList &dst) const
  378 + {
  379 + QList<Rect> rects;
  380 + QList<float> confidences;
  381 + foreach (const Template &t, src) {
  382 + rects.append(OpenCVUtils::toRect(t.file.get<QRectF>("Detection")));
  383 + confidences.append(t.file.get<float>("Confidence"));
  384 + }
  385 +
  386 + // Compute overlap between rectangles and create discrete Laplacian matrix
336 387 int n = rects.size();
337 388 if (n == 0)
338 389 return;
... ... @@ -379,12 +430,12 @@ private:
379 430 // each input dimension. Each input dimension corresponds to
380 431 // one of the input rect region. Thus, each eigenvector represents
381 432 // a set of overlaping regions.
382   - float midX[nRegions];
383   - float midY[nRegions];
384   - float avgWidth[nRegions];
385   - float avgHeight[nRegions];
386   - float confs[nRegions];
387   - int cnts[nRegions];
  433 + float * midX = new float[nRegions];
  434 + float * midY = new float[nRegions];
  435 + float * avgWidth = new float[nRegions];
  436 + float *avgHeight = new float[nRegions];
  437 + float *confs = new float[nRegions];
  438 + int *cnts = new int[nRegions];
388 439 int mx;
389 440 int mxIdx;
390 441 for (int i = 0 ; i < nRegions; i++) {
... ... @@ -396,7 +447,6 @@ private:
396 447 cnts[i] = 0;
397 448 }
398 449  
399   - QList<float> confidences = dst.file.getList<float>("Confidences");
400 450 for (int i = 0; i < n; i++) {
401 451 mx = 0.0;
402 452 mxIdx = -1;
... ... @@ -431,8 +481,20 @@ private:
431 481 }
432 482 }
433 483  
434   - dst.file.setRects(consolidatedRects);
435   - dst.file.setList<float>("Confidences", consolidatedConfidences);
  484 + for (int i=0; i<consolidatedRects.size(); i++) {
  485 + Template t(src.first().file);
  486 + t.file.set("Detection", OpenCVUtils::fromRect(consolidatedRects.at(i)));
  487 + t.file.set("Confidence", consolidatedConfidences.at(i));
  488 + dst.append(t);
  489 + }
  490 +
  491 + delete [] midX;
  492 + delete [] midY;
  493 + delete [] avgWidth;
  494 + delete [] avgHeight;
  495 + delete [] confs;
  496 + delete [] cnts;
  497 +
436 498 }
437 499 };
438 500  
... ...
openbr/plugins/stream.cpp
... ... @@ -363,7 +363,7 @@ public:
363 363 return this->templates.size();
364 364 }
365 365  
366   - bool open(TemplateList & input, br::Idiocy::StreamModes _mode)
  366 + bool open(const TemplateList & input, br::Idiocy::StreamModes _mode)
367 367 {
368 368 // Set up variables specific to us
369 369 current_template_idx = 0;
... ... @@ -1030,8 +1030,10 @@ public:
1030 1030 void projectUpdate(const TemplateList & src, TemplateList & dst)
1031 1031 {
1032 1032 dst = src;
  1033 + if (src.empty())
  1034 + return;
1033 1035  
1034   - bool res = readStage->dataSource.open(dst,readMode);
  1036 + bool res = readStage->dataSource.open(src,readMode);
1035 1037 if (!res) {
1036 1038 qDebug("stream failed to open %s", qPrintable(dst[0].file.name));
1037 1039 return;
... ... @@ -1082,6 +1084,8 @@ public:
1082 1084 // with anything output via the calls to finalize.
1083 1085 //dst = collectionStage->getOutput();
1084 1086  
  1087 + // dst is set to all output received by the final stage, along
  1088 + // with anything output via the calls to finalize.
1085 1089 foreach(const TemplateList & list, collector->sets) {
1086 1090 dst.append(list);
1087 1091 }
... ...
scripts/downloadDatasets.sh
... ... @@ -102,3 +102,21 @@ if [ ! -d ../data/MEDS/img ]; then
102 102 mv data/*/*.jpg ../data/MEDS/img
103 103 rm -r data NIST_SD32_MEDS-II_face.zip
104 104 fi
  105 +
  106 +#LFPW
  107 +if [ ! -d ../data/lfpw/trainset ]; then
  108 + echo "Downloading LFPW..."
  109 + if hash curl 2>/dev/null; then
  110 + curl -OL http://ibug.doc.ic.ac.uk/media/uploads/competitions/lfpw.zip
  111 + else
  112 + wget http://ibug.doc.ic.ac.uk/media/uploads/competitions/lfpw.zip
  113 + fi
  114 +
  115 + unzip lfpw.zip
  116 + mv lfpw ../data
  117 + cd ../data/lfpw
  118 + python ../../scripts/lfpwToSigset.py
  119 + cd ../../scripts
  120 + rm lfpw.zip
  121 +fi
  122 +
... ...
scripts/lfpwToSigset.py 0 → 100644
  1 +#!/usr/bin/python
  2 +
  3 +# This scripts converts the LFPW .pts files into xml sigsets that can be readily
  4 +# used within openbr.
  5 +
  6 +from xml.dom.minidom import Document
  7 +import glob
  8 +import os
  9 +
  10 +for lfpwType in ['train','test']:
  11 + files = glob.glob('%sset/*.pts' % lfpwType)
  12 + files.sort()
  13 + cnt = 0
  14 +
  15 + xmlDoc = Document()
  16 + xmlRoot = xmlDoc.createElement('biometric-signature-set')
  17 + for ptsFile in files:
  18 + cnt += 1
  19 + ini = open(ptsFile)
  20 + lines = ini.readlines()
  21 + ini.close()
  22 +
  23 + pntStrList = []
  24 + n = int(lines[1].split()[1])
  25 + for i in range(3,3+n):
  26 + pntStrList.append('(%s)' % (','.join(lines[i].split())))
  27 + pntStr = '[%s]' % ','.join(pntStrList)
  28 +
  29 + xmlSubj = xmlDoc.createElement('biometric-signature')
  30 + xmlSubj.setAttribute('name','subj_%05d' % cnt)
  31 + xmlPres = xmlDoc.createElement('presentation')
  32 + xmlPres.setAttribute('file-name','%sset/%s.png' % (lfpwType,os.path.splitext(ptsFile)[0]))
  33 + xmlPres.setAttribute('Points',pntStr)
  34 + xmlSubj.appendChild(xmlPres)
  35 + xmlRoot.appendChild(xmlSubj)
  36 +
  37 + if not os.path.exists('sigset'):
  38 + os.mkdir('sigset')
  39 + out = open('sigset/%s.xml' % lfpwType,'w')
  40 + print >> out, xmlRoot.toprettyxml()
  41 + out.close()
  42 +
  43 +
... ...
scripts/pedestrianBaselineLBP.sh
... ... @@ -13,7 +13,7 @@ fi
13 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"
14 14  
15 15 # Josh's new algorithm (in progress)
16   -# ALG2="Open+Cvt(Gray)+Detector(Gradient+Bin(0,360,9,true)+Merge+Integral+SlidingWindow(Identity))"
  16 +# ALG="Open+Cvt(Gray)+Detector(Gradient+Bin(0,360,9,true)+Merge+Integral+IntegralSlidingWindow(RecursiveIntegralSampler(2,2,0,PCA(0.95))+Cat+LDA(0.95,isBinary=true)))"
17 17  
18 18 br -useGui 0 \
19 19 -algorithm "${ALG}" \
... ...