diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 505cd6e3a1..799f34f100 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(c) add_subdirectory(cpp) add_subdirectory(gpu) +add_subdirectory(ocl) if(ANDROID AND BUILD_ANDROID_EXAMPLES) add_subdirectory(android) diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt new file mode 100644 index 0000000000..4d89ff40d7 --- /dev/null +++ b/samples/ocl/CMakeLists.txt @@ -0,0 +1,64 @@ +SET(OPENCV_OCL_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc opencv_highgui + opencv_ml opencv_video opencv_objdetect opencv_features2d + opencv_calib3d opencv_legacy opencv_contrib opencv_ocl + opencv_nonfree) + +ocv_check_dependencies(${OPENCV_OCL_SAMPLES_REQUIRED_DEPS}) + +if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) + set(project "ocl") + string(TOUPPER "${project}" project_upper) + + project("${project}_samples") + + ocv_include_modules(${OPENCV_OCL_SAMPLES_REQUIRED_DEPS}) + + if(HAVE_OPENCL) + ocv_include_directories(${OPENCL_INCLUDE_DIR}) + endif() + + if(CMAKE_COMPILER_IS_GNUCXX AND NOT ENABLE_NOISY_WARNINGS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") + endif() + + # --------------------------------------------- + # Define executable targets + # --------------------------------------------- + MACRO(OPENCV_DEFINE_OCL_EXAMPLE name srcs) + set(the_target "example_${project}_${name}") + add_executable(${the_target} ${srcs}) + + target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${OPENCV_OCL_SAMPLES_REQUIRED_DEPS}) + + set_target_properties(${the_target} PROPERTIES + OUTPUT_NAME "${name}_${project}" + PROJECT_LABEL "(EXAMPLE_${project_upper}) ${name}") + + if(ENABLE_SOLUTION_FOLDERS) + set_target_properties(${the_target} PROPERTIES FOLDER "samples//${project}") + endif() + + if(WIN32) + if(MSVC AND NOT BUILD_SHARED_LIBS) + set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /DEBUG") + endif() + install(TARGETS ${the_target} RUNTIME DESTINATION "samples/${project}" COMPONENT main) + endif() + ENDMACRO() + + file(GLOB all_samples RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) + + foreach(sample_filename ${all_samples}) + get_filename_component(sample ${sample_filename} NAME_WE) + file(GLOB sample_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${sample}.*) + OPENCV_DEFINE_OCL_EXAMPLE(${sample} ${sample_srcs}) + endforeach() +endif() + +if (NOT WIN32) + file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd ) + install(FILES ${install_list} + DESTINATION share/opencv/samples/${project} + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) +endif() + diff --git a/samples/ocl/hog.cpp b/samples/ocl/hog.cpp new file mode 100644 index 0000000000..96a4af0a7d --- /dev/null +++ b/samples/ocl/hog.cpp @@ -0,0 +1,459 @@ +#include +#include +#include +#include +#include +#include +#include "opencv2/ocl/ocl.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace std; +using namespace cv; + +bool help_showed = false; + +class Args +{ +public: + Args(); + static Args read(int argc, char** argv); + + string src; + bool src_is_video; + bool src_is_camera; + int camera_id; + + bool write_video; + string dst_video; + double dst_video_fps; + + bool make_gray; + + bool resize_src; + int width, height; + + double scale; + int nlevels; + int gr_threshold; + + double hit_threshold; + bool hit_threshold_auto; + + int win_width; + int win_stride_width, win_stride_height; + + bool gamma_corr; +}; + + +class App +{ +public: + App(const Args& s); + void run(); + + void handleKey(char key); + + void hogWorkBegin(); + void hogWorkEnd(); + string hogWorkFps() const; + + void workBegin(); + void workEnd(); + string workFps() const; + + string message() const; + +private: + App operator=(App&); + + Args args; + bool running; + + bool use_gpu; + bool make_gray; + double scale; + int gr_threshold; + int nlevels; + double hit_threshold; + bool gamma_corr; + + int64 hog_work_begin; + double hog_work_fps; + + int64 work_begin; + double work_fps; +}; + +static void printHelp() +{ + cout << "Histogram of Oriented Gradients descriptor and detector sample.\n" + << "\nUsage: hog_gpu\n" + << " (|--video |--camera ) # frames source\n" + << " [--make_gray ] # convert image to gray one or not\n" + << " [--resize_src ] # do resize of the source image or not\n" + << " [--width ] # resized image width\n" + << " [--height ] # resized image height\n" + << " [--hit_threshold ] # classifying plane distance threshold (0.0 usually)\n" + << " [--scale ] # HOG window scale factor\n" + << " [--nlevels ] # max number of HOG window scales\n" + << " [--win_width ] # width of the window (48 or 64)\n" + << " [--win_stride_width ] # distance by OX axis between neighbour wins\n" + << " [--win_stride_height ] # distance by OY axis between neighbour wins\n" + << " [--gr_threshold ] # merging similar rects constant\n" + << " [--gamma_correct ] # do gamma correction or not\n" + << " [--write_video ] # write video or not\n" + << " [--dst_video ] # output video path\n" + << " [--dst_video_fps ] # output video fps\n"; + help_showed = true; +} + +int main(int argc, char** argv) +{ + try + { + if (argc < 2) + printHelp(); + Args args = Args::read(argc, argv); + if (help_showed) + return -1; + App app(args); + app.run(); + } + catch (const Exception& e) { return cout << "error: " << e.what() << endl, 1; } + catch (const exception& e) { return cout << "error: " << e.what() << endl, 1; } + catch(...) { return cout << "unknown exception" << endl, 1; } + return 0; +} + + +Args::Args() +{ + src_is_video = false; + src_is_camera = false; + camera_id = 0; + + write_video = false; + dst_video_fps = 24.; + + make_gray = false; + + resize_src = false; + width = 640; + height = 480; + + scale = 1.05; + nlevels = 13; + gr_threshold = 8; + hit_threshold = 1.4; + hit_threshold_auto = true; + + win_width = 48; + win_stride_width = 8; + win_stride_height = 8; + + gamma_corr = true; +} + + +Args Args::read(int argc, char** argv) +{ + Args args; + for (int i = 1; i < argc; i++) + { + if (string(argv[i]) == "--make_gray") args.make_gray = (string(argv[++i]) == "true"); + else if (string(argv[i]) == "--resize_src") args.resize_src = (string(argv[++i]) == "true"); + else if (string(argv[i]) == "--width") args.width = atoi(argv[++i]); + else if (string(argv[i]) == "--height") args.height = atoi(argv[++i]); + else if (string(argv[i]) == "--hit_threshold") + { + args.hit_threshold = atof(argv[++i]); + args.hit_threshold_auto = false; + } + else if (string(argv[i]) == "--scale") args.scale = atof(argv[++i]); + else if (string(argv[i]) == "--nlevels") args.nlevels = atoi(argv[++i]); + else if (string(argv[i]) == "--win_width") args.win_width = atoi(argv[++i]); + else if (string(argv[i]) == "--win_stride_width") args.win_stride_width = atoi(argv[++i]); + else if (string(argv[i]) == "--win_stride_height") args.win_stride_height = atoi(argv[++i]); + else if (string(argv[i]) == "--gr_threshold") args.gr_threshold = atoi(argv[++i]); + else if (string(argv[i]) == "--gamma_correct") args.gamma_corr = (string(argv[++i]) == "true"); + else if (string(argv[i]) == "--write_video") args.write_video = (string(argv[++i]) == "true"); + else if (string(argv[i]) == "--dst_video") args.dst_video = argv[++i]; + else if (string(argv[i]) == "--dst_video_fps") args.dst_video_fps = atof(argv[++i]); + else if (string(argv[i]) == "--help") printHelp(); + else if (string(argv[i]) == "--video") { args.src = argv[++i]; args.src_is_video = true; } + else if (string(argv[i]) == "--camera") { args.camera_id = atoi(argv[++i]); args.src_is_camera = true; } + else if (args.src.empty()) args.src = argv[i]; + else throw runtime_error((string("unknown key: ") + argv[i])); + } + return args; +} + + +App::App(const Args& s) +{ + args = s; + cout << "\nControls:\n" + << "\tESC - exit\n" + << "\tm - change mode GPU <-> CPU\n" + << "\tg - convert image to gray or not\n" + << "\t1/q - increase/decrease HOG scale\n" + << "\t2/w - increase/decrease levels count\n" + << "\t3/e - increase/decrease HOG group threshold\n" + << "\t4/r - increase/decrease hit threshold\n" + << endl; + + use_gpu = true; + make_gray = args.make_gray; + scale = args.scale; + gr_threshold = args.gr_threshold; + nlevels = args.nlevels; + + if (args.hit_threshold_auto) + args.hit_threshold = args.win_width == 48 ? 1.4 : 0.; + hit_threshold = args.hit_threshold; + + gamma_corr = args.gamma_corr; + + if (args.win_width != 64 && args.win_width != 48) + args.win_width = 64; + + cout << "Scale: " << scale << endl; + if (args.resize_src) + cout << "Resized source: (" << args.width << ", " << args.height << ")\n"; + cout << "Group threshold: " << gr_threshold << endl; + cout << "Levels number: " << nlevels << endl; + cout << "Win width: " << args.win_width << endl; + cout << "Win stride: (" << args.win_stride_width << ", " << args.win_stride_height << ")\n"; + cout << "Hit threshold: " << hit_threshold << endl; + cout << "Gamma correction: " << gamma_corr << endl; + cout << endl; +} + + +void App::run() +{ + std::vector oclinfo; + ocl::getDevice(oclinfo); + running = true; + cv::VideoWriter video_writer; + + Size win_size(args.win_width, args.win_width * 2); //(64, 128) or (48, 96) + Size win_stride(args.win_stride_width, args.win_stride_height); + + // Create HOG descriptors and detectors here + vector detector; + if (win_size == Size(64, 128)) + detector = cv::ocl::HOGDescriptor::getPeopleDetector64x128(); + else + detector = cv::ocl::HOGDescriptor::getPeopleDetector48x96(); + + cv::ocl::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, + cv::ocl::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr, + cv::ocl::HOGDescriptor::DEFAULT_NLEVELS); + cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1, + HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS); + gpu_hog.setSVMDetector(detector); + cpu_hog.setSVMDetector(detector); + + while (running) + { + VideoCapture vc; + Mat frame; + + if (args.src_is_video) + { + vc.open(args.src.c_str()); + if (!vc.isOpened()) + throw runtime_error(string("can't open video file: " + args.src)); + vc >> frame; + } + else if (args.src_is_camera) + { + vc.open(args.camera_id); + if (!vc.isOpened()) + { + stringstream msg; + msg << "can't open camera: " << args.camera_id; + throw runtime_error(msg.str()); + } + vc >> frame; + } + else + { + frame = imread(args.src); + if (frame.empty()) + throw runtime_error(string("can't open image file: " + args.src)); + } + + Mat img_aux, img, img_to_show; + ocl::oclMat gpu_img; + + // Iterate over all frames + while (running && !frame.empty()) + { + workBegin(); + + // Change format of the image + if (make_gray) cvtColor(frame, img_aux, CV_BGR2GRAY); + else if (use_gpu) cvtColor(frame, img_aux, CV_BGR2BGRA); + else frame.copyTo(img_aux); + + // Resize image + if (args.resize_src) resize(img_aux, img, Size(args.width, args.height)); + else img = img_aux; + img_to_show = img; + + gpu_hog.nlevels = nlevels; + cpu_hog.nlevels = nlevels; + + vector found; + + // Perform HOG classification + hogWorkBegin(); + if (use_gpu) + { + gpu_img.upload(img); + gpu_hog.detectMultiScale(gpu_img, found, hit_threshold, win_stride, + Size(0, 0), scale, gr_threshold); + } + else cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride, + Size(0, 0), scale, gr_threshold); + hogWorkEnd(); + + // Draw positive classified windows + for (size_t i = 0; i < found.size(); i++) + { + Rect r = found[i]; + rectangle(img_to_show, r.tl(), r.br(), CV_RGB(0, 255, 0), 3); + } + + if (use_gpu) + putText(img_to_show, "Mode: GPU", Point(5, 25), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); + else + putText(img_to_show, "Mode: CPU", Point(5, 25), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); + putText(img_to_show, "FPS (HOG only): " + hogWorkFps(), Point(5, 65), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); + putText(img_to_show, "FPS (total): " + workFps(), Point(5, 105), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2); + imshow("opencv_gpu_hog", img_to_show); + + if (args.src_is_video || args.src_is_camera) vc >> frame; + + workEnd(); + + if (args.write_video) + { + if (!video_writer.isOpened()) + { + video_writer.open(args.dst_video, CV_FOURCC('x','v','i','d'), args.dst_video_fps, + img_to_show.size(), true); + if (!video_writer.isOpened()) + throw std::runtime_error("can't create video writer"); + } + + if (make_gray) cvtColor(img_to_show, img, CV_GRAY2BGR); + else cvtColor(img_to_show, img, CV_BGRA2BGR); + + video_writer << img; + } + + handleKey((char)waitKey(3)); + } + } +} + + +void App::handleKey(char key) +{ + switch (key) + { + case 27: + running = false; + break; + case 'm': + case 'M': + use_gpu = !use_gpu; + cout << "Switched to " << (use_gpu ? "CUDA" : "CPU") << " mode\n"; + break; + case 'g': + case 'G': + make_gray = !make_gray; + cout << "Convert image to gray: " << (make_gray ? "YES" : "NO") << endl; + break; + case '1': + scale *= 1.05; + cout << "Scale: " << scale << endl; + break; + case 'q': + case 'Q': + scale /= 1.05; + cout << "Scale: " << scale << endl; + break; + case '2': + nlevels++; + cout << "Levels number: " << nlevels << endl; + break; + case 'w': + case 'W': + nlevels = max(nlevels - 1, 1); + cout << "Levels number: " << nlevels << endl; + break; + case '3': + gr_threshold++; + cout << "Group threshold: " << gr_threshold << endl; + break; + case 'e': + case 'E': + gr_threshold = max(0, gr_threshold - 1); + cout << "Group threshold: " << gr_threshold << endl; + break; + case '4': + hit_threshold+=0.25; + cout << "Hit threshold: " << hit_threshold << endl; + break; + case 'r': + case 'R': + hit_threshold = max(0.0, hit_threshold - 0.25); + cout << "Hit threshold: " << hit_threshold << endl; + break; + case 'c': + case 'C': + gamma_corr = !gamma_corr; + cout << "Gamma correction: " << gamma_corr << endl; + break; + } +} + + +inline void App::hogWorkBegin() { hog_work_begin = getTickCount(); } + +inline void App::hogWorkEnd() +{ + int64 delta = getTickCount() - hog_work_begin; + double freq = getTickFrequency(); + hog_work_fps = freq / delta; +} + +inline string App::hogWorkFps() const +{ + stringstream ss; + ss << hog_work_fps; + return ss.str(); +} + + +inline void App::workBegin() { work_begin = getTickCount(); } + +inline void App::workEnd() +{ + int64 delta = getTickCount() - work_begin; + double freq = getTickFrequency(); + work_fps = freq / delta; +} + +inline string App::workFps() const +{ + stringstream ss; + ss << work_fps; + return ss.str(); +} +