diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 2004857f1..05bbfe874 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -4,7 +4,7 @@ # ---------------------------------------------------------------------------- SET(OPENCV_CPP_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc - opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree + opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree opencv_softcascade opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab) ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/cpp/peopledetect.cpp b/samples/cpp/peopledetect.cpp index e15b683ab..893f8cb73 100644 --- a/samples/cpp/peopledetect.cpp +++ b/samples/cpp/peopledetect.cpp @@ -1,111 +1,180 @@ #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" +#include -#include -#include -#include +#include +#include +#include +#include -using namespace cv; -using namespace std; - -// static void help() -// { -// printf( -// "\nDemonstrate the use of the HoG descriptor using\n" -// " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n" -// "Usage:\n" -// "./peopledetect ( | .txt)\n\n"); -// } +void filter_rects(const std::vector& candidates, std::vector& objects); int main(int argc, char** argv) { - Mat img; - FILE* f = 0; - char _filename[1024]; + const std::string keys = + "{help h usage ? | | print this message and exit }" + "{cascade c | | path to cascade xml, if empty HOG detector will be executed }" + "{frame f | | wildchart pattern to frame source}" + "{min_scale |0.4 | minimum scale to detect }" + "{max_scale |5.0 | maxamum scale to detect }" + "{total_scales |55 | prefered number of scales between min and max }" + "{write_file wf |0 | write to .txt. Disabled by default.}" + "{write_image wi |0 | write to image. Disabled by default.}" + "{show_image si |1 | show image. Enabled by default.}" + "{threshold thr |-1 | detection threshold. Detections with score less then threshold will be ignored.}" + ; - if( argc == 1 ) + cv::CommandLineParser parser(argc, argv, keys); + parser.about("Soft cascade training application."); + + if (parser.has("help")) { - printf("Usage: peopledetect ( | .txt)\n"); + parser.printMessage(); return 0; } - img = imread(argv[1]); - if( img.data ) + if (!parser.check()) { - strcpy(_filename, argv[1]); + parser.printErrors(); + return 1; + } + + int wf = parser.get("write_file"); + if (wf) std::cout << "resulte will be stored to .txt file with the same name as image." << std::endl; + + int wi = parser.get("write_image"); + if (wi) std::cout << "resulte will be stored to image with the same name as input plus dt." << std::endl; + + int si = parser.get("show_image"); + + float minScale = parser.get("min_scale"); + float maxScale = parser.get("max_scale"); + int scales = parser.get("total_scales"); + int thr = parser.get("threshold"); + + cv::HOGDescriptor hog; + cv::softcascade::Detector cascade; + + bool useHOG = false; + std::string cascadePath = parser.get("cascade"); + if (cascadePath.empty()) + { + useHOG = true; + hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); + std::cout << "going to use HOG detector." << std::endl; } else { - f = fopen(argv[1], "rt"); - if(!f) + cv::FileStorage fs(cascadePath, cv::FileStorage::READ); + if( !fs.isOpened()) { - fprintf( stderr, "ERROR: the specified file could not be loaded\n"); - return -1; + std::cout << "Soft Cascade file " << cascadePath << " can't be opened." << std::endl << std::flush; + return 1; + } + + cascade = cv::softcascade::Detector(minScale, maxScale, scales, cv::softcascade::Detector::DOLLAR); + + if (!cascade.load(fs.getFirstTopLevelNode())) + { + std::cout << "Soft Cascade can't be parsed." << std::endl << std::flush; + return 1; } } - HOGDescriptor hog; - hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); - namedWindow("people detector", 1); + std::string src = parser.get("frame"); + std::vector frames; + cv::glob(parser.get("frame"), frames); + std::cout << "collected " << src << " " << frames.size() << " frames." << std::endl; - for(;;) + for (int i = 0; i < (int)frames.size(); ++i) { - char* filename = _filename; - if(f) - { - if(!fgets(filename, (int)sizeof(_filename)-2, f)) - break; - //while(*filename && isspace(*filename)) - // ++filename; - if(filename[0] == '#') - continue; - int l = (int)strlen(filename); - while(l > 0 && isspace(filename[l-1])) - --l; - filename[l] = '\0'; - img = imread(filename); - } - printf("%s:\n", filename); - if(!img.data) - continue; + std::string& frame_sourse = frames[i]; + cv::Mat frame = cv::imread(frame_sourse); - fflush(stdout); - vector found, found_filtered; - double t = (double)getTickCount(); - // run the detector with default parameters. to get a higher hit-rate - // (and more false alarms, respectively), decrease the hitThreshold and - // groupThreshold (set groupThreshold to 0 to turn off the grouping completely). - hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2); - t = (double)getTickCount() - t; - printf("tdetection time = %gms\n", t*1000./cv::getTickFrequency()); - size_t i, j; - for( i = 0; i < found.size(); i++ ) + if(frame.empty()) { - Rect r = found[i]; - for( j = 0; j < found.size(); j++ ) - if( j != i && (r & found[j]) == r) - break; - if( j == found.size() ) - found_filtered.push_back(r); + std::cout << "Frame source " << frame_sourse << " can't be opened." << std::endl << std::flush; + continue; } - for( i = 0; i < found_filtered.size(); i++ ) + + std::ofstream myfile; + if (wf) + myfile.open((frame_sourse.replace(frame_sourse.end() - 3, frame_sourse.end(), "txt")).c_str(), std::ios::out); + + //// + if (useHOG) { - Rect r = found_filtered[i]; - // the HOG detector returns slightly larger rectangles than the real objects. - // so we slightly shrink the rectangles to get a nicer output. - r.x += cvRound(r.width*0.1); - r.width = cvRound(r.width*0.8); - r.y += cvRound(r.height*0.07); - r.height = cvRound(r.height*0.8); - rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3); + std::vector found, found_filtered; + // run the detector with default parameters. to get a higher hit-rate + // (and more false alarms, respectively), decrease the hitThreshold and + // groupThreshold (set groupThreshold to 0 to turn off the grouping completely). + hog.detectMultiScale(frame, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2); + + filter_rects(found, found_filtered); + std::cout << "collected: " << (int)found_filtered.size() << " detections." << std::endl; + + for (size_t ff = 0; ff < found_filtered.size(); ++ff) + { + cv::Rect r = found_filtered[ff]; + cv::rectangle(frame, r.tl(), r.br(), cv::Scalar(0,255,0), 3); + + if (wf) myfile << r.x << "," << r.y << "," << r.width << "," << r.height << "," << 0.f << "\n"; + } + } + else + { + std::vector objects; + cascade.detect(frame, cv::noArray(), objects); + std::cout << "collected: " << (int)objects.size() << " detections." << std::endl; + + for (int obj = 0; obj < (int)objects.size(); ++obj) + { + cv::softcascade::Detection d = objects[obj]; + + if(d.confidence > thr) + { + float b = d.confidence * 1.5f; + + std::stringstream conf(std::stringstream::in | std::stringstream::out); + conf << d.confidence; + + cv::rectangle(frame, cv::Rect(d.bb.x, d.bb.y, d.bb.width, d.bb.height), cv::Scalar(b, 0, 255 - b, 255), 2); + cv::putText(frame, conf.str() , cv::Point(d.bb.x + 10, d.bb.y - 5),1, 1.1, cv::Scalar(25, 133, 255, 0), 1, CV_AA); + + if (wf) + myfile << d.bb.x << "," << d.bb.y << "," + << d.bb.width << "," << d.bb.height << "," << d.confidence << "\n"; + } + } + } + + if (wi) cv::imwrite(frame_sourse + ".dt.png", frame); + if (wf) myfile.close(); + + if (si) + { + cv::imshow("pedestrian detector", frame); + cv::waitKey(10); } - imshow("people detector", img); - int c = waitKey(0) & 255; - if( c == 'q' || c == 'Q' || !f) - break; } - if(f) - fclose(f); + + if (si) cv::waitKey(0); return 0; } + +void filter_rects(const std::vector& candidates, std::vector& objects) +{ + size_t i, j; + for (i = 0; i < candidates.size(); ++i) + { + cv::Rect r = candidates[i]; + + for (j = 0; j < candidates.size(); ++j) + if (j != i && (r & candidates[j]) == r) + break; + + if (j == candidates.size()) + objects.push_back(r); + } +}