diff --git a/samples/ocl/aloe-L.png b/samples/ocl/aloe-L.png deleted file mode 100644 index 47587668e2..0000000000 Binary files a/samples/ocl/aloe-L.png and /dev/null differ diff --git a/samples/ocl/aloe-R.png b/samples/ocl/aloe-R.png deleted file mode 100644 index 5d11c57a9e..0000000000 Binary files a/samples/ocl/aloe-R.png and /dev/null differ diff --git a/samples/ocl/aloe-disp.png b/samples/ocl/aloe-disp.png deleted file mode 100644 index dd4a499bed..0000000000 Binary files a/samples/ocl/aloe-disp.png and /dev/null differ diff --git a/samples/ocl/facedetect.cpp b/samples/ocl/facedetect.cpp index ec79339518..684c2d923b 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 -static void help() -{ - 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; +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)} ; + +int64 work_begin = 0; +int64 work_end = 0; + +static void workBegin() +{ + work_begin = getTickCount(); +} +static void workEnd() +{ + work_end += (getTickCount() - work_begin); +} +static double getTime(){ + return work_end /((double)cvGetTickFrequency() * 1000.); } -struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } }; -void detectAndDraw( Mat& img, - cv::ocl::OclCascadeClassifier& cascade, CascadeClassifier& nestedCascade, - double scale); -String cascadeName = "../../../data/haarcascades/haarcascade_frontalface_alt.xml"; +void detect( Mat& img, vector& faces, + cv::ocl::OclCascadeClassifierBuf& cascade, + double scale, bool calTime); + +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 ) { + 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 << "Avaible options:" << endl; + cmd.printParams(); + return 0; + } 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; + 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; - for( int i = 1; i < argc; i++ ) - { - 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] ); - } - - if( !cascade.load( cascadeName ) ) + 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() ) + vector faces; + vector ref_rst; + double accuracy = 0.; + for(int i = 0; i <= LOOP_NUM;i ++) { - detectAndDraw( image, cascade, nestedCascade, scale ); - waitKey(0); - } - else if( !inputName.empty() ) - { - /* 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 76b6d2830e..28be6fa9af 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; + +} + diff --git a/samples/ocl/pyrlk_optical_flow.cpp b/samples/ocl/pyrlk_optical_flow.cpp new file mode 100644 index 0000000000..1b2b1d3798 --- /dev/null +++ b/samples/ocl/pyrlk_optical_flow.cpp @@ -0,0 +1,290 @@ +#include +#include +#include + +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/ocl/ocl.hpp" +#include "opencv2/video/video.hpp" + +using namespace std; +using namespace cv; +using namespace cv::ocl; + +typedef unsigned char uchar; +#define LOOP_NUM 10 +int64 work_begin = 0; +int64 work_end = 0; + +static void workBegin() +{ + work_begin = getTickCount(); +} +static void workEnd() +{ + work_end += (getTickCount() - work_begin); +} +static double getTime(){ + return work_end * 1000. / getTickFrequency(); +} + +static void download(const oclMat& d_mat, vector& vec) +{ + vec.resize(d_mat.cols); + Mat mat(1, d_mat.cols, CV_32FC2, (void*)&vec[0]); + d_mat.download(mat); +} + +static void download(const oclMat& d_mat, vector& vec) +{ + vec.resize(d_mat.cols); + Mat mat(1, d_mat.cols, CV_8UC1, (void*)&vec[0]); + d_mat.download(mat); +} + +static void drawArrows(Mat& frame, const vector& prevPts, const vector& nextPts, const vector& status, Scalar line_color = Scalar(0, 0, 255)) +{ + for (size_t i = 0; i < prevPts.size(); ++i) + { + if (status[i]) + { + int line_thickness = 1; + + Point p = prevPts[i]; + Point q = nextPts[i]; + + double angle = atan2((double) p.y - q.y, (double) p.x - q.x); + + double hypotenuse = sqrt( (double)(p.y - q.y)*(p.y - q.y) + (double)(p.x - q.x)*(p.x - q.x) ); + + if (hypotenuse < 1.0) + continue; + + // Here we lengthen the arrow by a factor of three. + q.x = (int) (p.x - 3 * hypotenuse * cos(angle)); + q.y = (int) (p.y - 3 * hypotenuse * sin(angle)); + + // Now we draw the main line of the arrow. + line(frame, p, q, line_color, line_thickness); + + // Now draw the tips of the arrow. I do some scaling so that the + // tips look proportional to the main line of the arrow. + + p.x = (int) (q.x + 9 * cos(angle + CV_PI / 4)); + p.y = (int) (q.y + 9 * sin(angle + CV_PI / 4)); + line(frame, p, q, line_color, line_thickness); + + p.x = (int) (q.x + 9 * cos(angle - CV_PI / 4)); + p.y = (int) (q.y + 9 * sin(angle - CV_PI / 4)); + line(frame, p, q, line_color, line_thickness); + } + } +} + + +int main(int argc, const char* argv[]) +{ + static std::vector ocl_info; + ocl::getDevice(ocl_info); + //if you want to use undefault device, set it here + setDevice(ocl_info[0]); + + //set this to save kernel compile time from second time you run + ocl::setBinpath("./"); + const char* keys = + "{ h | help | false | print help message }" + "{ l | left | | specify left image }" + "{ r | right | | specify right image }" + "{ c | camera | 0 | enable camera capturing }" + "{ s | use_cpu | false | use cpu or gpu to process the image }" + "{ v | video | | use video as input }" + "{ points | points | 1000 | specify points count [GoodFeatureToTrack] }" + "{ min_dist | min_dist | 0 | specify minimal distance between points [GoodFeatureToTrack] }"; + + CommandLineParser cmd(argc, argv, keys); + + if (cmd.get("help")) + { + cout << "Usage: pyrlk_optical_flow [options]" << endl; + cout << "Avaible options:" << endl; + cmd.printParams(); + return 0; + } + + bool defaultPicturesFail = false; + string fname0 = cmd.get("left"); + string fname1 = cmd.get("right"); + string vdofile = cmd.get("video"); + int points = cmd.get("points"); + double minDist = cmd.get("min_dist"); + bool useCPU = cmd.get("s"); + bool useCamera = cmd.get("c"); + int inputName = cmd.get("c"); + oclMat d_nextPts, d_status; + + Mat frame0 = imread(fname0, cv::IMREAD_GRAYSCALE); + Mat frame1 = imread(fname1, cv::IMREAD_GRAYSCALE); + PyrLKOpticalFlow d_pyrLK; + vector pts; + vector nextPts; + vector status; + vector err; + + if (frame0.empty() || frame1.empty()) + { + useCamera = true; + defaultPicturesFail = true; + CvCapture* capture = 0; + capture = cvCaptureFromCAM( inputName ); + if (!capture) + { + cout << "Can't load input images" << endl; + return -1; + } + } + + cout << "Points count : " << points << endl << endl; + + if (useCamera) + { + CvCapture* capture = 0; + Mat frame, frameCopy; + Mat frame0Gray, frame1Gray; + Mat ptr0, ptr1; + + if(vdofile == "") + capture = cvCaptureFromCAM( inputName ); + else + capture = cvCreateFileCapture(vdofile.c_str()); + + int c = inputName ; + if(!capture) + { + if(vdofile == "") + cout << "Capture from CAM " << c << " didn't work" << endl; + else + cout << "Capture from file " << vdofile << " failed" <= 0 ) + goto _cleanup_; + } + + waitKey(0); + +_cleanup_: + cvReleaseCapture( &capture ); + } + else + { +nocamera: + for(int i = 0; i <= LOOP_NUM;i ++) + { + cout << "loop" << i << endl; + if (i > 0) workBegin(); + + cv::goodFeaturesToTrack(frame0, pts, points, 0.01, minDist); + + if (useCPU) + { + cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, err); + } + else + { + oclMat d_prevPts(1, points, CV_32FC2, (void*)&pts[0]); + + d_pyrLK.sparse(oclMat(frame0), oclMat(frame1), d_prevPts, d_nextPts, d_status); + + download(d_prevPts, pts); + download(d_nextPts, nextPts); + download(d_status, status); + } + + if (i > 0 && i <= LOOP_NUM) + workEnd(); + + if (i == LOOP_NUM) + { + if (useCPU) + cout << "average CPU time (noCamera) : "; + else + cout << "average GPU time (noCamera) : "; + + cout << getTime() / LOOP_NUM << " ms" << endl; + + drawArrows(frame0, pts, nextPts, status, Scalar(255, 0, 0)); + + imshow("PyrLK [Sparse]", frame0); + } + } + } + + waitKey(); + + return 0; +} diff --git a/samples/ocl/stereo_match.cpp b/samples/ocl/stereo_match.cpp new file mode 100644 index 0000000000..7ac2c9a6f3 --- /dev/null +++ b/samples/ocl/stereo_match.cpp @@ -0,0 +1,419 @@ +#include +#include +#include +#include +#include +#include "opencv2/ocl/ocl.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; +using namespace ocl; + +bool help_showed = false; + +struct Params +{ + Params(); + static Params read(int argc, char** argv); + + string left; + string right; + + string method_str() const + { + switch (method) + { + case BM: return "BM"; + case BP: return "BP"; + case CSBP: return "CSBP"; + } + return ""; + } + enum {BM, BP, CSBP} method; + int ndisp; // Max disparity + 1 + enum {GPU, CPU} type; +}; + + +struct App +{ + App(const Params& p); + void run(); + void handleKey(char key); + void printParams() const; + + void workBegin() { work_begin = getTickCount(); } + void workEnd() + { + int64 d = getTickCount() - work_begin; + double f = getTickFrequency(); + work_fps = f / d; + } + + string text() const + { + stringstream ss; + ss << "(" << p.method_str() << ") FPS: " << setiosflags(ios::left) + << setprecision(4) << work_fps; + return ss.str(); + } +private: + Params p; + bool running; + + Mat left_src, right_src; + Mat left, right; + oclMat d_left, d_right; + + StereoBM_OCL bm; + StereoBeliefPropagation bp; + StereoConstantSpaceBP csbp; + + int64 work_begin; + double work_fps; +}; + +static void printHelp() +{ + cout << "Usage: stereo_match_gpu\n" + << "\t--left --right # must be rectified\n" + << "\t--method # BM | BP | CSBP\n" + << "\t--ndisp # number of disparity levels\n" + << "\t--type # cpu | CPU | gpu | GPU\n"; + help_showed = true; +} + +int main(int argc, char** argv) +{ + try + { + if (argc < 2) + { + printHelp(); + return 1; + } + + Params args = Params::read(argc, argv); + if (help_showed) + return -1; + + int flags[2] = { CVCL_DEVICE_TYPE_GPU, CVCL_DEVICE_TYPE_CPU }; + vector info; + + if(getDevice(info, flags[args.type]) == 0) + { + throw runtime_error("Error: Did not find a valid OpenCL device!"); + } + cout << "Device name:" << info[0].DeviceName[0] << endl; + + App app(args); + app.run(); + } + catch (const exception& e) + { + cout << "error: " << e.what() << endl; + } + return 0; +} + + +Params::Params() +{ + method = BM; + ndisp = 64; + type = GPU; +} + + +Params Params::read(int argc, char** argv) +{ + Params p; + + for (int i = 1; i < argc; i++) + { + if (string(argv[i]) == "--left") p.left = argv[++i]; + else if (string(argv[i]) == "--right") p.right = argv[++i]; + else if (string(argv[i]) == "--method") + { + if (string(argv[i + 1]) == "BM") p.method = BM; + else if (string(argv[i + 1]) == "BP") p.method = BP; + else if (string(argv[i + 1]) == "CSBP") p.method = CSBP; + else throw runtime_error("unknown stereo match method: " + string(argv[i + 1])); + i++; + } + else if (string(argv[i]) == "--ndisp") p.ndisp = atoi(argv[++i]); + else if (string(argv[i]) == "--type") + { + string t(argv[++i]); + if (t == "cpu" || t == "CPU") + { + p.type = CPU; + } + else if (t == "gpu" || t == "GPU") + { + p.type = GPU; + } + else throw runtime_error("unknown device type: " + t); + } + else if (string(argv[i]) == "--help") printHelp(); + else throw runtime_error("unknown key: " + string(argv[i])); + } + + return p; +} + + +App::App(const Params& params) + : p(params), running(false) +{ + cout << "stereo_match_ocl sample\n"; + cout << "\nControls:\n" + << "\tesc - exit\n" + << "\tp - print current parameters\n" + << "\tg - convert source images into gray\n" + << "\tm - change stereo match method\n" + << "\ts - change Sobel prefiltering flag (for BM only)\n" + << "\t1/q - increase/decrease maximum disparity\n" + << "\t2/w - increase/decrease window size (for BM only)\n" + << "\t3/e - increase/decrease iteration count (for BP and CSBP only)\n" + << "\t4/r - increase/decrease level count (for BP and CSBP only)\n"; +} + + +void App::run() +{ + // Load images + left_src = imread(p.left); + right_src = imread(p.right); + if (left_src.empty()) throw runtime_error("can't open file \"" + p.left + "\""); + if (right_src.empty()) throw runtime_error("can't open file \"" + p.right + "\""); + + cvtColor(left_src, left, CV_BGR2GRAY); + cvtColor(right_src, right, CV_BGR2GRAY); + + d_left.upload(left); + d_right.upload(right); + + imshow("left", left); + imshow("right", right); + + // Set common parameters + bm.ndisp = p.ndisp; + bp.ndisp = p.ndisp; + csbp.ndisp = p.ndisp; + + cout << endl; + printParams(); + + running = true; + while (running) + { + + // Prepare disparity map of specified type + Mat disp; + oclMat d_disp; + workBegin(); + switch (p.method) + { + case Params::BM: + if (d_left.channels() > 1 || d_right.channels() > 1) + { + cout << "BM doesn't support color images\n"; + cvtColor(left_src, left, CV_BGR2GRAY); + cvtColor(right_src, right, CV_BGR2GRAY); + cout << "image_channels: " << left.channels() << endl; + d_left.upload(left); + d_right.upload(right); + imshow("left", left); + imshow("right", right); + } + bm(d_left, d_right, d_disp); + break; + case Params::BP: + bp(d_left, d_right, d_disp); + break; + case Params::CSBP: + csbp(d_left, d_right, d_disp); + break; + } + ocl::finish(); + workEnd(); + + // Show results + d_disp.download(disp); + if (p.method != Params::BM) + { + disp.convertTo(disp, 0); + } + putText(disp, text(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar::all(255)); + imshow("disparity", disp); + + handleKey((char)waitKey(3)); + } +} + + +void App::printParams() const +{ + cout << "--- Parameters ---\n"; + cout << "image_size: (" << left.cols << ", " << left.rows << ")\n"; + cout << "image_channels: " << left.channels() << endl; + cout << "method: " << p.method_str() << endl + << "ndisp: " << p.ndisp << endl; + switch (p.method) + { + case Params::BM: + cout << "win_size: " << bm.winSize << endl; + cout << "prefilter_sobel: " << bm.preset << endl; + break; + case Params::BP: + cout << "iter_count: " << bp.iters << endl; + cout << "level_count: " << bp.levels << endl; + break; + case Params::CSBP: + cout << "iter_count: " << csbp.iters << endl; + cout << "level_count: " << csbp.levels << endl; + break; + } + cout << endl; +} + + +void App::handleKey(char key) +{ + switch (key) + { + case 27: + running = false; + break; + case 'p': case 'P': + printParams(); + break; + case 'g': case 'G': + if (left.channels() == 1 && p.method != Params::BM) + { + left = left_src; + right = right_src; + } + else + { + cvtColor(left_src, left, CV_BGR2GRAY); + cvtColor(right_src, right, CV_BGR2GRAY); + } + d_left.upload(left); + d_right.upload(right); + cout << "image_channels: " << left.channels() << endl; + imshow("left", left); + imshow("right", right); + break; + case 'm': case 'M': + switch (p.method) + { + case Params::BM: + p.method = Params::BP; + break; + case Params::BP: + p.method = Params::CSBP; + break; + case Params::CSBP: + p.method = Params::BM; + break; + } + cout << "method: " << p.method_str() << endl; + break; + case 's': case 'S': + if (p.method == Params::BM) + { + switch (bm.preset) + { + case StereoBM_OCL::BASIC_PRESET: + bm.preset = StereoBM_OCL::PREFILTER_XSOBEL; + break; + case StereoBM_OCL::PREFILTER_XSOBEL: + bm.preset = StereoBM_OCL::BASIC_PRESET; + break; + } + cout << "prefilter_sobel: " << bm.preset << endl; + } + break; + case '1': + p.ndisp = p.ndisp == 1 ? 8 : p.ndisp + 8; + cout << "ndisp: " << p.ndisp << endl; + bm.ndisp = p.ndisp; + bp.ndisp = p.ndisp; + csbp.ndisp = p.ndisp; + break; + case 'q': case 'Q': + p.ndisp = max(p.ndisp - 8, 1); + cout << "ndisp: " << p.ndisp << endl; + bm.ndisp = p.ndisp; + bp.ndisp = p.ndisp; + csbp.ndisp = p.ndisp; + break; + case '2': + if (p.method == Params::BM) + { + bm.winSize = min(bm.winSize + 1, 51); + cout << "win_size: " << bm.winSize << endl; + } + break; + case 'w': case 'W': + if (p.method == Params::BM) + { + bm.winSize = max(bm.winSize - 1, 2); + cout << "win_size: " << bm.winSize << endl; + } + break; + case '3': + if (p.method == Params::BP) + { + bp.iters += 1; + cout << "iter_count: " << bp.iters << endl; + } + else if (p.method == Params::CSBP) + { + csbp.iters += 1; + cout << "iter_count: " << csbp.iters << endl; + } + break; + case 'e': case 'E': + if (p.method == Params::BP) + { + bp.iters = max(bp.iters - 1, 1); + cout << "iter_count: " << bp.iters << endl; + } + else if (p.method == Params::CSBP) + { + csbp.iters = max(csbp.iters - 1, 1); + cout << "iter_count: " << csbp.iters << endl; + } + break; + case '4': + if (p.method == Params::BP) + { + bp.levels += 1; + cout << "level_count: " << bp.levels << endl; + } + else if (p.method == Params::CSBP) + { + csbp.levels += 1; + cout << "level_count: " << csbp.levels << endl; + } + break; + case 'r': case 'R': + if (p.method == Params::BP) + { + bp.levels = max(bp.levels - 1, 1); + cout << "level_count: " << bp.levels << endl; + } + else if (p.method == Params::CSBP) + { + csbp.levels = max(csbp.levels - 1, 1); + cout << "level_count: " << csbp.levels << endl; + } + break; + } +} + +