From fad96b95adafc7139c0e279992e9367293e1b330 Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 24 May 2013 15:52:33 +0800 Subject: [PATCH] add results verification to facedetect and hog samples --- samples/ocl/facedetect.cpp | 290 ++++++++++++++++++++++++++------------------- samples/ocl/hog.cpp | 64 +++++++++- 2 files changed, 229 insertions(+), 125 deletions(-) diff --git a/samples/ocl/facedetect.cpp b/samples/ocl/facedetect.cpp index ec79339..684c2d9 100644 --- a/samples/ocl/facedetect.cpp +++ b/samples/ocl/facedetect.cpp @@ -1,5 +1,3 @@ -//This sample is inherited from facedetect.cpp in smaple/c - #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" @@ -9,78 +7,84 @@ using namespace std; using namespace cv; +#define LOOP_NUM 10 + +const static Scalar colors[] = { CV_RGB(0,0,255), + CV_RGB(0,128,255), + CV_RGB(0,255,255), + CV_RGB(0,255,0), + CV_RGB(255,128,0), + CV_RGB(255,255,0), + CV_RGB(255,0,0), + CV_RGB(255,0,255)} ; -static void help() +int64 work_begin = 0; +int64 work_end = 0; + +static void workBegin() +{ + work_begin = getTickCount(); +} +static void workEnd() { - cout << "\nThis program demonstrates the cascade recognizer.\n" - "This classifier can recognize many ~rigid objects, it's most known use is for faces.\n" - "Usage:\n" - "./facedetect [--cascade= this is the primary trained classifier such as frontal face]\n" - " [--scale=\n" - " [filename|camera_index]\n\n" - "see facedetect.cmd for one call:\n" - "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --scale=1.3 \n" - "Hit any key to quit.\n" - "Using OpenCV version " << CV_VERSION << "\n" << endl; + work_end += (getTickCount() - work_begin); } -struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } }; -void detectAndDraw( Mat& img, - cv::ocl::OclCascadeClassifier& cascade, CascadeClassifier& nestedCascade, - double scale); +static double getTime(){ + return work_end /((double)cvGetTickFrequency() * 1000.); +} + +void detect( Mat& img, vector& faces, + cv::ocl::OclCascadeClassifierBuf& cascade, + double scale, bool calTime); -String cascadeName = "../../../data/haarcascades/haarcascade_frontalface_alt.xml"; +void detectCPU( Mat& img, vector& faces, + CascadeClassifier& cascade, + double scale, bool calTime); + +void Draw(Mat& img, vector& faces, double scale); + +// This function test if gpu_rst matches cpu_rst. +// If the two vectors are not equal, it will return the difference in vector size +// Else if will return (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) +double checkRectSimilarity(Size sz, std::vector& cpu_rst, std::vector& gpu_rst); int main( int argc, const char** argv ) { - CvCapture* capture = 0; - Mat frame, frameCopy, image; - const String scaleOpt = "--scale="; - size_t scaleOptLen = scaleOpt.length(); - const String cascadeOpt = "--cascade="; - size_t cascadeOptLen = cascadeOpt.length(); - String inputName; - - help(); - cv::ocl::OclCascadeClassifier cascade; - CascadeClassifier nestedCascade; - double scale = 1; - - for( int i = 1; i < argc; i++ ) + const char* keys = + "{ h | help | false | print help message }" + "{ i | input | | specify input image }" + "{ t | template | ../../../data/haarcascades/haarcascade_frontalface_alt.xml | specify template file }" + "{ c | scale | 1.0 | scale image }" + "{ s | use_cpu | false | use cpu or gpu to process the image }"; + + CommandLineParser cmd(argc, argv, keys); + if (cmd.get("help")) { - cout << "Processing " << i << " " << argv[i] << endl; - if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 ) - { - cascadeName.assign( argv[i] + cascadeOptLen ); - cout << " from which we have cascadeName= " << cascadeName << endl; - } - else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 ) - { - if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 ) - scale = 1; - cout << " from which we read scale = " << scale << endl; - } - else if( argv[i][0] == '-' ) - { - cerr << "WARNING: Unknown option %s" << argv[i] << endl; - } - else - inputName.assign( argv[i] ); + cout << "Avaible options:" << endl; + cmd.printParams(); + return 0; } + CvCapture* capture = 0; + Mat frame, frameCopy, image; - if( !cascade.load( cascadeName ) ) + bool useCPU = cmd.get("s"); + string inputName = cmd.get("i"); + string cascadeName = cmd.get("t"); + double scale = cmd.get("c"); + cv::ocl::OclCascadeClassifierBuf cascade; + CascadeClassifier cpu_cascade; + + if( !cascade.load( cascadeName ) || !cpu_cascade.load(cascadeName) ) { cerr << "ERROR: Could not load classifier cascade" << endl; - cerr << "Usage: facedetect [--cascade=]\n" - " [--scale[=\n" - " [filename|camera_index]\n" << endl ; return -1; } - if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') ) + if( inputName.empty() ) { - capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' ); - int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ; - if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl; + capture = cvCaptureFromCAM(0); + if(!capture) + cout << "Capture from CAM 0 didn't work" << endl; } else if( inputName.size() ) { @@ -88,26 +92,30 @@ int main( int argc, const char** argv ) if( image.empty() ) { capture = cvCaptureFromAVI( inputName.c_str() ); - if(!capture) cout << "Capture from AVI didn't work" << endl; + if(!capture) + cout << "Capture from AVI didn't work" << endl; + return -1; } } else { image = imread( "lena.jpg", 1 ); - if(image.empty()) cout << "Couldn't read lena.jpg" << endl; + if(image.empty()) + cout << "Couldn't read lena.jpg" << endl; + return -1; } cvNamedWindow( "result", 1 ); std::vector oclinfo; int devnums = cv::ocl::getDevice(oclinfo); - if(devnums<1) + if( devnums < 1 ) { std::cout << "no device found\n"; return -1; } //if you want to use undefault device, set it here //setDevice(oclinfo[0]); - //setBinpath(CLBINPATH); + ocl::setBinpath("./"); if( capture ) { cout << "In capture ..." << endl; @@ -115,15 +123,20 @@ int main( int argc, const char** argv ) { IplImage* iplImg = cvQueryFrame( capture ); frame = iplImg; + vector faces; if( frame.empty() ) break; if( iplImg->origin == IPL_ORIGIN_TL ) frame.copyTo( frameCopy ); else flip( frame, frameCopy, 0 ); - - detectAndDraw( frameCopy, cascade, nestedCascade, scale ); - + if(useCPU){ + detectCPU(frameCopy, faces, cpu_cascade, scale, false); + } + else{ + detect(frameCopy, faces, cascade, scale, false); + } + Draw(frameCopy, faces, scale); if( waitKey( 10 ) >= 0 ) goto _cleanup_; } @@ -136,42 +149,34 @@ _cleanup_: else { cout << "In image read" << endl; - if( !image.empty() ) - { - detectAndDraw( image, cascade, nestedCascade, scale ); - waitKey(0); - } - else if( !inputName.empty() ) + vector faces; + vector ref_rst; + double accuracy = 0.; + for(int i = 0; i <= LOOP_NUM;i ++) { - /* assume it is a text file containing the - list of the image filenames to be processed - one per line */ - FILE* f = fopen( inputName.c_str(), "rt" ); - if( f ) + cout << "loop" << i << endl; + if(useCPU){ + detectCPU(image, faces, cpu_cascade, scale, i==0?false:true); + } + else{ + detect(image, faces, cascade, scale, i==0?false:true); + if(i == 0){ + detectCPU(image, ref_rst, cpu_cascade, scale, false); + accuracy = checkRectSimilarity(image.size(), ref_rst, faces); + } + } + if (i == LOOP_NUM) { - char buf[1000+1]; - while( fgets( buf, 1000, f ) ) - { - int len = (int)strlen(buf), c; - while( len > 0 && isspace(buf[len-1]) ) - len--; - buf[len] = '\0'; - cout << "file " << buf << endl; - image = imread( buf, 1 ); - if( !image.empty() ) - { - detectAndDraw( image, cascade, nestedCascade, scale ); - c = waitKey(0); - if( c == 27 || c == 'q' || c == 'Q' ) - break; - } - else - { - cerr << "Aw snap, couldn't read image " << buf << endl; - } - } - fclose(f); + if (useCPU) + cout << "average CPU time (noCamera) : "; + else + cout << "average GPU time (noCamera) : "; + cout << getTime() / LOOP_NUM << " ms" << endl; + cout << "accuracy value: " << accuracy <& faces, + cv::ocl::OclCascadeClassifierBuf& cascade, + double scale, bool calTime) { - int i = 0; - double t = 0; - vector faces; - const static Scalar colors[] = { CV_RGB(0,0,255), - CV_RGB(0,128,255), - CV_RGB(0,255,255), - CV_RGB(0,255,0), - CV_RGB(255,128,0), - CV_RGB(255,255,0), - CV_RGB(255,0,0), - CV_RGB(255,0,255)} ; cv::ocl::oclMat image(img); cv::ocl::oclMat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); - + if(calTime) workBegin(); cv::ocl::cvtColor( image, gray, CV_BGR2GRAY ); cv::ocl::resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); cv::ocl::equalizeHist( smallImg, smallImg ); - CvSeq* _objects; - MemStorage storage(cvCreateMemStorage(0)); - t = (double)cvGetTickCount(); - _objects = cascade.oclHaarDetectObjects( smallImg, storage, 1.1, + cascade.detectMultiScale( smallImg, faces, 1.1, 3, 0 |CV_HAAR_SCALE_IMAGE , Size(30,30), Size(0, 0) ); - vector vecAvgComp; - Seq(_objects).copyTo(vecAvgComp); - faces.resize(vecAvgComp.size()); - std::transform(vecAvgComp.begin(), vecAvgComp.end(), faces.begin(), getRect()); - t = (double)cvGetTickCount() - t; - printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); + if(calTime) workEnd(); +} + +void detectCPU( Mat& img, vector& faces, + CascadeClassifier& cascade, + double scale, bool calTime) +{ + if(calTime) workBegin(); + Mat cpu_gray, cpu_smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); + cvtColor(img, cpu_gray, CV_BGR2GRAY); + resize(cpu_gray, cpu_smallImg, cpu_smallImg.size(), 0, 0, INTER_LINEAR); + equalizeHist(cpu_smallImg, cpu_smallImg); + cascade.detectMultiScale(cpu_smallImg, faces, 1.1, + 3, 0 | CV_HAAR_SCALE_IMAGE, + Size(30, 30), Size(0, 0)); + if(calTime) workEnd(); +} + +void Draw(Mat& img, vector& faces, double scale) +{ + int i = 0; for( vector::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) { - Mat smallImgROI; Point center; Scalar color = colors[i%8]; int radius; @@ -227,3 +232,42 @@ void detectAndDraw( Mat& img, } cv::imshow( "result", img ); } + +double checkRectSimilarity(Size sz, std::vector& ob1, std::vector& ob2) +{ + double final_test_result = 0.0; + size_t sz1 = ob1.size(); + size_t sz2 = ob2.size(); + + if(sz1 != sz2) + return sz1 > sz2 ? (double)(sz1 - sz2) : (double)(sz2 - sz1); + else + { + cv::Mat cpu_result(sz, CV_8UC1); + cpu_result.setTo(0); + + for(vector::const_iterator r = ob1.begin(); r != ob1.end(); r++) + { + cv::Mat cpu_result_roi(cpu_result, *r); + cpu_result_roi.setTo(1); + cpu_result.copyTo(cpu_result); + } + int cpu_area = cv::countNonZero(cpu_result > 0); + + cv::Mat gpu_result(sz, CV_8UC1); + gpu_result.setTo(0); + for(vector::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++) + { + cv::Mat gpu_result_roi(gpu_result, *r2); + gpu_result_roi.setTo(1); + gpu_result.copyTo(gpu_result); + } + + cv::Mat result_; + multiply(cpu_result, gpu_result, result_); + int result = cv::countNonZero(result_ > 0); + + final_test_result = 1.0 - (double)result/(double)cpu_area; + } + return final_test_result; +} diff --git a/samples/ocl/hog.cpp b/samples/ocl/hog.cpp index 76b6d28..28be6fa 100644 --- a/samples/ocl/hog.cpp +++ b/samples/ocl/hog.cpp @@ -45,7 +45,6 @@ public: bool gamma_corr; }; - class App { public: @@ -64,6 +63,13 @@ public: string message() const; +// This function test if gpu_rst matches cpu_rst. +// If the two vectors are not equal, it will return the difference in vector size +// Else if will return +// (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) + double checkRectSimilarity(Size sz, + std::vector& cpu_rst, + std::vector& gpu_rst); private: App operator=(App&); @@ -290,6 +296,7 @@ void App::run() ocl::oclMat gpu_img; // Iterate over all frames + bool verify = false; while (running && !frame.empty()) { workBegin(); @@ -316,7 +323,18 @@ void App::run() gpu_img.upload(img); gpu_hog.detectMultiScale(gpu_img, found, hit_threshold, win_stride, Size(0, 0), scale, gr_threshold); - } + if (!verify) + { + // verify if GPU output same objects with CPU at 1st run + verify = true; + vector ref_rst; + cvtColor(img, img, CV_BGRA2BGR); + cpu_hog.detectMultiScale(img, ref_rst, hit_threshold, win_stride, + Size(0, 0), scale, gr_threshold-2); + double accuracy = checkRectSimilarity(img.size(), ref_rst, found); + cout << "\naccuracy value: " << accuracy << endl; + } + } else cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride, Size(0, 0), scale, gr_threshold); hogWorkEnd(); @@ -457,3 +475,45 @@ inline string App::workFps() const return ss.str(); } +double App::checkRectSimilarity(Size sz, + std::vector& ob1, + std::vector& ob2) +{ + double final_test_result = 0.0; + size_t sz1 = ob1.size(); + size_t sz2 = ob2.size(); + + if(sz1 != sz2) + return sz1 > sz2 ? (double)(sz1 - sz2) : (double)(sz2 - sz1); + else + { + cv::Mat cpu_result(sz, CV_8UC1); + cpu_result.setTo(0); + + for(vector::const_iterator r = ob1.begin(); r != ob1.end(); r++) + { + cv::Mat cpu_result_roi(cpu_result, *r); + cpu_result_roi.setTo(1); + cpu_result.copyTo(cpu_result); + } + int cpu_area = cv::countNonZero(cpu_result > 0); + + cv::Mat gpu_result(sz, CV_8UC1); + gpu_result.setTo(0); + for(vector::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++) + { + cv::Mat gpu_result_roi(gpu_result, *r2); + gpu_result_roi.setTo(1); + gpu_result.copyTo(gpu_result); + } + + cv::Mat result_; + multiply(cpu_result, gpu_result, result_); + int result = cv::countNonZero(result_ > 0); + + final_test_result = 1.0 - (double)result/(double)cpu_area; + } + return final_test_result; + +} + -- 2.7.4