diff --git a/openbr/core/boost.cpp b/openbr/core/boost.cpp index 6a75156..0f4e7fc 100644 --- a/openbr/core/boost.cpp +++ b/openbr/core/boost.cpp @@ -131,23 +131,16 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b //------------------------------------- FeatureEvaluator --------------------------------------- -void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount, int channels) +void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount) { representation = _representation; - - int dx, dy; - Size windowSize = representation->windowSize(&dx, &dy); - data.create((int)_maxSampleCount, (windowSize.width + dx) * (windowSize.height + dy), CV_32SC(channels)); cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); } -void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) +void FeatureEvaluator::setImage(const Template &src, uchar clsLabel, int idx) { cls.ptr(idx)[0] = clsLabel; - - Mat pp; - representation->preprocess(img, pp); - pp.reshape(0, 1).copyTo(data.row(idx)); + data.append(representation->preprocess(src)); } //----------------------------- CascadeBoostParams ------------------------------------------------- diff --git a/openbr/core/boost.h b/openbr/core/boost.h index 31c4a63..7a462a6 100644 --- a/openbr/core/boost.h +++ b/openbr/core/boost.h @@ -2,7 +2,6 @@ #define _BOOST_H_ #include "ml.h" -#include #include #ifdef _WIN32 @@ -17,9 +16,9 @@ namespace br struct FeatureEvaluator { ~FeatureEvaluator() {} - void init(Representation *_representation, int _maxSampleCount, int channels); - void setImage(const cv::Mat& img, uchar clsLabel, int idx); - float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } + void init(Representation *_representation, int _maxSampleCount); + void setImage(const Template &src, uchar clsLabel, int idx); + float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data[sampleIdx], featureIdx); } int getNumFeatures() const { return representation->numFeatures(); } int getMaxCatCount() const { return representation->maxCatCount(); } @@ -27,7 +26,8 @@ struct FeatureEvaluator const cv::Mat& getCls() const { return cls; } float getCls(int si) const { return cls.at(si, 0); } - cv::Mat data, cls; + cv::Mat cls; + TemplateList data; Representation *representation; }; diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index 5ae5069..783cb5d 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -882,13 +882,11 @@ public: static Representation *make(QString str, QObject *parent); /*!< \brief Make a representation from a string. */ - virtual void preprocess(const cv::Mat &src, cv::Mat &dst) const { dst = src; } - virtual void train(const QList &images, const QList &labels) { (void) images; (void)labels; } - - virtual float evaluate(const cv::Mat &image, int idx) const = 0; - // By convention, an empty indices list will result in all feature responses being calculated - // and returned. - virtual cv::Mat evaluate(const cv::Mat &image, const QList &indices = QList()) const = 0; + virtual Template preprocess(const Template &src) const { return src; } + virtual void train(const TemplateList &data) { (void)data; } + virtual float evaluate(const Template &src, int idx) const = 0; + // By convention passing an empty list evaluates all features in the representation + virtual cv::Mat evaluate(const Template &src, const QList &indices = QList()) const = 0; virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0; // dx and dy should indicate the change to the original window size after preprocessing virtual int numChannels() const { return 1; } @@ -905,13 +903,13 @@ public: static Classifier *make(QString str, QObject *parent); - virtual void train(const QList &images, const QList &labels) = 0; - virtual float classify(const cv::Mat &image, bool process = true, float *confidence = NULL) const = 0; + virtual void train(const TemplateList &data) { (void)data; } + virtual float classify(const Template &src, bool process = true, float *confidence = NULL) const = 0; // Slots for representations - virtual cv::Mat preprocess(const cv::Mat &image) const = 0; + virtual Template preprocess(const Template &src) const { return src; } virtual cv::Size windowSize(int *dx = NULL, int *dy = NULL) const = 0; - virtual int numFeatures() const = 0; + virtual int numFeatures() const { return 0; } }; diff --git a/openbr/plugins/classification/boostedforest.cpp b/openbr/plugins/classification/boostedforest.cpp index 809b5a9..3cf941e 100644 --- a/openbr/plugins/classification/boostedforest.cpp +++ b/openbr/plugins/classification/boostedforest.cpp @@ -125,20 +125,20 @@ private: QList classifiers; float threshold; - void train(const QList &images, const QList &labels) + void train(const TemplateList &data) { - representation->train(images, labels); + representation->train(data); CascadeBoostParams params(type, minTAR, maxFAR, trimRate, maxDepth, maxWeakCount); FeatureEvaluator featureEvaluator; - featureEvaluator.init(representation, images.size(), representation->numChannels()); + featureEvaluator.init(representation, data.size()); - for (int i = 0; i < images.size(); i++) - featureEvaluator.setImage(images[i], labels[i], i); + for (int i = 0; i < data.size(); i++) + featureEvaluator.setImage(data[i], data[i].file.get("Label"), i); CascadeBoost boost; - boost.train(&featureEvaluator, images.size(), 1024, 1024, representation->numChannels(), params); + boost.train(&featureEvaluator, data.size(), 1024, 1024, representation->numChannels(), params); threshold = boost.getThreshold(); @@ -149,13 +149,9 @@ private: } } - float classify(const Mat &image, bool process, float *confidence) const + float classify(const Template &src, bool process, float *confidence) const { - Mat m; - if (process) - m = preprocess(image); - else - m = image; + Template t = process ? preprocess(src) : src; float sum = 0; for (int i = 0; i < classifiers.size(); i++) { @@ -163,10 +159,10 @@ private: while (node->left) { if (representation->maxCatCount() > 0) { - int c = (int)representation->evaluate(m, node->featureIdx); + int c = (int)representation->evaluate(t, node->featureIdx); node = (node->subset[c >> 5] & (1 << (c & 31))) ? node->left : node->right; } else { - double val = representation->evaluate(m, node->featureIdx); + double val = representation->evaluate(t, node->featureIdx); node = val <= node->threshold ? node->left : node->right; } } @@ -184,11 +180,9 @@ private: return representation->numFeatures(); } - Mat preprocess(const Mat &image) const + Template preprocess(const Template &src) const { - Mat dst; - representation->preprocess(image, dst); - return dst; + return representation->preprocess(src); } Size windowSize(int *dx, int *dy) const diff --git a/openbr/plugins/classification/cascade.cpp b/openbr/plugins/classification/cascade.cpp index 5d91efc..bf0a448 100644 --- a/openbr/plugins/classification/cascade.cpp +++ b/openbr/plugins/classification/cascade.cpp @@ -1,5 +1,5 @@ #include -#include + #include #include @@ -100,8 +100,8 @@ class CascadeClassifier : public Classifier BR_PROPERTY(bool, requireAllStages, false) QList stages; - QList posImages, negImages; - QList posSamples, negSamples; + TemplateList posImages, negImages; + TemplateList posSamples, negSamples; QList indices; int negIndex, posIndex, samplingRound; @@ -113,18 +113,17 @@ class CascadeClassifier : public Classifier negIndex = posIndex = samplingRound = 0; } - bool getPositive(Mat &img) + bool getPositive(Template &img) { if (posIndex >= posImages.size()) return false; - - posImages[indices[posIndex++]].copyTo(img); + img = posImages[indices[posIndex++]]; return true; } - Mat getNegative(Point &offset) + Template getNegative(Point &offset) { - Mat negative; + Template negative; const Size size = windowSize(); // Grab negative from list @@ -136,9 +135,9 @@ class CascadeClassifier : public Classifier samplingRound = samplingRound % (size.width * size.height); negIndex %= count; - offset.x = qMin( (int)samplingRound % size.width, negative.cols - size.width); - offset.y = qMin( (int)samplingRound / size.width, negative.rows - size.height); - if (!negative.empty() && negative.type() == CV_8UC1 + offset.x = qMin( (int)samplingRound % size.width, negative.m().cols - size.width); + offset.y = qMin( (int)samplingRound / size.width, negative.m().rows - size.height); + if (!negative.m().empty() && negative.m().type() == CV_8UC1 && offset.x >= 0 && offset.y >= 0) break; } @@ -150,16 +149,16 @@ class CascadeClassifier : public Classifier { uint64 passedNegatives = 0; forever { - Mat negative; + Template negative; Point offset; QMutexLocker samplingLocker(&samplingMutex); negative = getNegative(offset); samplingLocker.unlock(); - Miner miner(negative, windowSize(), offset); + Miner miner(negative.m(), windowSize(), offset); forever { bool newImg; - Mat sample = miner.mine(&newImg); + Template sample(negative.file, miner.mine(&newImg)); if (!newImg) { if (negSamples.size() >= numNegs) return passedNegatives; @@ -181,16 +180,16 @@ class CascadeClassifier : public Classifier } } - void train(const QList &images, const QList &labels) + void train(const TemplateList &data) { - for (int i = 0; i < images.size(); i++) - labels[i] == 1 ? posImages.append(images[i]) : negImages.append(images[i]); + foreach (const Template &t, data) + t.file.get("Label") == 1.0f ? posImages.append(t) : negImages.append(t); - qDebug() << "Total images:" << images.size() + qDebug() << "Total images:" << data.size() << "\nTotal positive images:" << posImages.size() << "\nTotal negative images:" << negImages.size(); - indices = Common::RandSample(posImages.size(),posImages.size(),true); + indices = Common::RandSample(posImages.size(), posImages.size(), true); stages.reserve(numStages); for (int i = 0; i < numStages; i++) { @@ -209,27 +208,17 @@ class CascadeClassifier : public Classifier return; } - QList posLabels; - posLabels.reserve(posSamples.size()); - for (int j=0; j negLabels; - negLabels.reserve(negSamples.size()); - for (int j=0; jtrain(posSamples+negSamples, posLabels+negLabels); + stages[i]->train(posSamples + negSamples); qDebug() << "END>"; } } - float classify(const Mat &image, bool process, float *confidence) const + float classify(const Template &src, bool process, float *confidence) const { float stageConf = 0.0f; foreach (const Classifier *stage, stages) { - float result = stage->classify(image, process, &stageConf); + float result = stage->classify(src, process, &stageConf); if (confidence) *confidence += stageConf; if (result == 0.0f) @@ -243,9 +232,9 @@ class CascadeClassifier : public Classifier return stages.first()->numFeatures(); } - Mat preprocess(const Mat &image) const + Template preprocess(const Template &src) const { - return stages.first()->preprocess(image); + return stages.first()->preprocess(src); } Size windowSize(int *dx = NULL, int *dy = NULL) const @@ -273,16 +262,13 @@ class CascadeClassifier : public Classifier private: float getSamples() { - posSamples.clear(); - posSamples.reserve(numPos); - negSamples.clear(); - negSamples.reserve(numNegs); + posSamples.clear(); posSamples.reserve(numPos); + negSamples.clear(); negSamples.reserve(numNegs); posIndex = 0; float confidence; while (posSamples.size() < numPos) { - Mat pos(windowSize(), CV_8UC1); - + Template pos; if (!getPositive(pos)) qFatal("Cannot get another positive sample!"); diff --git a/openbr/plugins/classification/liblinear.cpp b/openbr/plugins/classification/liblinear.cpp index 2bebbc4..b3d4035 100644 --- a/openbr/plugins/classification/liblinear.cpp +++ b/openbr/plugins/classification/liblinear.cpp @@ -138,7 +138,7 @@ private: param.weight = NULL; } - m = *train_svm(&prob, ¶m); + //m = *train_svm(&prob, ¶m); delete[] param.weight; delete[] param.weight_label; diff --git a/openbr/plugins/imgproc/slidingwindow.cpp b/openbr/plugins/imgproc/slidingwindow.cpp index 1517c1b..2fdcd00 100644 --- a/openbr/plugins/imgproc/slidingwindow.cpp +++ b/openbr/plugins/imgproc/slidingwindow.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -35,7 +34,6 @@ namespace br * \br_property int minSize The smallest sized object to detect in pixels * \br_property int maxSize The largest sized object to detect in pixels. A negative value will set maxSize == image size * \br_property float scaleFactor The factor to scale the image by during each resize. - * \br_property int minNeighbors Parameter for non-maximum supression * \br_property float confidenceThreshold A threshold for positive detections. Positive detections returned by the classifier that have confidences below this threshold are considered negative detections. * \br_property float eps Parameter for non-maximum supression */ @@ -60,7 +58,7 @@ class SlidingWindowTransform : public MetaTransform void train(const TemplateList &data) { - classifier->train(data.data(), File::get(data, "Label", -1)); + classifier->train(data); } void project(const Template &src, Template &dst) const @@ -123,15 +121,18 @@ class SlidingWindowTransform : public MetaTransform Mat scaledImage(scaledImageSize, CV_8U, imageBuffer.data); resize(m, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR); - Mat repImage = classifier->preprocess(scaledImage); + + Template repImage(t.file, scaledImage); + repImage = classifier->preprocess(repImage); int step = factor > 2. ? 1 : 2; for (int y = 0; y < processingRectSize.height; y += step) { for (int x = 0; x < processingRectSize.width; x += step) { - Mat window = repImage(Rect(Point(x, y), Size(originalWindowSize.width + dx, originalWindowSize.height + dy))).clone(); + Mat window = repImage.m()(Rect(Point(x, y), Size(originalWindowSize.width + dx, originalWindowSize.height + dy))).clone(); + Template t(window); float confidence = 0; - int result = classifier->classify(window, false, &confidence); + int result = classifier->classify(t, false, &confidence); if (result == 1) { rects.append(Rect(cvRound(x*factor), cvRound(y*factor), windowSize.width, windowSize.height)); diff --git a/openbr/plugins/representation/haar.cpp b/openbr/plugins/representation/haar.cpp index c803aa3..fcf94d1 100644 --- a/openbr/plugins/representation/haar.cpp +++ b/openbr/plugins/representation/haar.cpp @@ -80,23 +80,25 @@ class HaarRepresentation : public Representation } } - void preprocess(const Mat &src, Mat &dst) const + Template preprocess(const Template &src) const { + Template dst; integral(src, dst); + return dst; } - float evaluate(const Mat &image, int idx) const + float evaluate(const Template &src, int idx) const { - return (float)features[idx].calc(image); + return (float)features[idx].calc(src.m()); } - Mat evaluate(const Mat &image, const QList &indices) const + Mat evaluate(const Template &src, const QList &indices) const { int size = indices.empty() ? numFeatures() : indices.size(); Mat result(1, size, CV_32FC1); for (int i = 0; i < size; i++) - result.at(i) = evaluate(image, indices.empty() ? i : indices[i]); + result.at(i) = evaluate(src, indices.empty() ? i : indices[i]); return result; } diff --git a/openbr/plugins/representation/mblbp.cpp b/openbr/plugins/representation/mblbp.cpp index 2a312f6..7f815ba 100644 --- a/openbr/plugins/representation/mblbp.cpp +++ b/openbr/plugins/representation/mblbp.cpp @@ -39,32 +39,36 @@ class MBLBPRepresentation : public Representation void init() { - int offset = winWidth + 1; - for (int x = 0; x < winWidth; x++ ) - for (int y = 0; y < winHeight; y++ ) - for (int w = 1; w <= winWidth / 3; w++ ) - for (int h = 1; h <= winHeight / 3; h++ ) - if ((x+3*w <= winWidth) && (y+3*h <= winHeight) ) - features.append(Feature(offset, x, y, w, h ) ); + if (features.isEmpty()) { + int offset = winWidth + 1; + for (int x = 0; x < winWidth; x++ ) + for (int y = 0; y < winHeight; y++ ) + for (int w = 1; w <= winWidth / 3; w++ ) + for (int h = 1; h <= winHeight / 3; h++ ) + if ((x+3*w <= winWidth) && (y+3*h <= winHeight) ) + features.append(Feature(offset, x, y, w, h ) ); + } } - void preprocess(const Mat &src, Mat &dst) const + Template preprocess(const Template &src) const { + Template dst; integral(src, dst); + return dst; } - float evaluate(const Mat &image, int idx) const + float evaluate(const Template &src, int idx) const { - return (float)features[idx].calc(image); + return (float)features[idx].calc(src.m()); } - Mat evaluate(const Mat &image, const QList &indices) const + Mat evaluate(const Template &src, const QList &indices) const { int size = indices.empty() ? numFeatures() : indices.size(); Mat result(1, size, CV_32FC1); for (int i = 0; i < size; i++) - result.at(i) = evaluate(image, indices.empty() ? i : indices[i]); + result.at(i) = evaluate(src, indices.empty() ? i : indices[i]); return result; } diff --git a/openbr/plugins/representation/npd.cpp b/openbr/plugins/representation/npd.cpp index 30f1c5e..90655f8 100644 --- a/openbr/plugins/representation/npd.cpp +++ b/openbr/plugins/representation/npd.cpp @@ -16,23 +16,25 @@ class NPDRepresentation : public Representation void init() { - for (int p1 = 0; p1 < (winWidth * winHeight); p1++) - for (int p2 = p1; p2 < (winWidth * winHeight); p2++) - features.append(Feature(p1, p2)); + if (features.isEmpty()) { + for (int p1 = 0; p1 < (winWidth * winHeight); p1++) + for (int p2 = p1; p2 < (winWidth * winHeight); p2++) + features.append(Feature(p1, p2)); + } } - float evaluate(const Mat &image, int idx) const + float evaluate(const Template &src, int idx) const { - return features[idx].calc(image); + return features[idx].calc(src.m()); } - Mat evaluate(const Mat &image, const QList &indices) const + Mat evaluate(const Template &src, const QList &indices) const { int size = indices.empty() ? numFeatures() : indices.size(); Mat result(1, size, CV_32FC1); for (int i = 0; i < size; i++) - result.at(i) = evaluate(image, indices.empty() ? i : indices[i]); + result.at(i) = evaluate(src, indices.empty() ? i : indices[i]); return result; } @@ -49,10 +51,10 @@ class NPDRepresentation : public Representation struct Feature { Feature() {} - Feature(int p1, int p2) { p[0] = p1; p[1] = p2; } + Feature(int p0, int p1) : p0(p0), p1(p1) {} float calc(const Mat &image) const; - int p[2]; + int p0, p1; }; QList features; }; @@ -61,9 +63,9 @@ BR_REGISTER(Representation, NPDRepresentation) inline float NPDRepresentation::Feature::calc(const Mat &image) const { - const int *ptr = image.ptr(); - int v1 = ptr[p[0]], v2 = ptr[p[1]]; - return v1 == 0 && v2 == 0 ? 0 : ((float)(v1 - v2)) / (v1 + v2); + const uchar *ptr = image.ptr(); + int v1 = (int)ptr[p0], v2 = (int)ptr[p1]; + return (v1 + v2) == 0 ? 0 : (1.0 * (v1 - v2)) / (v1 + v2); } } // namespace br diff --git a/openbr/plugins/representation/random.cpp b/openbr/plugins/representation/random.cpp index 6ac9fa2..1fc56bd 100644 --- a/openbr/plugins/representation/random.cpp +++ b/openbr/plugins/representation/random.cpp @@ -28,9 +28,9 @@ class RandomRepresentation : public Representation QList features; - void train(const QList &images, const QList &labels) + void train(const TemplateList &data) { - representation->train(images, labels); + representation->train(data); const int nFeatures = representation->numFeatures(); @@ -40,17 +40,17 @@ class RandomRepresentation : public Representation features = Common::RandSample(count,nFeatures,0,true); } - void preprocess(const Mat &src, Mat &dst) const + Template preprocess(const Template &src) const { - representation->preprocess(src,dst); + return representation->preprocess(src); } - float evaluate(const Mat &image, int idx) const + float evaluate(const Template &src, int idx) const { - return representation->evaluate(image,features[idx]); + return representation->evaluate(src, features[idx]); } - Mat evaluate(const Mat &image, const QList &indices) const + Mat evaluate(const Template &src, const QList &indices) const { QList newIndices; if (indices.empty()) @@ -59,7 +59,7 @@ class RandomRepresentation : public Representation for (int i = 0; i < indices.size(); i++) newIndices.append(features[indices[i]]); - return representation->evaluate(image,newIndices); + return representation->evaluate(src, newIndices); } int numFeatures() const @@ -108,6 +108,3 @@ BR_REGISTER(Representation, RandomRepresentation) } // namespace br #include "representation/random.moc" - - -