一、安装Visual Studio
OpenCV是一种开源的计算机视觉开发库。既然是开发库,那么必须依托某种语言程序来加载。以C++为例,在安装OpenCV之前,必须安装C++的程序开发环境(IDE),在此我们选择Visual Studio Community——VS社区版,这个版本是免费的。
中文版下载安装地址:
https://visualstudio.microsoft.com/zh-hans/downloads/
注意这是一个在线安装的版本,请确保在安装过程中网络畅通。
二、创建C++程序
我们需要在VS中建立应用程序。在此我们建立最简单的基于控制台的应用程序,项目名为face1。
三、下载OpenCV
所谓OpenCV的安装,其实就是把OpenCV的库路径加入我们已有的项目路径集合当中。现在有两种方法,一种是自己下载OpencCV源码,在源码的基础上编译成库(lib/dll)文件,一种是下载直接编译好的库文件, 我们选择直接下载已经编译好的库文件
最新版OpenCV Lib 下载链接
https://sourceforge.net/projects/opencvlibrary/files/latest/download
一共266MB,外网有的时候挺慢的。
四、安装/配置OpenCV
下载后OpenCV后,运行,解压到一个固定目录。比如我的:“D:\试验\软件\opencv”——这个路径稍后要作为库和头文件的路径,加入以后C++程序项目中
在VS中,因为每个项目都是独立编译的,所以,每个项目具有自己的“规则包“。也就是说,对着项目名称右键,选择”属性“,可以配置该项目的编译规则。
现在我们在属性窗口中,配置OpenCV路径,步骤如下
1、在属性窗口中,我们选择输出目标”配置”为“Debug“,”平台“为”x64“。也就是编译输出在64位windows系统中运行的调试版(debug)应用程序
2、左边选择VC++目录,右边选中“包含目录“项进行编辑。把刚在OpenCV解压目录下的“include”目录包含进来。然后确定
3、重复上述步骤2。右边选中“库目录“项进行编辑。把刚在OpenCV解压目录下的“库目录”包含进来。然后确定
4、在属性窗口中,左边选中“链接器->输入“。右边选中“附加依赖项”。把刚在OpenCV解压后产生的静态引用库名字“opencv_world3416.lib”加进来(注意名字后面的数字部分视各个版本不同而不同)。然后确定。
5、最后将OpenCV解压目录下的dll文件拷贝到程序运行所在的目录
五、运行OpenCV程序
在已经建立好的项目“face1”的源代码中,加入opencv头文件
接着,在程序中就可以使用openCV所提供的库函数了。
比如在这个例子中:
我们读取事先准备好的一张图片,并输出它的尺寸:
运行结果:
六、利用OpenCV程序进行人脸检测。
这个实例在opencv安装目录下的“samples/c++”目录下。该目录有大量实例,可以一一尝试运行。
在此我们选择facedetect.cpp。复制相应代码运行
注意头文件需要做参照以下(而非例程中所示):
接着我们把这个项目所需要的数据文件移动到该项目应用程序所在目录
整个实验程序源码如下:
#define _CRT_SECURE_NO_WARNINGS#include #include using namespace std;using namespace cv;static void help(const char** argv){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"<<argv[0]<<" [--cascade= 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=]\n"" [--try-flip]\n"" [filename|camera_index]\n\n""example:\n"<<argv[0]<<" --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(argv);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(argv);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 thelist of the image filenames to be processed - one per line */FILE* f = fopen( 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 );}elserectangle( 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 );}
运行程序。该程序会自动打开摄像头,识别并定位摄像头前的人脸以及眼睛部位。
输入q或者Q,退出程序。
下一篇——参数解析