運行環境
- visual studio 2017(2019也可)
- opencv3.4(410也可)
xml文件
- 從OpenCV目錄裏找
C:\OpenCV4.0\opencv\sources\data\haarcascades 這裏也有其它目標檢測的xml文件,有空能夠一試ios
- 爲方便拷貝出來放在代碼工程的debug目錄
代碼
代碼從OpenCV提供的sample提取,稍微改一改git
C:\OpenCV4.0\opencv\sources\samples\cpp\facedetect.cpp 這裏面其它sample也值得一學app
#include "opencv2/objdetect.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include <iostream> using namespace std; using namespace cv; static void help() { cout << "\nThis program demonstrates the use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n" "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n" "It's most known use is for faces.\n" "Usage:\n" "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n" " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n" " [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n" " [--try-flip]\n" " [filename|camera_index]\n\n" "see facedetect.cmd for one call:\n" "./facedetect --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n" "During execution:\n\tHit any key to quit.\n" "\tUsing OpenCV version " << CV_VERSION << "\n" << endl; } void detectAndDraw(Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale, bool tryflip); string cascadeName; string nestedCascadeName; int main(int argc, const char** argv) { VideoCapture capture; Mat frame, image; string inputName; bool tryflip; CascadeClassifier cascade, nestedCascade; double scale; cv::CommandLineParser parser(argc, argv, "{help h||}" "{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}" "{nested-cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}" "{scale|1|}{try-flip||}{@filename||}" ); if (parser.has("help")) { help(); return 0; } cascadeName = parser.get<string>("cascade"); nestedCascadeName = parser.get<string>("nested-cascade"); scale = parser.get<double>("scale"); if (scale < 1) scale = 1; tryflip = parser.has("try-flip"); inputName = parser.get<string>("@filename"); if (!parser.check()) { parser.printErrors(); return 0; } if (!nestedCascade.load(samples::findFileOrKeep(nestedCascadeName))) cerr << "WARNING: Could not load classifier cascade for nested objects" << endl; if (!cascade.load(samples::findFile(cascadeName))) { cerr << "ERROR: Could not load classifier cascade" << endl; help(); return -1; } if (inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1)) { int camera = inputName.empty() ? 0 : inputName[0] - '0'; if (!capture.open(camera)) { cout << "Capture from camera #" << camera << " didn't work" << endl; return 1; } } else if (!inputName.empty()) { image = imread(samples::findFileOrKeep(inputName), IMREAD_COLOR); if (image.empty()) { if (!capture.open(samples::findFileOrKeep(inputName))) { cout << "Could not read " << inputName << endl; return 1; } } } else { image = imread(samples::findFile("lena.jpg"), IMREAD_COLOR); if (image.empty()) { cout << "Couldn't read lena.jpg" << endl; return 1; } } if (capture.isOpened()) { cout << "Video capturing has been started ..." << endl; for (;;) { capture >> frame; if (frame.empty()) break; Mat frame1 = frame.clone(); detectAndDraw(frame1, cascade, nestedCascade, scale, tryflip); char c = (char)waitKey(10); if (c == 27 || c == 'q' || c == 'Q') break; } } else { cout << "Detecting face(s) in " << inputName << endl; if (!image.empty()) { detectAndDraw(image, cascade, nestedCascade, scale, tryflip); 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_s(&f, inputName.c_str(), "rt"); if (f) { char buf[1000 + 1]; while (fgets(buf, 1000, f)) { int len = (int)strlen(buf); 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, tryflip); char c = (char)waitKey(0); if (c == 27 || c == 'q' || c == 'Q') break; } else { cerr << "Aw snap, couldn't read image " << buf << endl; } } fclose(f); } } } return 0; } void detectAndDraw(Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale, bool tryflip) { double t = 0; vector<Rect> faces, faces2; const static Scalar colors[] = { Scalar(255,0,0), Scalar(255,128,0), Scalar(255,255,0), Scalar(0,255,0), Scalar(0,128,255), Scalar(0,255,255), Scalar(0,0,255), Scalar(255,0,255) }; Mat gray, smallImg; cvtColor(img, gray, COLOR_BGR2GRAY); double fx = 1 / scale; resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT); equalizeHist(smallImg, smallImg); t = (double)getTickCount(); cascade.detectMultiScale(smallImg, faces, 1.1, 2, 0 //|CASCADE_FIND_BIGGEST_OBJECT //|CASCADE_DO_ROUGH_SEARCH | CASCADE_SCALE_IMAGE, Size(30, 30)); if (tryflip) { flip(smallImg, smallImg, 1); cascade.detectMultiScale(smallImg, faces2, 1.1, 2, 0 //|CASCADE_FIND_BIGGEST_OBJECT //|CASCADE_DO_ROUGH_SEARCH | CASCADE_SCALE_IMAGE, Size(30, 30)); for (vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r) { faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); } } t = (double)getTickCount() - t; printf("detection time = %g ms\n", t * 1000 / getTickFrequency()); for (size_t i = 0; i < faces.size(); i++) { Rect r = faces[i]; Mat smallImgROI; vector<Rect> nestedObjects; Point center; Scalar color = colors[i % 8]; int radius; double aspect_ratio = (double)r.width / r.height; //if (0.75 < aspect_ratio && aspect_ratio < 1.3) //{ // center.x = cvRound((r.x + r.width*0.5)*scale); // center.y = cvRound((r.y + r.height*0.5)*scale); // radius = cvRound((r.width + r.height)*0.25*scale); // circle(img, center, radius, color, 3, 8, 0); //} //else rectangle(img, Point(cvRound(r.x*scale), cvRound(r.y*scale)), Point(cvRound((r.x + r.width - 1)*scale), cvRound((r.y + r.height - 1)*scale)), color, 3, 8, 0); if (nestedCascade.empty()) continue; smallImgROI = smallImg(r); nestedCascade.detectMultiScale(smallImgROI, nestedObjects, 1.1, 2, 0 //|CASCADE_FIND_BIGGEST_OBJECT //|CASCADE_DO_ROUGH_SEARCH //|CASCADE_DO_CANNY_PRUNING | CASCADE_SCALE_IMAGE, Size(30, 30)); for (size_t j = 0; j < nestedObjects.size(); j++) { Rect nr = nestedObjects[j]; center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale); center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale); radius = cvRound((nr.width + nr.height)*0.25*scale); circle(img, center, radius, color, 3, 8, 0); } } imshow("result", img); }
代碼編譯成功後編輯一個bat文件便可,例如:ide
XML_object_detect --cascade=./data/haarcascades/haarcascade_frontalface_alt.xml --scale=1.3 --try-flip ./img/261068.jpg pause
有個比較全面的博客值得參考https://blog.csdn.net/u012679707/article/details/80376969ui