Commit 07d19c2c authored by Anton Obukhov's avatar Anton Obukhov

[~] Refactored, cleaned up, and consolidated the code of GPU examples…

[~] Refactored, cleaned up, and consolidated the code of GPU examples (cascadeclassifier and cascadeclassifier_nvidia_api)
parent daac469b
...@@ -67,9 +67,15 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl ...@@ -67,9 +67,15 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
{ {
ncvSetDebugOutputHandler(NCVDebugOutputHandler); ncvSetDebugOutputHandler(NCVDebugOutputHandler);
if (ncvStat != load(filename)) if (ncvStat != load(filename))
{
CV_Error(CV_GpuApiCallError, "Error in GPU cacade load"); CV_Error(CV_GpuApiCallError, "Error in GPU cacade load");
} }
NCVStatus process(const GpuMat& src, GpuMat& objects, float scaleStep, int minNeighbors, bool findLargestObject, bool visualizeInPlace, NcvSize32u ncvMinSize, /*out*/unsigned int& numDetections) }
NCVStatus process(const GpuMat& src, GpuMat& objects, float scaleStep, int minNeighbors,
bool findLargestObject, bool visualizeInPlace, NcvSize32u ncvMinSize,
/*out*/unsigned int& numDetections)
{ {
calculateMemReqsAndAllocate(src.size()); calculateMemReqsAndAllocate(src.size());
...@@ -84,12 +90,6 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl ...@@ -84,12 +90,6 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
NCVMatrixReuse<Ncv8u> d_src(src_seg, devProp.textureAlignment, src.cols, src.rows, src.step, true); NCVMatrixReuse<Ncv8u> d_src(src_seg, devProp.textureAlignment, src.cols, src.rows, src.step, true);
ncvAssertReturn(d_src.isMemReused(), NCV_ALLOCATOR_BAD_REUSE); ncvAssertReturn(d_src.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
//NCVMatrixAlloc<Ncv8u> d_src(*gpuAllocator, src.cols, src.rows);
//ncvAssertReturn(d_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
//NCVMatrixAlloc<Ncv8u> h_src(*cpuAllocator, src.cols, src.rows);
//ncvAssertReturn(h_src.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
CV_Assert(objects.rows == 1); CV_Assert(objects.rows == 1);
NCVMemPtr objects_beg; NCVMemPtr objects_beg;
...@@ -101,8 +101,6 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl ...@@ -101,8 +101,6 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
objects_seg.size = objects.step * objects.rows; objects_seg.size = objects.step * objects.rows;
NCVVectorReuse<NcvRect32u> d_rects(objects_seg, objects.cols); NCVVectorReuse<NcvRect32u> d_rects(objects_seg, objects.cols);
ncvAssertReturn(d_rects.isMemReused(), NCV_ALLOCATOR_BAD_REUSE); ncvAssertReturn(d_rects.isMemReused(), NCV_ALLOCATOR_BAD_REUSE);
//NCVVectorAlloc<NcvRect32u> d_rects(*gpuAllocator, 100);
//ncvAssertReturn(d_rects.isMemAllocated(), NCV_ALLOCATOR_BAD_ALLOC);
NcvSize32u roi; NcvSize32u roi;
roi.width = d_src.width(); roi.width = d_src.width();
...@@ -125,14 +123,18 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl ...@@ -125,14 +123,18 @@ struct cv::gpu::CascadeClassifier_GPU::CascadeClassifierImpl
return NCV_SUCCESS; return NCV_SUCCESS;
} }
////
NcvSize32u getClassifierSize() const { return haar.ClassifierSize; } NcvSize32u getClassifierSize() const { return haar.ClassifierSize; }
cv::Size getClassifierCvSize() const { return cv::Size(haar.ClassifierSize.width, haar.ClassifierSize.height); } cv::Size getClassifierCvSize() const { return cv::Size(haar.ClassifierSize.width, haar.ClassifierSize.height); }
private: private:
static void NCVDebugOutputHandler(const char* msg) { CV_Error(CV_GpuApiCallError, msg); } static void NCVDebugOutputHandler(const char* msg) { CV_Error(CV_GpuApiCallError, msg); }
NCVStatus load(const string& classifierFile) NCVStatus load(const string& classifierFile)
{ {
int devId = cv::gpu::getDevice(); int devId = cv::gpu::getDevice();
...@@ -177,12 +179,14 @@ private: ...@@ -177,12 +179,14 @@ private:
return NCV_SUCCESS; return NCV_SUCCESS;
} }
////
NCVStatus calculateMemReqsAndAllocate(const Size& frameSize) NCVStatus calculateMemReqsAndAllocate(const Size& frameSize)
{ {
if (lastAllocatedFrameSize == frameSize) if (lastAllocatedFrameSize == frameSize)
{
return NCV_SUCCESS; return NCV_SUCCESS;
}
// Calculate memory requirements and create real allocators // Calculate memory requirements and create real allocators
NCVMemStackAllocator gpuCounter(devProp.textureAlignment); NCVMemStackAllocator gpuCounter(devProp.textureAlignment);
...@@ -217,7 +221,7 @@ private: ...@@ -217,7 +221,7 @@ private:
ncvAssertPrintReturn(cpuAllocator->isInitialized(), "Error creating CPU memory allocator", NCV_CUDA_ERROR); ncvAssertPrintReturn(cpuAllocator->isInitialized(), "Error creating CPU memory allocator", NCV_CUDA_ERROR);
return NCV_SUCCESS; return NCV_SUCCESS;
} }
////
cudaDeviceProp devProp; cudaDeviceProp devProp;
NCVStatus ncvStat; NCVStatus ncvStat;
...@@ -242,14 +246,13 @@ private: ...@@ -242,14 +246,13 @@ private:
}; };
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU() : findLargestObject(false), visualizeInPlace(false), impl(0) {} cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU() : findLargestObject(false), visualizeInPlace(false), impl(0) {}
cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU(const string& filename) : findLargestObject(false), visualizeInPlace(false), impl(0) { load(filename); } cv::gpu::CascadeClassifier_GPU::CascadeClassifier_GPU(const string& filename) : findLargestObject(false), visualizeInPlace(false), impl(0) { load(filename); }
cv::gpu::CascadeClassifier_GPU::~CascadeClassifier_GPU() { release(); } cv::gpu::CascadeClassifier_GPU::~CascadeClassifier_GPU() { release(); }
bool cv::gpu::CascadeClassifier_GPU::empty() const { return impl == 0; } bool cv::gpu::CascadeClassifier_GPU::empty() const { return impl == 0; }
void cv::gpu::CascadeClassifier_GPU::release() { if (impl) { delete impl; impl = 0; } } void cv::gpu::CascadeClassifier_GPU::release() { if (impl) { delete impl; impl = 0; } }
bool cv::gpu::CascadeClassifier_GPU::load(const string& filename) bool cv::gpu::CascadeClassifier_GPU::load(const string& filename)
{ {
release(); release();
...@@ -257,11 +260,13 @@ bool cv::gpu::CascadeClassifier_GPU::load(const string& filename) ...@@ -257,11 +260,13 @@ bool cv::gpu::CascadeClassifier_GPU::load(const string& filename)
return !this->empty(); return !this->empty();
} }
Size cv::gpu::CascadeClassifier_GPU::getClassifierSize() const Size cv::gpu::CascadeClassifier_GPU::getClassifierSize() const
{ {
return this->empty() ? Size() : impl->getClassifierCvSize(); return this->empty() ? Size() : impl->getClassifierCvSize();
} }
int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor, int minNeighbors, Size minSize) int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMat& objectsBuf, double scaleFactor, int minNeighbors, Size minSize)
{ {
CV_Assert( scaleFactor > 1 && image.depth() == CV_8U); CV_Assert( scaleFactor > 1 && image.depth() == CV_8U);
...@@ -269,7 +274,9 @@ int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMa ...@@ -269,7 +274,9 @@ int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMa
const int defaultObjSearchNum = 100; const int defaultObjSearchNum = 100;
if (objectsBuf.empty()) if (objectsBuf.empty())
{
objectsBuf.create(1, defaultObjSearchNum, DataType<Rect>::type); objectsBuf.create(1, defaultObjSearchNum, DataType<Rect>::type);
}
NcvSize32u ncvMinSize = impl->getClassifierSize(); NcvSize32u ncvMinSize = impl->getClassifierSize();
...@@ -282,11 +289,14 @@ int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMa ...@@ -282,11 +289,14 @@ int cv::gpu::CascadeClassifier_GPU::detectMultiScale( const GpuMat& image, GpuMa
unsigned int numDetections; unsigned int numDetections;
NCVStatus ncvStat = impl->process(image, objectsBuf, (float)scaleFactor, minNeighbors, findLargestObject, visualizeInPlace, ncvMinSize, numDetections); NCVStatus ncvStat = impl->process(image, objectsBuf, (float)scaleFactor, minNeighbors, findLargestObject, visualizeInPlace, ncvMinSize, numDetections);
if (ncvStat != NCV_SUCCESS) if (ncvStat != NCV_SUCCESS)
{
CV_Error(CV_GpuApiCallError, "Error in face detectioln"); CV_Error(CV_GpuApiCallError, "Error in face detectioln");
}
return numDetections; return numDetections;
} }
struct RectConvert struct RectConvert
{ {
Rect operator()(const NcvRect32u& nr) const { return Rect(nr.x, nr.y, nr.width, nr.height); } Rect operator()(const NcvRect32u& nr) const { return Rect(nr.x, nr.y, nr.width, nr.height); }
...@@ -301,6 +311,7 @@ struct RectConvert ...@@ -301,6 +311,7 @@ struct RectConvert
} }
}; };
void groupRectangles(std::vector<NcvRect32u> &hypotheses, int groupThreshold, double eps, std::vector<Ncv32u> *weights) void groupRectangles(std::vector<NcvRect32u> &hypotheses, int groupThreshold, double eps, std::vector<Ncv32u> *weights)
{ {
vector<Rect> rects(hypotheses.size()); vector<Rect> rects(hypotheses.size());
...@@ -350,9 +361,9 @@ NCVStatus loadFromXML(const std::string &filename, ...@@ -350,9 +361,9 @@ NCVStatus loadFromXML(const std::string &filename,
Ptr<CvHaarClassifierCascade> oldCascade = (CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0); Ptr<CvHaarClassifierCascade> oldCascade = (CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0);
if (oldCascade.empty()) if (oldCascade.empty())
{
return NCV_HAAR_XML_LOADING_EXCEPTION; return NCV_HAAR_XML_LOADING_EXCEPTION;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
haar.ClassifierSize.width = oldCascade->orig_window_size.width; haar.ClassifierSize.width = oldCascade->orig_window_size.width;
haar.ClassifierSize.height = oldCascade->orig_window_size.height; haar.ClassifierSize.height = oldCascade->orig_window_size.height;
...@@ -466,8 +477,6 @@ NCVStatus loadFromXML(const std::string &filename, ...@@ -466,8 +477,6 @@ NCVStatus loadFromXML(const std::string &filename,
haarStages.push_back(curStage); haarStages.push_back(curStage);
} }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//fill in cascade stats //fill in cascade stats
haar.NumStages = haarStages.size(); haar.NumStages = haarStages.size();
haar.NumClassifierRootNodes = haarClassifierNodes.size(); haar.NumClassifierRootNodes = haarClassifierNodes.size();
...@@ -496,6 +505,7 @@ NCVStatus loadFromXML(const std::string &filename, ...@@ -496,6 +505,7 @@ NCVStatus loadFromXML(const std::string &filename,
} }
haarClassifierNodes[i].setRightNodeDesc(nodeRight); haarClassifierNodes[i].setRightNodeDesc(nodeRight);
} }
for (Ncv32u i=0; i<h_TmpClassifierNotRootNodes.size(); i++) for (Ncv32u i=0; i<h_TmpClassifierNotRootNodes.size(); i++)
{ {
HaarFeatureDescriptor32 featureDesc = h_TmpClassifierNotRootNodes[i].getFeatureDesc(); HaarFeatureDescriptor32 featureDesc = h_TmpClassifierNotRootNodes[i].getFeatureDesc();
...@@ -522,8 +532,6 @@ NCVStatus loadFromXML(const std::string &filename, ...@@ -522,8 +532,6 @@ NCVStatus loadFromXML(const std::string &filename,
return NCV_SUCCESS; return NCV_SUCCESS;
} }
////
#else /* loadFromXML implementation switch */ #else /* loadFromXML implementation switch */
#include "e:/devNPP-OpenCV/src/external/_rapidxml-1.13/rapidxml.hpp" #include "e:/devNPP-OpenCV/src/external/_rapidxml-1.13/rapidxml.hpp"
...@@ -793,5 +801,3 @@ NCVStatus loadFromXML(const std::string &filename, ...@@ -793,5 +801,3 @@ NCVStatus loadFromXML(const std::string &filename,
#endif /* loadFromXML implementation switch */ #endif /* loadFromXML implementation switch */
#endif /* HAVE_CUDA */ #endif /* HAVE_CUDA */
// WARNING: this sample is under construction! Use it on your own risk. // WARNING: this sample is under construction! Use it on your own risk.
#pragma warning(disable : 4100)
#include "cvconfig.h"
#include <iostream>
#include <iomanip>
#include <opencv2/contrib/contrib.hpp> #include <opencv2/contrib/contrib.hpp>
#include <opencv2/objdetect/objdetect.hpp> #include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/gpu/gpu.hpp> #include <opencv2/gpu/gpu.hpp>
#include <iostream>
#include <iomanip>
using namespace std; using namespace std;
using namespace cv; using namespace cv;
using namespace cv::gpu; using namespace cv::gpu;
#if !defined(HAVE_CUDA)
int main(int argc, const char **argv)
{
cout << "Please compile the library with CUDA support" << endl;
return -1;
}
#else
void help() void help()
{ {
cout << "Usage: ./cascadeclassifier <cascade_file> <image_or_video_or_cameraid>\n" cout << "Usage: ./cascadeclassifier <cascade_file> <image_or_video_or_cameraid>\n"
...@@ -21,14 +31,8 @@ void help() ...@@ -21,14 +31,8 @@ void help()
} }
void DetectAndDraw(Mat& img, CascadeClassifier_GPU& cascade); template<class T>
void convertAndResize(const T& src, T& gray, T& resized, double scale)
String cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
String nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
template<class T> void convertAndResize(const T& src, T& gray, T& resized, double scale)
{ {
if (src.channels() == 3) if (src.channels() == 3)
{ {
...@@ -54,15 +58,16 @@ template<class T> void convertAndResize(const T& src, T& gray, T& resized, doubl ...@@ -54,15 +58,16 @@ template<class T> void convertAndResize(const T& src, T& gray, T& resized, doubl
void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss) void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss)
{ {
int fontFace = FONT_HERSHEY_PLAIN; int fontFace = FONT_HERSHEY_DUPLEX;
double fontScale = 1.5; double fontScale = 0.8;
int fontThickness = 2; int fontThickness = 2;
Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0); Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
Point org; Point org;
org.x = 1; org.x = 1;
org.y = 3 * fontSize.height * (lineOffsY + 1) / 2; org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness); putText(img, ss.str(), org, fontFace, fontScale, CV_RGB(0,0,0), 5*fontThickness/2, 16);
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness, 16);
} }
...@@ -72,25 +77,26 @@ void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bF ...@@ -72,25 +77,26 @@ void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bF
Scalar fontColorNV = CV_RGB(118,185,0); Scalar fontColorNV = CV_RGB(118,185,0);
ostringstream ss; ostringstream ss;
ss << "FPS = " << setprecision(1) << fixed << fps;
matPrint(canvas, 0, fontColorRed, ss);
ss.str("");
ss << "[" << canvas.cols << "x" << canvas.rows << "], " << ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
(bGpu ? "GPU, " : "CPU, ") << (bGpu ? "GPU, " : "CPU, ") <<
(bLargestFace ? "OneFace, " : "MultiFace, ") << (bLargestFace ? "OneFace, " : "MultiFace, ") <<
(bFilter ? "Filter:ON, " : "Filter:OFF, ") << (bFilter ? "Filter:ON" : "Filter:OFF");
"FPS = " << setprecision(1) << fixed << fps; matPrint(canvas, 1, fontColorRed, ss);
matPrint(canvas, 0, fontColorRed, ss);
if (bHelp) if (bHelp)
{ {
matPrint(canvas, 1, fontColorNV, ostringstream("Space - switch GPU / CPU")); matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
matPrint(canvas, 2, fontColorNV, ostringstream("M - switch OneFace / MultiFace")); matPrint(canvas, 3, fontColorNV, ostringstream("M - switch OneFace / MultiFace"));
matPrint(canvas, 3, fontColorNV, ostringstream("F - toggle rectangles Filter (only in MultiFace)")); matPrint(canvas, 4, fontColorNV, ostringstream("F - toggle rectangles Filter"));
matPrint(canvas, 4, fontColorNV, ostringstream("H - toggle hotkeys help")); matPrint(canvas, 5, fontColorNV, ostringstream("H - toggle hotkeys help"));
matPrint(canvas, 5, fontColorNV, ostringstream("1/Q - increase/decrease scale")); matPrint(canvas, 6, fontColorNV, ostringstream("1/Q - increase/decrease scale"));
} }
else else
{ {
matPrint(canvas, 1, fontColorNV, ostringstream("H - toggle hotkeys help")); matPrint(canvas, 2, fontColorNV, ostringstream("H - toggle hotkeys help"));
} }
} }
...@@ -130,8 +136,10 @@ int main(int argc, const char *argv[]) ...@@ -130,8 +136,10 @@ int main(int argc, const char *argv[])
{ {
if (!capture.open(inputName)) if (!capture.open(inputName))
{ {
int camid = 0; int camid = -1;
sscanf(inputName.c_str(), "%d", &camid); istringstream iss(inputName);
iss >> camid;
if (!capture.open(camid)) if (!capture.open(camid))
{ {
cout << "Can't open source" << endl; cout << "Can't open source" << endl;
...@@ -180,26 +188,28 @@ int main(int argc, const char *argv[]) ...@@ -180,26 +188,28 @@ int main(int argc, const char *argv[])
cascade_gpu.visualizeInPlace = true; cascade_gpu.visualizeInPlace = true;
cascade_gpu.findLargestObject = findLargestObject; cascade_gpu.findLargestObject = findLargestObject;
detections_num = cascade_gpu.detectMultiScale(resized_gpu, facesBuf_gpu, 1.2, filterRects ? 4 : 0); detections_num = cascade_gpu.detectMultiScale(resized_gpu, facesBuf_gpu, 1.2,
(filterRects || findLargestObject) ? 4 : 0);
facesBuf_gpu.colRange(0, detections_num).download(faces_downloaded); facesBuf_gpu.colRange(0, detections_num).download(faces_downloaded);
} }
else else
{ {
Size minSize = cascade_gpu.getClassifierSize(); Size minSize = cascade_gpu.getClassifierSize();
cascade_cpu.detectMultiScale(resized_cpu, facesBuf_cpu, 1.2, filterRects ? 4 : 0, (findLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0) | CV_HAAR_SCALE_IMAGE, minSize); cascade_cpu.detectMultiScale(resized_cpu, facesBuf_cpu, 1.2,
(filterRects || findLargestObject) ? 4 : 0,
(findLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0)
| CV_HAAR_SCALE_IMAGE,
minSize);
detections_num = (int)facesBuf_cpu.size(); detections_num = (int)facesBuf_cpu.size();
} }
if (!useGPU) if (!useGPU && detections_num)
{
if (detections_num)
{ {
for (int i = 0; i < detections_num; ++i) for (int i = 0; i < detections_num; ++i)
{ {
rectangle(resized_cpu, facesBuf_cpu[i], Scalar(255)); rectangle(resized_cpu, facesBuf_cpu[i], Scalar(255));
} }
} }
}
if (useGPU) if (useGPU)
{ {
...@@ -265,3 +275,5 @@ int main(int argc, const char *argv[]) ...@@ -265,3 +275,5 @@ int main(int argc, const char *argv[])
return 0; return 0;
} }
#endif //!defined(HAVE_CUDA)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment