1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 4 using namespace cv; 5 using namespace std; 6 7 Rect roi; 8 Mat frame, mask; 9 void processFrame(Mat &binary, Rect &rect); 10 11 int main(int argc, char* argv) { 12 VideoCapture capture(0);//打开摄像头 13 if (!capture.isOpened()) { 14 printf("Could not find Video data.."); 15 return -1; 16 } 17 18 Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); 19 Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1)); 20 21 namedWindow("input_Video", CV_WINDOW_AUTOSIZE); 22 namedWindow("mask_Video", CV_WINDOW_AUTOSIZE); 23 while (capture.read(frame))//读取当前帧 24 { 25 26 inRange(frame, Scalar(0, 0, 0), Scalar(255, 80, 80), mask);//过滤得到Scalar1到Scalar2之间的图像 27 28 //形态学操作 29 morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1));//开操作,去掉噪声 30 dilate(mask, mask, kernel2, Point(-1, -1), 4);//膨胀,填补空洞 31 imshow("mask_Video", mask); 32 33 processFrame(mask, roi); // 轮廓发现与位置标定 34 rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);//画出外接矩形 35 imshow("input_Video", frame); 36 37 char c = waitKey(100);//延时100ms 38 if (c == 27) //等待“Esc” 39 { 40 break; 41 } 42 } 43 capture.release();//释放视频的内存 44 waitKey(0); 45 return 0; 46 47 } 48 49 50 //binary:输入图像 51 //rect:返回的ROI区域 52 void processFrame(Mat &binary, Rect &rect) { 53 Point p, center; 54 vector<vector<Point>> contours; 55 vector<Vec4i> hireachy; 56 //发现最外层轮廓 57 findContours(binary, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0)); 58 59 if (contours.size() > 0) //判断是否有轮廓被找到 60 { 61 double maxArea = 0.0; 62 for (size_t t = 0; t < contours.size(); t++) { 63 double area = contourArea(contours[static_cast<int>(t)]);//获取轮廓的面积 64 if (area > maxArea)//面积筛选,只画出最大的轮廓 65 { 66 maxArea = area; 67 rect = boundingRect(contours[static_cast<int>(t)]);//获取最小外界矩形 68 69 //计算并输出坐标 70 center.x = rect.x + cvRound(rect.width / 2.0); 71 center.y = rect.y + cvRound(rect.height / 2.0); 72 center.x = center.x - frame.cols / 2; 73 center.y = center.y - frame.rows / 2; 74 75 cout << center.x << "," << center.y << endl; 76 } 77 } 78 79 } 80 else { 81 rect.x = rect.y = rect.width = rect.height = 0; 82 } 83 84 }
inRange()函数 :
此函数作用:可实现二值化功能(这点类似threshold()函数),更关键的是可以同时针对多通道进行操作,使用起来非常方便! 主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0),该功能类似于之间所讲的双阈值化操作。
void inRange(InputArray src, InputArray lowerb,
InputArray upperb, OutputArray dst);
参数解释:
参数1:输入要处理的图像,可以为单通道或多通道。
参数2:包含下边界的数组或标量。
参数3:包含上边界数组或标量。
参数4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
请注意:该函数输出的dst是一幅二值化之后的图像。