基于opencv的人脸识别程序
1. 解析opencv自带人脸识别源码(……/opencv-3.1.0/samples/cpp/facedetect.cpp)
@ 操作系统:Ubuntu 15.04
OpenCV版本:3.1.0
1 #include "opencv2/objdetect.hpp" 2 #include "opencv2/highgui.hpp" 3 #include "opencv2/imgproc.hpp" 4 #include <iostream> 5 6 using namespace std; 7 using namespace cv; 8 9 static void help() 10 { 11 cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n" 12 "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n" 13 "It's most known use is for faces.\n" 14 "Usage:\n" 15 "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n" 16 " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n" 17 " [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n" 18 " [--try-flip]\n" 19 " [filename|camera_index]\n\n" 20 "see facedetect.cmd for one call:\n" 21 "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n" 22 "During execution:\n\tHit any key to quit.\n" 23 "\tUsing OpenCV version " << CV_VERSION << "\n" << endl; 24 } 25 26 void detectAndDraw( Mat& img, CascadeClassifier& cascade, 27 CascadeClassifier& nestedCascade, 28 double scale, bool tryflip ); 29 30 string cascadeName; 31 string nestedCascadeName; 32 33 int main( int argc, const char** argv ) 34 { 35 VideoCapture capture; 36 Mat frame, image; 37 string inputName; 38 bool tryflip; 39 40 // CascadeClassifier是Opencv中做人脸检测的时候的一个级联分类器,现在有两种选择:一是使用老版本的CvHaarClassifierCascade函数,一是使用新版本的CascadeClassifier类。老版本的分类器只支持类Haar特征,而新版本的分类器既可以使用Haar,也可以使用LBP特征。 41 CascadeClassifier cascade, nestedCascade; 42 double scale; 43 44 cv::CommandLineParser parser(argc, argv, 45 "{help h||}" 46 "{cascade|../../data/haarcascades/haarcascade_frontalface_alt.xml|}" 47 "{nested-cascade|../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}" 48 "{scale|1|}{try-flip||}{@filename||}" 49 ); 50 if (parser.has("help")) 51 { 52 help(); 53 return 0; 54 } 55 56 // 问题1:不用定义返回类型? 57 cascadeName = parser.get<string>("cascade"); 58 nestedCascadeName = parser.get<string>("nested-cascade"); 59 scale = parser.get<double>("scale"); 60 if (scale < 1) 61 scale = 1; 62 tryflip = parser.has("try-flip"); 63 inputName = parser.get<string>("@filename"); 64 std::cout << inputName << std::endl; // test 65 if (!parser.check()) 66 { 67 parser.printErrors(); 68 return 0; 69 } 70 71 // 加载模型 72 if ( !nestedCascade.load( nestedCascadeName ) ) 73 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl; 74 if( !cascade.load( cascadeName ) ) 75 { 76 cerr << "ERROR: Could not load classifier cascade" << endl; 77 help(); 78 return -1; 79 } 80 // 读取摄像头 81 // isdigit检测字符是否为阿拉伯数字 82 if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) ) 83 { 84 int c = inputName.empty() ? 0 : inputName[0] - '0'; 85 // 此处若系统在虚拟机上,需在虚拟机中设置接管摄像头:虚拟机(M)-> 可移动设备 -> 摄像头名称 -> 连接(断开与主机连接) 86 if(!capture.open(c)) 87 cout << "Capture from camera #" << c << " didn't work" << endl; 88 else { 89 capture.set(CV_CAP_PROP_FRAME_WIDTH, 640); 90 capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480); 91 } 92 } 93 else if( inputName.size() ) 94 { 95 image = imread( inputName, 1 ); 96 if( image.empty() ) 97 { 98 if(!capture.open( inputName )) 99 cout << "Could not read " << inputName << endl; 100 } 101 } 102 else 103 { 104 image = imread( "../data/lena.jpg", 1 ); 105 if(image.empty()) cout << "Couldn't read ../data/lena.jpg" << endl; 106 } 107 108 if( capture.isOpened() ) 109 { 110 cout << "Video capturing has been started ..." << endl; 111 112 113 for(;;) 114 { 115 std::cout << "capturing..." << std::endl; // test 116 capture >> frame; 117 if( frame.empty() ) 118 break; 119 120 Mat frame1 = frame.clone(); 121 std::cout << "Start to detect..." << std::endl; // test 122 detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip ); 123 124 int c = waitKey(10); 125 if( c == 27 || c == 'q' || c == 'Q' ) 126 break; 127 } 128 } 129 else 130 { 131 cout << "Detecting face(s) in " << inputName << endl; 132 if( !image.empty() ) 133 { 134 detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); 135 waitKey(0); 136 } 137 else if( !inputName.empty() ) 138 { 139 /* assume it is a text file containing the 140 list of the image filenames to be processed - one per line */ 141 FILE* f = fopen( inputName.c_str(), "rt" ); 142 if( f ) 143 { 144 char buf[1000+1]; 145 while( fgets( buf, 1000, f ) ) 146 { 147 int len = (int)strlen(buf), c; 148 while( len > 0 && isspace(buf[len-1]) ) 149 len--; 150 buf[len] = '\0'; 151 cout << "file " << buf << endl; 152 image = imread( buf, 1 ); 153 if( !image.empty() ) 154 { 155 detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); 156 c = waitKey(0); 157 if( c == 27 || c == 'q' || c == 'Q' ) 158 break; 159 } 160 else 161 { 162 cerr << "Aw snap, couldn't read image " << buf << endl; 163 } 164 } 165 fclose(f); 166 } 167 } 168 } 169 170 return 0; 171 } 172 173 void detectAndDraw( Mat& img, CascadeClassifier& cascade, 174 CascadeClassifier& nestedCascade, 175 double scale, bool tryflip ) 176 { 177 double t = 0; 178 vector<Rect> faces, faces2; 179 const static Scalar colors[] = 180 { 181 Scalar(255,0,0), 182 Scalar(255,128,0), 183 Scalar(255,255,0), 184 Scalar(0,255,0), 185 Scalar(0,128,255), 186 Scalar(0,255,255), 187 Scalar(0,0,255), 188 Scalar(255,0,255) 189 }; 190 Mat gray, smallImg; 191 192 cvtColor( img, gray, COLOR_BGR2GRAY ); 193 double fx = 1 / scale; 194 resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR ); 195 equalizeHist( smallImg, smallImg ); 196 197 t = (double)cvGetTickCount(); 198 cascade.detectMultiScale( smallImg, faces, 199 1.1, 2, 0 200 //|CASCADE_FIND_BIGGEST_OBJECT 201 //|CASCADE_DO_ROUGH_SEARCH 202 |CASCADE_SCALE_IMAGE, 203 Size(30, 30) ); 204 if( tryflip ) 205 { 206 flip(smallImg, smallImg, 1); 207 cascade.detectMultiScale( smallImg, faces2, 208 1.1, 2, 0 209 //|CASCADE_FIND_BIGGEST_OBJECT 210 //|CASCADE_DO_ROUGH_SEARCH 211 |CASCADE_SCALE_IMAGE, 212 Size(30, 30) ); 213 for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ ) 214 { 215 faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); 216 } 217 } 218 t = (double)cvGetTickCount() - t; 219 printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); 220 for ( size_t i = 0; i < faces.size(); i++ ) 221 { 222 Rect r = faces[i]; 223 Mat smallImgROI; 224 vector<Rect> nestedObjects; 225 Point center; 226 Scalar color = colors[i%8]; 227 int radius; 228 229 double aspect_ratio = (double)r.width/r.height; 230 if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ) 231 { 232 center.x = cvRound((r.x + r.width*0.5)*scale); 233 center.y = cvRound((r.y + r.height*0.5)*scale); 234 radius = cvRound((r.width + r.height)*0.25*scale); 235 circle( img, center, radius, color, 3, 8, 0 ); 236 } 237 else 238 rectangle( img, cvPoint(cvRound(r.x*scale), cvRound(r.y*scale)), 239 cvPoint(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)), 240 color, 3, 8, 0); 241 if( nestedCascade.empty() ) 242 continue; 243 smallImgROI = smallImg( r ); 244 nestedCascade.detectMultiScale( smallImgROI, nestedObjects, 245 1.1, 2, 0 246 //|CASCADE_FIND_BIGGEST_OBJECT 247 //|CASCADE_DO_ROUGH_SEARCH 248 //|CASCADE_DO_CANNY_PRUNING 249 |CASCADE_SCALE_IMAGE, 250 Size(30, 30) ); 251 for ( size_t j = 0; j < nestedObjects.size(); j++ ) 252 { 253 Rect nr = nestedObjects[j]; 254 center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale); 255 center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale); 256 radius = cvRound((nr.width + nr.height)*0.25*scale); 257 circle( img, center, radius, color, 3, 8, 0 ); 258 } 259 } 260 imshow( "result", img ); 261 }
问题未解决:
运行到capture>>frame;时出现select timeout的错误;
@ 操作系统:windows 10
OpenCV版本:3.1.0
代码与Linux版本基本相同,未出现错误;