OpenCV计算得到摄像头视野内灯源数目

目标:判断是否有灯源

环境:XP OpenCV3.1.0 VS2010

步骤说明:

1、cvtColor获得灰度图img_gray
2、blur模糊化
3、threshold获得二值图img_thres
4、再次blur模糊化
5、canny边缘检测得到img_canny
6、findContours轮廓检测获得N个包围
7、得到每个轮廓的最小外接矩阵
for(int i=0;i {
    7.1 绘制轮廓的最小矩阵,得到旋转矩阵
    7.2 根据旋转矩阵的角度,将图片整体旋转
    7.3 提取图片旋转后的ROI
    7.4 计算ROI的亮度和亮度的标准差,通过阀值判断是否灯源
}

缺点:只通过判断平均亮度和亮度的标准差,阀值选择不合适的话,会把反光的白色墙面都当成灯源。

程序:

程序段1:

主函数循环体:功能:获取摄像头图像,转换为灰度图,计算图像平均亮度和亮度的标准差,并实时显示在图像中。

while (true)
    {
        cap >> img,img_gray;
        if (!img.data)
            continue;

		GetLightSource(img);
		cvtColor(img, img_gray , COLOR_BGR2GRAY  );
        imshow("img_gray", img_gray);
		LumAvg = GetGrayImagAvg(img_gray);
		LumSd  = GetGrayImagStandardDeviation(img_gray, LumAvg);
				
		cv::Mat image_1 = img.clone();
		IplImage tmp = IplImage(image_1);
		//CvArr* arr = (CvArr*)&tmp;

		//the font variable    
		CvFont font;    
		double hScale=0.7;   
		double vScale=0.7;    
		int lineWidth=4;// 相当于写字的线条    
		//char showMsg[10]="hello image!";   
		// sprintf(showMsg, "avg: %d", LumAvg);             // 将整数转换成字符串
		char showMsg[14];

		showMsg[0]='a';	
		showMsg[1]='v';
		showMsg[2]='g';
		showMsg[3]=':';
		showMsg[4]='0'+(int)LumAvg/100;
		showMsg[5]='0'+(int)LumAvg%100/10;
		showMsg[6]='0'+(int)LumAvg%10;
		showMsg[7]=' ';
		
		showMsg[8]='s';
		showMsg[9]=':';
		showMsg[10]='0'+(int)LumSd/100;
		showMsg[11]='0'+(int)LumSd%100/10;
		showMsg[12]='0'+(int)LumSd%10;
		showMsg[13]='\0';
		// 初始化字体   
		cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);//初始化字体,准备写到图片上的   
		// cvPoint 为起笔的x,y坐标   
		cvPutText(&tmp,showMsg,cvPoint(10,20),&font,CV_RGB(255,0,0));//在图片中输出字符   

		cv::imshow ( "image_1", image_1 );
		cv::imshow ("img_gray", img_gray);
        imshow("video capture", img);
		imshow("标注出矩形", img);
		
		//waitKey(0);
        if (waitKey(20) >= 0)
            break;
    }

程序段2:全部复制自http://answers.opencv.org/question/905/roi-region-of-interest/

功能是contour得到了包围住目标的旋转后的矩阵,使用这个矩阵获得ROI。

// rect is the RotatedRect (I got it from a contour...)
RotatedRect rect;
// matrices we'll use
Mat M, rotated, cropped, cropped_gray;
// get angle and size from the bounding box
float angle = rect.angle;
Size rect_size = rect.size;
// thanks to http://felix.abecassis.me/2011/10/opencv-rotation-deskewing/
if (rect.angle < -45.) {
    angle += 90.0;
    swap(rect_size.width, rect_size.height);
}
// get the rotation matrix
M = getRotationMatrix2D(rect.center, angle, 1.0);
// perform the affine transformation
warpAffine(img, rotated, M, img.size(), INTER_CUBIC);
// crop the resulting image
getRectSubPix(rotated, rect_size, rect.center, cropped);
		

程序段3:平均亮度超过阀值或者亮度的标准差小于阀值,当作是光源。


		if( ( cropped_LumAvg > 200)&& ( cropped_LumSd < 40))
		{	
			lightSrcDetectCnt++;
			cout << "lightSrcDetectCnt++ "<< endl;
		}

程序段4:函数代码。输出参数就是有效的光源数目。


int GetLightSource(cv::Mat img)
{
	int lightSrcDetectCnt;
	vector> contours;
	vector hierarchy;
	double cropped_LumAvg, cropped_LumSd;

    Mat img_gray, img_canny, img_thres;
	cvtColor(img, img_gray , COLOR_BGR2GRAY  );
	img_thres = img_gray.clone();
	blur( img_gray, img_gray, Size(3,3) );
	threshold(img_gray,img_thres,250,253,THRESH_BINARY_INV);
	blur(img_thres,img_thres,Size(3,3));		
	Canny(img_thres, img_canny, 0, 30, 3);
	findContours(img_canny, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
 
	lightSrcDetectCnt = 0;
	Mat drawing = Mat::zeros(img_thres.size(), CV_8UC1); //最小外接矩形画布  
	for (int i = 0; i 200)&& ( cropped_LumSd < 40))
		{	
			lightSrcDetectCnt++;
			cout << "lightSrcDetectCnt++ "<< endl;
		}
		imshow("cropped", cropped);

		//waitKey(0);
	}
	//imshow("最小外接矩形", 画布);

	//Mat  B=A(Rect(0,0,100,100));
	cout << "contours.size(): " << contours.size()<< endl;
	cout << "lightSrcDetectCnt: " << lightSrcDetectCnt<< endl;
	
		cv::imshow ("img_canny", img_canny);
	imshow("drawing", drawing);
	
		imshow("img_thres", img_thres);
		return lightSrcDetectCnt;
}

 

你可能感兴趣的:(OpenCV)