From 9f89a05f088e6a5ff509b53929e081580b34d88e Mon Sep 17 00:00:00 2001 From: Josh Klontz Date: Thu, 14 Nov 2013 10:57:44 -0500 Subject: [PATCH] proposed implementation of #123 --- openbr/core/opencvutils.cpp | 10 ++++++++++ openbr/core/opencvutils.h | 1 + openbr/plugins/slidingwindow.cpp | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------- scripts/pedestrianBaselineLBP.sh | 10 +++++++--- 4 files changed, 88 insertions(+), 78 deletions(-) diff --git a/openbr/core/opencvutils.cpp b/openbr/core/opencvutils.cpp index bf91833..48e08e8 100644 --- a/openbr/core/opencvutils.cpp +++ b/openbr/core/opencvutils.cpp @@ -300,6 +300,16 @@ QList OpenCVUtils::fromRects(const QList &cvRects) return qRects; } +bool OpenCVUtils::overlaps(const QList &posRects, const Rect &negRect, double overlap) +{ + foreach (const Rect &posRect, posRects) { + Rect intersect = negRect & posRect; + if (intersect.area() > overlap*posRect.area()) + return true; + } + return false; +} + QDataStream &operator<<(QDataStream &stream, const Mat &m) { // Write header diff --git a/openbr/core/opencvutils.h b/openbr/core/opencvutils.h index d01c807..283aada 100644 --- a/openbr/core/opencvutils.h +++ b/openbr/core/opencvutils.h @@ -87,6 +87,7 @@ namespace OpenCVUtils QRectF fromRect(const cv::Rect &cvRect); QList toRects(const QList &qRects); QList fromRects(const QList &cvRects); + bool overlaps(const QList &posRects, const cv::Rect &negRect, double overlap); int getFourcc(); } diff --git a/openbr/plugins/slidingwindow.cpp b/openbr/plugins/slidingwindow.cpp index 7627f0d..36338e9 100644 --- a/openbr/plugins/slidingwindow.cpp +++ b/openbr/plugins/slidingwindow.cpp @@ -101,12 +101,73 @@ private: BR_REGISTER(Transform, SlidingWindowTransform) +static TemplateList cropTrainingSamples(const TemplateList &data, const float aspectRatio, const int minSize, const float maxOverlap, const int negToPosRatio) +{ + TemplateList result; + foreach (const Template &tmpl, data) { + QList posRects = OpenCVUtils::toRects(tmpl.file.rects()); + QList negRects; + for (int i=0; i= tmpl.m().cols) || + (posRect.y + posRect.height >= tmpl.m().rows) || + (posRect.x < 0) || + (posRect.y < 0)) + continue; + + result += Template(tmpl.file, Mat(tmpl, posRect)); + + // Add random negative samples + Mat m = tmpl.m(); + int sample = 0; + while (sample < negToPosRatio) { + const int x = rand() % m.cols; + const int y = rand() % m.rows; + const int maxWidth = m.cols - x; + const int maxHeight = m.rows - y; + if (maxWidth <= minSize || maxHeight <= minSize) + continue; + + int height; + int width; + if (aspectRatio > (float) maxWidth / (float) maxHeight) { + width = rand() % (maxWidth - minSize) + minSize; + height = qRound(width / aspectRatio); + } else { + height = rand() % (maxHeight - minSize) + minSize; + width = qRound(height * aspectRatio); + } + Rect negRect(x, y, width, height); + + // The negative samples cannot overlap the positive samples at + // all, but they may partially overlap with other negatives. + if (OpenCVUtils::overlaps(posRects, negRect, 0) || + OpenCVUtils::overlaps(negRects, negRect, maxOverlap)) + continue; + + result += Template(tmpl.file, Mat(tmpl, negRect)); + result.last().file.set("Label", QString("neg")); + sample++; + } + } + } + + return result; +} + /*! * \ingroup transforms * \brief . * \author Austin Blanton \cite imaus10 */ -class BuildScalesTransform : public Transform +class BuildScalesTransform : public MetaTransform { Q_OBJECT Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) @@ -117,7 +178,6 @@ class BuildScalesTransform : public Transform Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false) Q_PROPERTY(float minScale READ get_minScale WRITE set_minScale RESET reset_minScale STORED false) - Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false) BR_PROPERTY(br::Transform *, transform, NULL) BR_PROPERTY(double, scaleFactor, 0.75) BR_PROPERTY(bool, takeLargestScale, false) @@ -126,92 +186,27 @@ class BuildScalesTransform : public Transform BR_PROPERTY(int, minSize, 8) BR_PROPERTY(double, maxOverlap, 0) BR_PROPERTY(float, minScale, 1.0) - BR_PROPERTY(bool, negSamples, true) -public: - BuildScalesTransform() : Transform(false, true) {} private: - int windowHeight; float aspectRatio; + int windowHeight; - void train(const TemplateList &_data) + void train(const TemplateList &data) { - TemplateList data(_data); // have to make a copy b/c data is const aspectRatio = getAspectRatio(data); - data.first().file.set("aspectRatio", aspectRatio); - windowHeight = (int) qRound((float) windowWidth / aspectRatio); - + windowHeight = qRound(windowWidth / aspectRatio); if (transform->trainable) { TemplateList full; - foreach (const Template &tmpl, data) { - QList posRects = OpenCVUtils::toRects(tmpl.file.rects()); - QList negRects; - foreach (Rect posRect, posRects) { - - //Adjust for training samples that have different aspect ratios - int diff = posRect.width - (int)((float) posRect.height * aspectRatio); - posRect.x += diff / 2; - posRect.width += diff; - - if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) { - continue; - } - - Mat scaledImg; - resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,qRound(windowWidth / aspectRatio))); - Template pos(tmpl.file, scaledImg); - full += pos; - - // add random negative samples - if (negSamples) { - Mat m = tmpl.m(); - int sample = 0; - while (sample < negToPosRatio) { - int x = Common::RandSample(1, m.cols)[0]; - int y = Common::RandSample(1, m.rows)[0]; - int maxWidth = m.cols - x; - int maxHeight = m.rows - y; - if (maxWidth <= minSize || maxHeight <= minSize) - continue; - int height; - int width; - if (aspectRatio > (float) maxWidth / (float) maxHeight) { - width = Common::RandSample(1,maxWidth,minSize)[0]; - height = (int) qRound(width / aspectRatio); - } else { - height = Common::RandSample(1,maxHeight,minSize)[0]; - width = (int) qRound(height * aspectRatio); - } - Rect negRect(x, y, width, height); - // the negative samples cannot overlap the positive at all - // but they may overlap with other negatives - if (overlaps(posRects, negRect, 0) || overlaps(negRects, negRect, maxOverlap)) - continue; - negRects.append(negRect); - Template neg(tmpl.file, Mat()); - resize(Mat(tmpl, negRect), neg, Size(windowWidth, windowHeight)); - neg.file.set("Label", QString("neg")); - full += neg; - sample++; - } - } - } + foreach (const Template &roi, cropTrainingSamples(data, aspectRatio, minSize, maxOverlap, negToPosRatio)) { + Mat resized; + resize(roi, resized, Size(windowWidth, windowHeight)); + full += Template(roi.file, resized); } + full.first().file.set("aspectRatio", aspectRatio); transform->train(full); } } - bool overlaps(QList posRects, Rect negRect, double overlap) - { - foreach (const Rect posRect, posRects) { - Rect intersect = negRect & posRect; - if (intersect.area() > overlap*posRect.area()) - return true; - } - return false; - } - - void project(const Template &src, Template &dst) const { dst = src; diff --git a/scripts/pedestrianBaselineLBP.sh b/scripts/pedestrianBaselineLBP.sh index 1a6b52d..52d4813 100755 --- a/scripts/pedestrianBaselineLBP.sh +++ b/scripts/pedestrianBaselineLBP.sh @@ -1,10 +1,14 @@ #!/bin/bash -#Right now this is just a simple proof of concept. No quanititative eval is performed +# Right now this is just a simple proof of concept. No quantitative eval is performed # but instead the qualitative results are displayed. -#Make sure you set your data path. This will likely by your openbr/data directory. -INRIA_PATH=$DATA/INRIAPerson +# Make sure you set your data path. This will likely by your openbr/data directory. +if [ -z "$DATA" ]; then + INRIA_PATH=../data/INRIAPerson +else + INRIA_PATH=$DATA/INRIAPerson +fi 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" -- libgit2 0.21.4