From 40600fa5048ddf43bf8fc7602694ad723234c87d Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Sat, 10 Nov 2012 00:49:51 +0400 Subject: [PATCH] GPU version becomes algorithm --- modules/gpu/include/opencv2/gpu/gpu.hpp | 67 +++++----- modules/gpu/perf/perf_softcascade.cpp | 146 +++++++++++---------- modules/gpu/src/gpu_init.cpp | 60 +++++++++ modules/gpu/src/softcascade.cpp | 161 +++++++++++++----------- modules/gpu/test/test_softcascade.cpp | 147 +++++++++++++--------- 5 files changed, 346 insertions(+), 235 deletions(-) create mode 100644 modules/gpu/src/gpu_init.cpp diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 9b59c6004..4fc6179d8 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -1534,10 +1534,12 @@ public: // ======================== GPU version for soft cascade ===================== // -class CV_EXPORTS SoftCascade +// Implementation of soft (stageless) cascaded detector. +class CV_EXPORTS SCascade : public Algorithm { public: + // Representation of detectors result. struct CV_EXPORTS Detection { ushort x; @@ -1549,47 +1551,44 @@ public: enum {PEDESTRIAN = 0}; }; - //! An empty cascade will be created. - SoftCascade(); - //! Cascade will be created from file for scales from minScale to maxScale. - //! Param filename is a path to xml-serialized cascade. - //! Param minScale is a minimum scale relative to the original size of the image on which cascade will be applyed. - //! Param minScale is a maximum scale relative to the original size of the image on which cascade will be applyed. - SoftCascade( const string& filename, const float minScale = 0.4f, const float maxScale = 5.f); + // An empty cascade will be created. + // Param minScale is a minimum scale relative to the original size of the image on which cascade will be applyed. + // Param minScale is a maximum scale relative to the original size of the image on which cascade will be applyed. + // Param scales is a number of scales from minScale to maxScale. + // Param rejfactor is used for NMS. + SCascade(const double minScale = 0.4, const double maxScale = 5., const int scales = 55, const int rejfactor = 1); - //! cascade will be loaded from file "filename". The previous cascade will be destroyed. - //! Param filename is a path to xml-serialized cascade. - //! Param minScale is a minimum scale relative to the original size of the image on which cascade will be applyed. - //! Param minScale is a maximum scale relative to the original size of the image on which cascade will be applyed. - bool load( const string& filename, const float minScale = 0.4f, const float maxScale = 5.f); + virtual ~SCascade(); - virtual ~SoftCascade(); + cv::AlgorithmInfo* info() const; - //! detect specific objects on in the input frame for all scales computed flom minScale and maxscale values - //! Param image is input frame for detector. Cascade will be applied to it. - //! Param rois is a mask - //! Param objects 4-channel matrix thet contain detected rectangles - //! Param rejectfactor used for final object box computing - virtual void detectMultiScale(const GpuMat& image, const GpuMat& rois, GpuMat& objects, - int rejectfactor = 1, int specificScale = -1) const; + // Load cascade from FileNode. + // Param fn is a root node for cascade. Should be . + virtual bool load(const FileNode& fn); - //! detect specific objects on in the input frame for all scales computed flom minScale and maxscale values. - //! asynchronous version. - //! Param image is input frame for detector. Cascade will be applied to it. - //! Param rois is a mask - //! Param objects 4-channel matrix thet contain detected rectangles - //! Param rejectfactor used for final object box computing - //! Param ndet retrieves number of detections - //! Param stream wrapper for CUDA stream - virtual void detectMultiScale(const GpuMat& image, const GpuMat& rois, GpuMat& objects, - int rejectfactor, GpuMat& ndet, Stream stream) const; + // Load cascade config. + virtual void read(const FileNode& fn); - cv::Size getRoiSize() const; + // Return the vector of Decection objcts. + // Param image is a frame on which detector will be applied. + // Param rois is a vector of regions of interest. Only the objects that fall into one of the regions will be returned. + // Param objects is an output array of Detections + virtual void detect(InputArray image, InputArray rois, OutputArray objects, Stream& stream = Stream::Null()) const; + virtual void detect(InputArray image, InputArray rois, OutputArray objects, const int level, Stream& stream = Stream::Null()) const; + + void genRoi(InputArray roi, OutputArray mask) const; private: - struct Filds; - Filds* filds; + + struct Fields; + Fields* fields; + + double minScale; + double maxScale; + + int scales; + int rejfactor; }; ////////////////////////////////// SURF ////////////////////////////////////////// diff --git a/modules/gpu/perf/perf_softcascade.cpp b/modules/gpu/perf/perf_softcascade.cpp index 9b53b2e84..1e62af8eb 100644 --- a/modules/gpu/perf/perf_softcascade.cpp +++ b/modules/gpu/perf/perf_softcascade.cpp @@ -25,8 +25,8 @@ void fixture##_##name::__cpu() { FAIL() << "No such CPU implementation analogy"; namespace { struct DetectionLess { - bool operator()(const cv::gpu::SoftCascade::Detection& a, - const cv::gpu::SoftCascade::Detection& b) const + bool operator()(const cv::gpu::SCascade::Detection& a, + const cv::gpu::SCascade::Detection& b) const { if (a.x != b.x) return a.x < b.x; else if (a.y != b.y) return a.y < b.y; @@ -51,7 +51,7 @@ namespace { { cv::Mat detections(objects); - typedef cv::gpu::SoftCascade::Detection Detection; + typedef cv::gpu::SCascade::Detection Detection; Detection* begin = (Detection*)(detections.ptr(0)); Detection* end = (Detection*)(detections.ptr(0) + detections.cols); std::sort(begin, end, DetectionLess()); @@ -62,52 +62,54 @@ namespace { typedef std::tr1::tuple fixture_t; -typedef perf::TestBaseWithParam SoftCascadeTest; +typedef perf::TestBaseWithParam SCascadeTest; -GPU_PERF_TEST_P(SoftCascadeTest, detect, +GPU_PERF_TEST_P(SCascadeTest, detect, testing::Combine( testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("cv/cascadeandhog/bahnhof/image_00000000_0.png")))) { } -RUN_GPU(SoftCascadeTest, detect) +RUN_GPU(SCascadeTest, detect) { cv::Mat cpu = readImage (GET_PARAM(1)); ASSERT_FALSE(cpu.empty()); cv::gpu::GpuMat colored(cpu); - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath(GET_PARAM(0)))); + cv::gpu::SCascade cascade; - cv::gpu::GpuMat objectBoxes(1, 10000 * sizeof(cv::gpu::SoftCascade::Detection), CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1), trois; + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(0)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); + + cv::gpu::GpuMat objectBoxes(1, 10000 * sizeof(cv::gpu::SCascade::Detection), CV_8UC1), rois(colored.size(), CV_8UC1), trois; rois.setTo(1); - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cv::gpu::GpuMat curr = objectBoxes; - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); TEST_CYCLE() { - curr = objectBoxes; - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); } - SANITY_CHECK(sortDetections(curr)); + SANITY_CHECK(sortDetections(objectBoxes)); } -NO_CPU(SoftCascadeTest, detect) +NO_CPU(SCascadeTest, detect) -// RUN_CPU(SoftCascadeTest, detect) +// RUN_CPU(SCascadeTest, detect) // { // cv::Mat colored = readImage(GET_PARAM(1)); // ASSERT_FALSE(colored.empty()); -// cv::SoftCascade cascade; +// cv::SCascade cascade; // ASSERT_TRUE(cascade.load(getDataPath(GET_PARAM(0)))); // std::vector rois; -// typedef cv::SoftCascade::Detection Detection; +// typedef cv::SCascade::Detection Detection; // std::vectorobjects; // cascade.detectMultiScale(colored, rois, objects); @@ -124,42 +126,46 @@ static cv::Rect getFromTable(int idx) { static const cv::Rect rois[] = { - cv::Rect( 65, 20, 35, 80), - cv::Rect( 95, 35, 45, 40), - cv::Rect( 45, 35, 45, 40), - cv::Rect( 25, 27, 50, 45), - cv::Rect(100, 50, 45, 40), + cv::Rect( 65 * 4, 20 * 4, 35 * 4, 80 * 4), + cv::Rect( 95 * 4, 35 * 4, 45 * 4, 40 * 4), + cv::Rect( 45 * 4, 35 * 4, 45 * 4, 40 * 4), + cv::Rect( 25 * 4, 27 * 4, 50 * 4, 45 * 4), + cv::Rect(100 * 4, 50 * 4, 45 * 4, 40 * 4), - cv::Rect( 60, 30, 45, 40), - cv::Rect( 40, 55, 50, 40), - cv::Rect( 48, 37, 72, 80), - cv::Rect( 48, 32, 85, 58), - cv::Rect( 48, 0, 32, 27) + cv::Rect( 60 * 4, 30 * 4, 45 * 4, 40 * 4), + cv::Rect( 40 * 4, 55 * 4, 50 * 4, 40 * 4), + cv::Rect( 48 * 4, 37 * 4, 72 * 4, 80 * 4), + cv::Rect( 48 * 4, 32 * 4, 85 * 4, 58 * 4), + cv::Rect( 48 * 4, 0 * 4, 32 * 4, 27 * 4) }; return rois[idx]; } typedef std::tr1::tuple roi_fixture_t; -typedef perf::TestBaseWithParam SoftCascadeTestRoi; +typedef perf::TestBaseWithParam SCascadeTestRoi; -GPU_PERF_TEST_P(SoftCascadeTestRoi, detectInRoi, +GPU_PERF_TEST_P(SCascadeTestRoi, detectInRoi, testing::Combine( testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("cv/cascadeandhog/bahnhof/image_00000000_0.png")), testing::Range(0, 5))) {} -RUN_GPU(SoftCascadeTestRoi, detectInRoi) +RUN_GPU(SCascadeTestRoi, detectInRoi) { cv::Mat cpu = readImage (GET_PARAM(1)); ASSERT_FALSE(cpu.empty()); cv::gpu::GpuMat colored(cpu); - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath(GET_PARAM(0)))); + cv::gpu::SCascade cascade; - cv::gpu::GpuMat objectBoxes(1, 16384 * 20, CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1); + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(0)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); + + cv::gpu::GpuMat objectBoxes(1, 16384 * 20, CV_8UC1), rois(colored.size(), CV_8UC1); rois.setTo(0); int nroi = GET_PARAM(2); @@ -172,40 +178,42 @@ RUN_GPU(SoftCascadeTestRoi, detectInRoi) } cv::gpu::GpuMat trois; - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cv::gpu::GpuMat curr = objectBoxes; - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); TEST_CYCLE() { - curr = objectBoxes; - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); } - SANITY_CHECK(sortDetections(curr)); + SANITY_CHECK(sortDetections(objectBoxes)); } -NO_CPU(SoftCascadeTestRoi, detectInRoi) +NO_CPU(SCascadeTestRoi, detectInRoi) -GPU_PERF_TEST_P(SoftCascadeTestRoi, detectEachRoi, +GPU_PERF_TEST_P(SCascadeTestRoi, detectEachRoi, testing::Combine( testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("cv/cascadeandhog/bahnhof/image_00000000_0.png")), testing::Range(0, 10))) {} -RUN_GPU(SoftCascadeTestRoi, detectEachRoi) +RUN_GPU(SCascadeTestRoi, detectEachRoi) { cv::Mat cpu = readImage (GET_PARAM(1)); ASSERT_FALSE(cpu.empty()); cv::gpu::GpuMat colored(cpu); - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath(GET_PARAM(0)))); + cv::gpu::SCascade cascade; - cv::gpu::GpuMat objectBoxes(1, 16384 * 20, CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1); + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(0)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); + + cv::gpu::GpuMat objectBoxes(1, 16384 * 20, CV_8UC1), rois(colored.size(), CV_8UC1); rois.setTo(0); int idx = GET_PARAM(2); @@ -213,24 +221,22 @@ RUN_GPU(SoftCascadeTestRoi, detectEachRoi) cv::gpu::GpuMat sub(rois, r); sub.setTo(1); - cv::gpu::GpuMat curr = objectBoxes; cv::gpu::GpuMat trois; - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); TEST_CYCLE() { - curr = objectBoxes; - cascade.detectMultiScale(colored, trois, curr); + cascade.detect(colored, trois, objectBoxes); } - SANITY_CHECK(sortDetections(curr)); + SANITY_CHECK(sortDetections(objectBoxes)); } -NO_CPU(SoftCascadeTestRoi, detectEachRoi) +NO_CPU(SCascadeTestRoi, detectEachRoi) -GPU_PERF_TEST_P(SoftCascadeTest, detectOnIntegral, +GPU_PERF_TEST_P(SCascadeTest, detectOnIntegral, testing::Combine( testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("cv/cascadeandhog/integrals.xml")))) @@ -243,37 +249,39 @@ GPU_PERF_TEST_P(SoftCascadeTest, detectOnIntegral, return std::string(s); } -RUN_GPU(SoftCascadeTest, detectOnIntegral) +RUN_GPU(SCascadeTest, detectOnIntegral) { - cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(1)), cv::FileStorage::READ); - ASSERT_TRUE(fs.isOpened()); + cv::FileStorage fsi(perf::TestBase::getDataPath(GET_PARAM(1)), cv::FileStorage::READ); + ASSERT_TRUE(fsi.isOpened()); cv::gpu::GpuMat hogluv(121 * 10, 161, CV_32SC1); for (int i = 0; i < 10; ++i) { cv::Mat channel; - fs[std::string("channel") + itoa(i)] >> channel; + fsi[std::string("channel") + itoa(i)] >> channel; cv::gpu::GpuMat gchannel(hogluv, cv::Rect(0, 121 * i, 161, 121)); gchannel.upload(channel); } - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath(GET_PARAM(0)))); + cv::gpu::SCascade cascade; - cv::gpu::GpuMat objectBoxes(1, 10000 * sizeof(cv::gpu::SoftCascade::Detection), CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1), trois; + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(0)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); + + cv::gpu::GpuMat objectBoxes(1, 10000 * sizeof(cv::gpu::SCascade::Detection), CV_8UC1), rois(cv::Size(640, 480), CV_8UC1), trois; rois.setTo(1); - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cv::gpu::GpuMat curr = objectBoxes; - cascade.detectMultiScale(hogluv, trois, curr); + cascade.detect(hogluv, trois, objectBoxes); TEST_CYCLE() { - curr = objectBoxes; - cascade.detectMultiScale(hogluv, trois, curr); + cascade.detect(hogluv, trois, objectBoxes); } - SANITY_CHECK(sortDetections(curr)); + SANITY_CHECK(sortDetections(objectBoxes)); } -NO_CPU(SoftCascadeTest, detectOnIntegral) \ No newline at end of file +NO_CPU(SCascadeTest, detectOnIntegral) \ No newline at end of file diff --git a/modules/gpu/src/gpu_init.cpp b/modules/gpu/src/gpu_init.cpp new file mode 100644 index 000000000..f25bc2ceb --- /dev/null +++ b/modules/gpu/src/gpu_init.cpp @@ -0,0 +1,60 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include + +namespace cv { namespace gpu +{ + +CV_INIT_ALGORITHM(SCascade, "CascadeDetector.SCascade", + obj.info()->addParam(obj, "minScale", obj.minScale); + obj.info()->addParam(obj, "maxScale", obj.maxScale); + obj.info()->addParam(obj, "scales", obj.scales); + obj.info()->addParam(obj, "rejfactor", obj.rejfactor)); + +bool initModule_gpu(void) +{ + Ptr sc = createSCascade(); + return sc->info() != 0; +} + +} } \ No newline at end of file diff --git a/modules/gpu/src/softcascade.cpp b/modules/gpu/src/softcascade.cpp index 1e0c271b9..02481ed37 100644 --- a/modules/gpu/src/softcascade.cpp +++ b/modules/gpu/src/softcascade.cpp @@ -45,21 +45,18 @@ #if !defined (HAVE_CUDA) -cv::gpu::SoftCascade::SoftCascade() : filds(0) { throw_nogpu(); } -cv::gpu::SoftCascade::SoftCascade( const string&, const float, const float) : filds(0) { throw_nogpu(); } -cv::gpu::SoftCascade::~SoftCascade() { throw_nogpu(); } -bool cv::gpu::SoftCascade::load( const string&, const float, const float) { throw_nogpu(); return false; } -void cv::gpu::SoftCascade::detectMultiScale(const GpuMat&, const GpuMat&, GpuMat&, const int, int) const -{ - throw_nogpu(); -} +cv::gpu::SCascade::SCascade(const double, const double, const int, const int) { throw_nogpu(); } -void cv::gpu::SoftCascade::detectMultiScale(const GpuMat&, const GpuMat&, GpuMat&, int, GpuMat&, Stream) const -{ - throw_nogpu(); -} +cv::gpu::SCascade::~SCascade() { throw_nogpu(); } -cv::Size cv::gpu::SoftCascade::getRoiSize() const { throw_nogpu(); return cv::Size();} +bool cv::gpu::SCascade::load(const FileNode&) { throw_nogpu(); return false;} + +void cv::gpu::SCascade::detect(InputArray, InputArray, OutputArray, Stream&) const { throw_nogpu(); } +void cv::gpu::SCascade::detect(InputArray, InputArray, OutputArray, const int, Stream&) const { throw_nogpu(); } + +void cv::gpu::SCascade::genRoi(InputArray, OutputArray) const { throw_nogpu(); } + +void cv::gpu::SCascade::read(const FileNode& fn) { Algorithm::read(fn); } #else @@ -92,7 +89,7 @@ namespace imgproc { }}} -struct cv::gpu::SoftCascade::Filds +struct cv::gpu::SCascade::Fields { struct CascadeIntrinsics { @@ -126,7 +123,7 @@ struct cv::gpu::SoftCascade::Filds } }; - static Filds* parseCascade(const FileNode &root, const float mins, const float maxs) + static Fields* parseCascade(const FileNode &root, const float mins, const float maxs) { static const char *const SC_STAGE_TYPE = "stageType"; static const char *const SC_BOOST = "BOOST"; @@ -312,13 +309,13 @@ struct cv::gpu::SoftCascade::Filds cv::Mat hlevels(1, vlevels.size() * sizeof(Level), CV_8UC1, (uchar*)&(vlevels[0]) ); CV_Assert(!hlevels.empty()); - Filds* filds = new Filds(mins, maxs, origWidth, origHeight, shrinkage, downscales, + Fields* fields = new Fields(mins, maxs, origWidth, origHeight, shrinkage, downscales, hoctaves, hstages, hnodes, hleaves, hlevels); - return filds; + return fields; } - Filds( const float mins, const float maxs, const int ow, const int oh, const int shr, const int ds, + Fields( const float mins, const float maxs, const int ow, const int oh, const int shr, const int ds, cv::Mat hoctaves, cv::Mat hstages, cv::Mat hnodes, cv::Mat hleaves, cv::Mat hlevels) : minScale(mins), maxScale(maxs), origObjWidth(ow), origObjHeight(oh), shrinkage(shr), downscales(ds) { @@ -332,7 +329,7 @@ struct cv::gpu::SoftCascade::Filds hogluv.create((FRAME_HEIGHT / shr) * HOG_LUV_BINS + 1, FRAME_WIDTH / shr + 1, CV_32SC1); hogluv.setTo(cv::Scalar::all(0)); - detCounter.create(1,1, CV_32SC1); + detCounter.create(sizeof(Detection) / sizeof(int),1, CV_32SC1); octaves.upload(hoctaves); stages.upload(hstages); @@ -344,20 +341,21 @@ struct cv::gpu::SoftCascade::Filds } - void detect(int scale, const cv::gpu::GpuMat& roi, cv::gpu::GpuMat& objects, cudaStream_t stream) const + void detect(int scale, const cv::gpu::GpuMat& roi, const cv::gpu::GpuMat& count, cv::gpu::GpuMat& objects, cudaStream_t stream) const { - cudaMemset(detCounter.data, 0, detCounter.step * detCounter.rows * sizeof(int)); - invoker(roi, hogluv, objects, detCounter, downscales, scale); + cudaMemset(count.data, 0, sizeof(Detection)); + cudaSafeCall( cudaGetLastError()); + invoker(roi, hogluv, objects, count, downscales, scale); } void preprocess(const cv::gpu::GpuMat& colored) { cudaMemset(plane.data, 0, plane.step * plane.rows); - static const int fw = Filds::FRAME_WIDTH; - static const int fh = Filds::FRAME_HEIGHT; + static const int fw = Fields::FRAME_WIDTH; + static const int fh = Fields::FRAME_HEIGHT; - GpuMat gray(plane, cv::Rect(0, fh * Filds::HOG_LUV_BINS, fw, fh)); + GpuMat gray(plane, cv::Rect(0, fh * Fields::HOG_LUV_BINS, fw, fh)); cv::gpu::cvtColor(colored, gray, CV_BGR2GRAY); createHogBins(gray); @@ -390,8 +388,8 @@ private: void createHogBins(const cv::gpu::GpuMat& gray) { - static const int fw = Filds::FRAME_WIDTH; - static const int fh = Filds::FRAME_HEIGHT; + static const int fw = Fields::FRAME_WIDTH; + static const int fh = Fields::FRAME_HEIGHT; GpuMat dfdx(fplane, cv::Rect(0, 0, fw, fh)); GpuMat dfdy(fplane, cv::Rect(0, fh, fw, fh)); @@ -413,21 +411,21 @@ private: cv::gpu::multiply(ang, cv::Scalar::all(1.f / 60.f), nang); //create uchar magnitude - GpuMat cmag(plane, cv::Rect(0, fh * Filds::HOG_BINS, fw, fh)); + GpuMat cmag(plane, cv::Rect(0, fh * Fields::HOG_BINS, fw, fh)); nmag.convertTo(cmag, CV_8UC1); - device::icf::fillBins(plane, nang, fw, fh, Filds::HOG_BINS); + device::icf::fillBins(plane, nang, fw, fh, Fields::HOG_BINS); } void createLuvBins(const cv::gpu::GpuMat& colored) { - static const int fw = Filds::FRAME_WIDTH; - static const int fh = Filds::FRAME_HEIGHT; + static const int fw = Fields::FRAME_WIDTH; + static const int fh = Fields::FRAME_HEIGHT; cv::gpu::cvtColor(colored, luv, CV_BGR2Luv); std::vector splited; - for(int i = 0; i < Filds::LUV_BINS; ++i) + for(int i = 0; i < Fields::LUV_BINS; ++i) { splited.push_back(GpuMat(plane, cv::Rect(0, fh * (7 + i), fw, fh))); } @@ -437,10 +435,10 @@ private: void integrate() { - int fw = Filds::FRAME_WIDTH; - int fh = Filds::FRAME_HEIGHT; + int fw = Fields::FRAME_WIDTH; + int fh = Fields::FRAME_HEIGHT; - GpuMat channels(plane, cv::Rect(0, 0, fw, fh * Filds::HOG_LUV_BINS)); + GpuMat channels(plane, cv::Rect(0, 0, fw, fh * Fields::HOG_LUV_BINS)); cv::gpu::resize(channels, shrunk, cv::Size(), 0.25, 0.25, CV_INTER_AREA); device::imgproc::shfl_integral_gpu_buffered(shrunk, integralBuffer, hogluv, 12, 0); } @@ -500,45 +498,33 @@ public: }; }; -cv::gpu::SoftCascade::SoftCascade() : filds(0) {} +cv::gpu::SCascade::SCascade(const double mins, const double maxs, const int sc, const int rjf) +: fields(0), minScale(mins), maxScale(maxs), scales(sc), rejfactor(rjf) {} -cv::gpu::SoftCascade::SoftCascade( const string& filename, const float minScale, const float maxScale) : filds(0) +cv::gpu::SCascade::~SCascade() { delete fields; } + +bool cv::gpu::SCascade::load(const FileNode& fn) { - load(filename, minScale, maxScale); + if (fields) delete fields; + fields = Fields::parseCascade(fn, minScale, maxScale); + return fields != 0; } -cv::gpu::SoftCascade::~SoftCascade() -{ - delete filds; -} - -bool cv::gpu::SoftCascade::load( const string& filename, const float minScale, const float maxScale) -{ - if (filds) delete filds; - - cv::FileStorage fs(filename, FileStorage::READ); - if (!fs.isOpened()) return false; - - filds = Filds::parseCascade(fs.getFirstTopLevelNode(), minScale, maxScale); - return filds != 0; -} - -void cv::gpu::SoftCascade::detectMultiScale(const GpuMat& colored, const GpuMat& rois, - GpuMat& objects, const int /*rejectfactor*/, int specificScale) const +void cv::gpu::SCascade::detect(InputArray image, InputArray _rois, OutputArray _objects, Stream& s) const { + const GpuMat colored = image.getGpuMat(); // only color images are supperted CV_Assert(colored.type() == CV_8UC3 || colored.type() == CV_32SC1); // we guess user knows about shrincage - CV_Assert((rois.size().width == getRoiSize().height) && (rois.type() == CV_8UC1)); + // CV_Assert((rois.size().width == getRoiSize().height) && (rois.type() == CV_8UC1)); - - Filds& flds = *filds; + Fields& flds = *fields; if (colored.type() == CV_8UC3) { // only this window size allowed - CV_Assert(colored.cols == Filds::FRAME_WIDTH && colored.rows == Filds::FRAME_HEIGHT); + CV_Assert(colored.cols == Fields::FRAME_WIDTH && colored.rows == Fields::FRAME_HEIGHT); flds.preprocess(colored); } else @@ -546,25 +532,60 @@ void cv::gpu::SoftCascade::detectMultiScale(const GpuMat& colored, const GpuMat& colored.copyTo(flds.hogluv); } - flds.detect(specificScale, rois, objects, 0); + GpuMat rois = _rois.getGpuMat(), objects = _objects.getGpuMat(); - cv::Mat out(flds.detCounter); - int ndetections = *(out.ptr(0)); + GpuMat tmp = GpuMat(objects, cv::Rect(0, 0, sizeof(Detection), 1)); + objects = GpuMat(objects, cv::Rect( sizeof(Detection), 0, objects.cols - sizeof(Detection), 1)); + cudaStream_t stream = StreamAccessor::getStream(s); - if (! ndetections) - objects = GpuMat(); + flds.detect(-1, rois, tmp, objects, stream); +} + +void cv::gpu::SCascade::detect(InputArray image, InputArray _rois, OutputArray _objects, const int level, Stream& s) const +{ + const GpuMat colored = image.getGpuMat(); + // only color images are supperted + CV_Assert(colored.type() == CV_8UC3 || colored.type() == CV_32SC1); + + // we guess user knows about shrincage + // CV_Assert((rois.size().width == getRoiSize().height) && (rois.type() == CV_8UC1)); + + Fields& flds = *fields; + + if (colored.type() == CV_8UC3) + { + // only this window size allowed + CV_Assert(colored.cols == Fields::FRAME_WIDTH && colored.rows == Fields::FRAME_HEIGHT); + flds.preprocess(colored); + } else - objects = GpuMat(objects, cv::Rect(0, 0, ndetections * sizeof(Detection), 1)); + { + colored.copyTo(flds.hogluv); + } + + GpuMat rois = _rois.getGpuMat(), objects = _objects.getGpuMat(); + + GpuMat tmp = GpuMat(objects, cv::Rect(0, 0, sizeof(Detection), 1)); + objects = GpuMat(objects, cv::Rect( sizeof(Detection), 0, objects.cols - sizeof(Detection), 1)); + cudaStream_t stream = StreamAccessor::getStream(s); + + flds.detect(level, rois, tmp, objects, stream); } -void cv::gpu::SoftCascade::detectMultiScale(const GpuMat&, const GpuMat&, GpuMat&, int, GpuMat&, Stream) const +void cv::gpu::SCascade::genRoi(InputArray _roi, OutputArray _mask) const { - // cudaStream_t stream = StreamAccessor::getStream(s); + const GpuMat roi = _roi.getGpuMat(); + _mask.create( roi.cols / 4, roi.rows / 4, roi.type() ); + GpuMat mask = _mask.getGpuMat(); + cv::gpu::GpuMat tmp; + + cv::gpu::resize(roi, tmp, cv::Size(), 0.25, 0.25, CV_INTER_AREA); + cv::gpu::transpose(tmp, mask); } -cv::Size cv::gpu::SoftCascade::getRoiSize() const +void cv::gpu::SCascade::read(const FileNode& fn) { - return cv::Size(Filds::FRAME_WIDTH / (*filds).shrinkage, Filds::FRAME_HEIGHT / (*filds).shrinkage); + Algorithm::read(fn); } #endif \ No newline at end of file diff --git a/modules/gpu/test/test_softcascade.cpp b/modules/gpu/test/test_softcascade.cpp index 1146b062b..f26c44f0e 100644 --- a/modules/gpu/test/test_softcascade.cpp +++ b/modules/gpu/test/test_softcascade.cpp @@ -70,23 +70,23 @@ using cv::gpu::GpuMat; namespace { - typedef cv::gpu::SoftCascade::Detection Detection; + typedef cv::gpu::SCascade::Detection Detection; static cv::Rect getFromTable(int idx) { static const cv::Rect rois[] = { - cv::Rect( 65, 20, 35, 80), - cv::Rect( 95, 35, 45, 40), - cv::Rect( 45, 35, 45, 40), - cv::Rect( 25, 27, 50, 45), - cv::Rect(100, 50, 45, 40), + cv::Rect( 65 * 4, 20 * 4, 35 * 4, 80 * 4), + cv::Rect( 95 * 4, 35 * 4, 45 * 4, 40 * 4), + cv::Rect( 45 * 4, 35 * 4, 45 * 4, 40 * 4), + cv::Rect( 25 * 4, 27 * 4, 50 * 4, 45 * 4), + cv::Rect(100 * 4, 50 * 4, 45 * 4, 40 * 4), - cv::Rect( 60, 30, 45, 40), - cv::Rect( 40, 55, 50, 40), - cv::Rect( 48, 37, 72, 80), - cv::Rect( 48, 32, 85, 58), - cv::Rect( 48, 0, 32, 27) + cv::Rect( 60 * 4, 30 * 4, 45 * 4, 40 * 4), + cv::Rect( 40 * 4, 55 * 4, 50 * 4, 40 * 4), + cv::Rect( 48 * 4, 37 * 4, 72 * 4, 80 * 4), + cv::Rect( 48 * 4, 32 * 4, 85 * 4, 58 * 4), + cv::Rect( 48 * 4, 0 * 4, 32 * 4, 27 * 4) }; return rois[idx]; @@ -140,11 +140,11 @@ namespace { } } -typedef ::testing::TestWithParam > SoftCascadeTestRoi; -GPU_TEST_P(SoftCascadeTestRoi, detect, +typedef ::testing::TestWithParam > SCascadeTestRoi; +GPU_TEST_P(SCascadeTestRoi, detect, testing::Combine( ALL_DEVICES, - testing::Values(std::string("../cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), + testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("../cv/cascadeandhog/bahnhof/image_00000000_0.png")), testing::Range(0, 5))) { @@ -152,10 +152,14 @@ GPU_TEST_P(SoftCascadeTestRoi, detect, cv::Mat coloredCpu = cv::imread(cvtest::TS::ptr()->get_data_path() + GET_PARAM(2)); ASSERT_FALSE(coloredCpu.empty()); - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(cvtest::TS::ptr()->get_data_path() + GET_PARAM(1))); + cv::gpu::SCascade cascade; - GpuMat colored(coloredCpu), objectBoxes(1, 16384, CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1), trois; + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(1)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); + + GpuMat colored(coloredCpu), objectBoxes(1, 16384, CV_8UC1), rois(colored.size(), CV_8UC1), trois; rois.setTo(0); int nroi = GET_PARAM(3); @@ -166,21 +170,21 @@ GPU_TEST_P(SoftCascadeTestRoi, detect, cv::Rect r = getFromTable(rng(10)); GpuMat sub(rois, r); sub.setTo(1); - r.x *= 4; r.y *= 4; r.width *= 4; r.height *= 4; cv::rectangle(result, r, cv::Scalar(0, 0, 255, 255), 1); } - cv::gpu::transpose(rois, trois); - - cascade.detectMultiScale(colored, trois, objectBoxes); + cascade.genRoi(rois, trois); + cascade.detect(colored, trois, objectBoxes); cv::Mat dt(objectBoxes); - typedef cv::gpu::SoftCascade::Detection Detection; + typedef cv::gpu::SCascade::Detection Detection; - Detection* dts = (Detection*)dt.data; + Detection* dts = ((Detection*)dt.data) + 1; + int* count = dt.ptr(0); - printTotal(std::cout, dt.cols); - for (int i = 0; i < (int)(dt.cols / sizeof(Detection)); ++i) + printTotal(std::cout, *count); + + for (int i = 0; i < *count; ++i) { Detection d = dts[i]; print(std::cout, d); @@ -188,43 +192,49 @@ GPU_TEST_P(SoftCascadeTestRoi, detect, } SHOW(result); + } -typedef ::testing::TestWithParam > SoftCascadeTestLevel; -GPU_TEST_P(SoftCascadeTestLevel, detect, +typedef ::testing::TestWithParam > SCascadeTestLevel; +GPU_TEST_P(SCascadeTestLevel, detect, testing::Combine( ALL_DEVICES, - testing::Values(std::string("../cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), + testing::Values(std::string("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml")), testing::Values(std::string("../cv/cascadeandhog/bahnhof/image_00000000_0.png")), testing::Range(0, 47) )) { cv::gpu::setDevice(GET_PARAM(0).deviceID()); - std::string xml = cvtest::TS::ptr()->get_data_path() + GET_PARAM(1); - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(xml)); + cv::gpu::SCascade cascade; + + cv::FileStorage fs(perf::TestBase::getDataPath(GET_PARAM(1)), cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); cv::Mat coloredCpu = cv::imread(cvtest::TS::ptr()->get_data_path() + GET_PARAM(2)); ASSERT_FALSE(coloredCpu.empty()); - typedef cv::gpu::SoftCascade::Detection Detection; - GpuMat colored(coloredCpu), objectBoxes(1, 100 * sizeof(Detection), CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1); + typedef cv::gpu::SCascade::Detection Detection; + GpuMat colored(coloredCpu), objectBoxes(1, 100 * sizeof(Detection), CV_8UC1), rois(colored.size(), CV_8UC1); rois.setTo(1); cv::gpu::GpuMat trois; - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); int level = GET_PARAM(3); - cascade.detectMultiScale(colored, trois, objectBoxes, 1, level); + cascade.detect(colored, trois, objectBoxes, level); cv::Mat dt(objectBoxes); - Detection* dts = (Detection*)dt.data; + Detection* dts = ((Detection*)dt.data) + 1; + int* count = dt.ptr(0); + cv::Mat result(coloredCpu); - printTotal(std::cout, dt.cols); - for (int i = 0; i < (int)(dt.cols / sizeof(Detection)); ++i) + printTotal(std::cout, *count); + for (int i = 0; i < *count; ++i) { Detection d = dts[i]; print(std::cout, d); @@ -235,76 +245,89 @@ GPU_TEST_P(SoftCascadeTestLevel, detect, SHOW(result); } -TEST(SoftCascadeTest, readCascade) +TEST(SCascadeTest, readCascade) { std::string xml = cvtest::TS::ptr()->get_data_path() + "../cv/cascadeandhog/icf-template.xml"; - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(xml)); + cv::gpu::SCascade cascade; + + cv::FileStorage fs(xml, cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); } -typedef ::testing::TestWithParam SoftCascadeTestAll; -GPU_TEST_P(SoftCascadeTestAll, detect, +typedef ::testing::TestWithParam SCascadeTestAll; +GPU_TEST_P(SCascadeTestAll, detect, ALL_DEVICES ) { cv::gpu::setDevice(GetParam().deviceID()); std::string xml = cvtest::TS::ptr()->get_data_path() + "../cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml"; - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(xml)); + cv::gpu::SCascade cascade; + + cv::FileStorage fs(xml, cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); cv::Mat coloredCpu = cv::imread(cvtest::TS::ptr()->get_data_path() + "../cv/cascadeandhog/bahnhof/image_00000000_0.png"); ASSERT_FALSE(coloredCpu.empty()); - GpuMat colored(coloredCpu), objectBoxes(1, 100000, CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1); + GpuMat colored(coloredCpu), objectBoxes(1, 100000, CV_8UC1), rois(colored.size(), CV_8UC1); rois.setTo(0); GpuMat sub(rois, cv::Rect(rois.cols / 4, rois.rows / 4,rois.cols / 2, rois.rows / 2)); sub.setTo(cv::Scalar::all(1)); cv::gpu::GpuMat trois; - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cascade.detectMultiScale(colored, trois, objectBoxes); + cascade.detect(colored, trois, objectBoxes); - typedef cv::gpu::SoftCascade::Detection Detection; + typedef cv::gpu::SCascade::Detection Detection; cv::Mat detections(objectBoxes); - ASSERT_EQ(detections.cols / sizeof(Detection) ,3670U); + int a = *(detections.ptr(0)); + ASSERT_EQ(a ,2460); } -//ToDo: fix me -GPU_TEST_P(SoftCascadeTestAll, detectOnIntegral, +GPU_TEST_P(SCascadeTestAll, detectOnIntegral, ALL_DEVICES ) { cv::gpu::setDevice(GetParam().deviceID()); std::string xml = cvtest::TS::ptr()->get_data_path() + "../cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml"; - cv::gpu::SoftCascade cascade; - ASSERT_TRUE(cascade.load(xml)); + cv::gpu::SCascade cascade; + + cv::FileStorage fs(xml, cv::FileStorage::READ); + ASSERT_TRUE(fs.isOpened()); + + ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); std::string intPath = cvtest::TS::ptr()->get_data_path() + "../cv/cascadeandhog/integrals.xml"; - cv::FileStorage fs(intPath, cv::FileStorage::READ); - ASSERT_TRUE(fs.isOpened()); + cv::FileStorage fsi(intPath, cv::FileStorage::READ); + ASSERT_TRUE(fsi.isOpened()); GpuMat hogluv(121 * 10, 161, CV_32SC1); for (int i = 0; i < 10; ++i) { cv::Mat channel; - fs[std::string("channel") + itoa(i)] >> channel; + fsi[std::string("channel") + itoa(i)] >> channel; GpuMat gchannel(hogluv, cv::Rect(0, 121 * i, 161, 121)); gchannel.upload(channel); } - GpuMat objectBoxes(1, 100000, CV_8UC1), rois(cascade.getRoiSize(), CV_8UC1); + GpuMat objectBoxes(1, 100000, CV_8UC1), rois(cv::Size(640, 480), CV_8UC1); rois.setTo(1); cv::gpu::GpuMat trois; - cv::gpu::transpose(rois, trois); + cascade.genRoi(rois, trois); - cascade.detectMultiScale(hogluv, trois, objectBoxes); + cascade.detect(hogluv, trois, objectBoxes); - typedef cv::gpu::SoftCascade::Detection Detection; + typedef cv::gpu::SCascade::Detection Detection; cv::Mat detections(objectBoxes); + int a = *(detections.ptr(0)); - ASSERT_EQ(detections.cols / sizeof(Detection) ,2042U); + ASSERT_EQ( a ,1024); } #endif \ No newline at end of file