diff --git a/samples/ocl/pyrlk_optical_flow.cpp b/samples/ocl/pyrlk_optical_flow.cpp new file mode 100644 index 000000000..1b2b1d379 --- /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 000000000..7ac2c9a6f --- /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; + } +} + +