图像识别(10)——UVC预览+曝光滑动调节+Canny阈值调节+圆心打点

Posted somebot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像识别(10)——UVC预览+曝光滑动调节+Canny阈值调节+圆心打点相关的知识,希望对你有一定的参考价值。

博主QQ:1356438802

QQ群:473383394——UVC&OpenCV473383394


平台:Win7 64bits + Visual Studio 2012 + OpenCV 2.4.10


将《图像识别(7)——静态图片识别LED灯+Canny阈值调节+圆心打点》与《图像识别(9)——UVC预览+曝光滑动调节》两份代码结合,就可以得到动态视频的LED光点捕捉,并且绘制圆心点。

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序07
//		程序描述:使用VideoCapture类调用摄像头读入视频并显示
//		开发测试所用操作系统: Windows 7 64bit
//		开发测试所用IDE版本:Visual Studio 2010
//		开发测试所用OpenCV版本:	2.4.9
//		2014年03月 Created by @浅墨_毛星云
//		2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------
//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2\\opencv.hpp>  
using namespace cv;  
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"			//为窗口标题定义的宏 
#define WINDOW_NAME2 "【LED轨迹图】"			//为窗口标题定义的宏 
#define TRACK_BAR
//【1】从摄像头读入视频
VideoCapture capture;
Mat frame;  //定义一个Mat变量,用于存储每一帧的图像
double time0;
int exposure = -10;
Mat g_srcImage; 
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
#ifdef TRACK_BAR
//滑动条回调函数
void onChange(int pos, void* userdata);
void on_ThreshChange(int, void* );
#endif
//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main( )  
  
	//对给定的 2D 点集,寻找最小面积的包围圆
	Point2f center;
	float radius = 0;
	//用来绘制圆心点
	Mat drawing;
	bool is_new_draw = true;
	frame = imread("1.jpg", 0);
	// 创建窗口
	namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );
	namedWindow( WINDOW_NAME2, CV_WINDOW_AUTOSIZE );
	imshow( WINDOW_NAME1, frame );
	imshow( WINDOW_NAME2, frame );  //显示当前帧
	waitKey(1000);
	capture.open(0);
	if(false == capture.isOpened())
	
		return -1;
		
	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);
	exposure = capture.get(CV_CAP_PROP_EXPOSURE);
	//显示曝光值
	cout << ">设置后: 曝光值= " << exposure << endl;
	double width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
	double height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
	//显示尺寸
	cout << ">宽:= " << width << ";  高: =" << height << endl;
#ifdef TRACK_BAR
	exposure = 50 - exposure;
	createTrackbar("曝光值", WINDOW_NAME1, &exposure, 100, onChange);
	onChange(0, 0);
	createTrackbar( "canny阈值", WINDOW_NAME2, &g_nThresh, g_nThresh_max, on_ThreshChange );
	on_ThreshChange( 0, 0 );
#endif
	//【2】循环显示每一帧
	while(1)  
	  
		
		time0 = static_cast<double>(getTickCount( ));//记录起始时间
		capture >> frame;  //读取当前帧
		//若视频播放完成,退出循环
		if (frame.empty())
		
			break;
		
		imshow(WINDOW_NAME1, frame);  //显示当前帧
		//====================获取LED圆心======================
		// 转成灰度并模糊化降噪
		cvtColor( frame, g_grayImage, CV_BGR2GRAY );
		blur( g_grayImage, g_grayImage, Size(3,3) );
		// 用Canny算子检测边缘
		Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );
		// 寻找轮廓
		findContours( g_cannyMat_output, g_vContours, g_vHierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
		// 绘出轮廓或圆心
		if(true == is_new_draw)
		
			//drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
			drawing = Mat( g_cannyMat_output.size(), CV_8UC3, Scalar(255, 255, 255));
			is_new_draw = false;
		
		Scalar color = Scalar(0, 0, 255 );//红色
		for( int i = 0; i < g_vContours.size(); i++ )
		
			
			//drawContours( drawing, g_vContours, i, color, 1, 8, g_vHierarchy, 0, Point() );
			//对给定的 2D 点集,寻找最小面积的包围圆
			minEnclosingCircle(Mat(g_vContours[i]), center, radius);
			//画出圆心
			circle( drawing, center, 1, color, CV_FILLED, CV_AA );
			//绘制出最小面积的包围圆
			//circle(drawing, center, cvRound(radius), color, 1, CV_AA);
		
		// 显示效果图
		imshow( WINDOW_NAME2, drawing );
		//显示帧率
		cout << ">帧率= " << getTickFrequency() / (getTickCount() - time0) << endl;
		char c = (char)waitKey(10);
		if( c == 27 )
			break;
	  
	return 0;     
  
#ifdef TRACK_BAR
void onChange(int pos, void* userdata)

	exposure = 50 - exposure;	
	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);

//-----------------------------------【on_ThreshChange( )函数】------------------------------  
//      描述:回调函数
//----------------------------------------------------------------------------------------------  
void on_ThreshChange(int, void* )

	;

#endif

上面的代码,如果曝光值调的比较高,会检测到多个轮廓,于是会得到多个圆心点。所以我们需要把曝光值调整到一个合适的值,让画面中只剩下LED光点,那么这个时候其实就只有一个轮廓,也就只有一个圆形点,我们可以修改代码,只打印第一个圆心点:

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序07
//		程序描述:使用VideoCapture类调用摄像头读入视频并显示
//		开发测试所用操作系统: Windows 7 64bit
//		开发测试所用IDE版本:Visual Studio 2010
//		开发测试所用OpenCV版本:	2.4.9
//		2014年03月 Created by @浅墨_毛星云
//		2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------
//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2\\opencv.hpp>  
using namespace cv;  
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"			//为窗口标题定义的宏 
#define WINDOW_NAME2 "【LED轨迹图】"			//为窗口标题定义的宏 
#define TRACK_BAR
//【1】从摄像头读入视频
VideoCapture capture;
Mat frame;  //定义一个Mat变量,用于存储每一帧的图像
double time0;
int exposure = -10;
Mat g_srcImage; 
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
#ifdef TRACK_BAR
//滑动条回调函数
void onChange(int pos, void* userdata);
void on_ThreshChange(int, void* );
#endif
//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main( )  
  
	//对给定的 2D 点集,寻找最小面积的包围圆
	Point2f prev_center;
	Point2f center;
	float radius = 0;
	//用来绘制圆心点
	Mat drawing;
	//drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
	//drawing = Mat( g_cannyMat_output.size(), CV_8UC3, Scalar(255, 255, 255));
	//当前摄像头的分辨率最大就是640x480
	drawing = Mat( Size(640, 480), CV_8UC3, Scalar(255, 255, 255));
	Scalar color = Scalar(0, 0, 255 );//红色
	frame = imread("1.jpg", 0);
	// 创建窗口
	namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );
	namedWindow( WINDOW_NAME2, CV_WINDOW_AUTOSIZE );
	imshow( WINDOW_NAME1, frame );
	imshow( WINDOW_NAME2, frame );  //显示当前帧
	waitKey(1000);
	capture.open(0);
	if(false == capture.isOpened())
	
		return -1;
		
	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);
	exposure = capture.get(CV_CAP_PROP_EXPOSURE);
	//显示曝光值
	cout << ">设置后: 曝光值= " << exposure << endl;
	double width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
	double height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
	//显示尺寸
	cout << ">宽:= " << width << ";  高: =" << height << endl;
#ifdef TRACK_BAR
	exposure = 50 - exposure;
	createTrackbar("曝光值", WINDOW_NAME1, &exposure, 100, onChange);
	onChange(0, 0);
	createTrackbar( "canny阈值", WINDOW_NAME2, &g_nThresh, g_nThresh_max, on_ThreshChange );
	on_ThreshChange( 0, 0 );
#endif
	//【2】循环显示每一帧
	while(1)  
	  
		
		time0 = static_cast<double>(getTickCount( ));//记录起始时间
		capture >> frame;  //读取当前帧
		//若视频播放完成,退出循环
		if (frame.empty())
		
			break;
		
		imshow(WINDOW_NAME1, frame);  //显示当前帧
		//====================获取LED圆心======================
		// 转成灰度并模糊化降噪
		cvtColor( frame, g_grayImage, CV_BGR2GRAY );
		blur( g_grayImage, g_grayImage, Size(3,3) );
		// 用Canny算子检测边缘
		Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );
		// 寻找轮廓
		findContours( g_cannyMat_output, g_vContours, g_vHierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
		// 绘出轮廓或圆心
		//for( int i = 0; i < g_vContours.size(); i++ )
		if(g_vContours.size() > 0)
		
			
			//drawContours( drawing, g_vContours, i, color, 1, 8, g_vHierarchy, 0, Point() );
			//先只考虑对第一个轮廓
			//对给定的 2D 点集,寻找最小面积的包围圆
			minEnclosingCircle(Mat(g_vContours[0]), center, radius);
			//画出圆心
			circle( drawing, center, 1, color, CV_FILLED, CV_AA );
			//绘制出最小面积的包围圆
			//circle(drawing, center, cvRound(radius), color, 1, CV_AA);
		
		// 显示效果图
		imshow( WINDOW_NAME2, drawing );
		//显示帧率
		cout << ">帧率= " << getTickFrequency() / (getTickCount() - time0) << endl;
		char c = (char)waitKey(10);
		if( c == 27 )
			break;
	  
	return 0;     
  
#ifdef TRACK_BAR
void onChange(int pos, void* userdata)

	exposure = 50 - exposure;	
	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);

//-----------------------------------【on_ThreshChange( )函数】------------------------------  
//      描述:回调函数
//----------------------------------------------------------------------------------------------  
void on_ThreshChange(int, void* )

	;

#endif


再增加一个鼠标双击回调函数,清空所有圆心点,重新打印:


//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//-----------------------------------------------------------------------------------------
#include <opencv2\\opencv.hpp>  
using namespace cv;  
using namespace std;

#define WINDOW_NAME1 "【原始图窗口】"			//为窗口标题定义的宏 
#define WINDOW_NAME2 "【LED轨迹图】"			//为窗口标题定义的宏 

//-----------------------------------------------------------------------------------------
// 全局变量
//-----------------------------------------------------------------------------------------

//从摄像头读入视频
VideoCapture capture;

//计算帧率
double time0;

//曝光值
int exposure = -10;			

//作为绘制圆心点的画布
Mat drawing;

//用于存储摄像头的每一帧图像
Mat g_srcImage; 

//用于存储灰度化处理后的图像
Mat g_grayImage;

//用于存储canny算法的结果
Mat g_cannyMat_output;

//canny阈值和最大值
int g_nThresh = 80;
int g_nThresh_max = 255;

//轮廓向量集
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;


//-----------------------------------------------------------------------------------------
// 局部函数声明
//-----------------------------------------------------------------------------------------
//曝光值变化回调函数
void onExposureChange(int pos, void* userdata);

//canny阈值变化回调函数
void onThreshChange(int, void* );

//鼠标回调函数
void onMouseCallback(int event, int x, int y, int flags, void* userdata);



//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//----------------------------------------------------------------------------------------------
int main( )  
  
	Point2f prev_center;			//上一次计算出来的中心点
	Point2f center;					//当前计算的中心点
	float radius = 0;				//最小包围圆的半径
	bool first_detect = true;	
	
	//当前摄像头的分辨率最大就是640x480
	drawing = Mat( Size(640, 480), CV_8UC3, Scalar(255, 255, 255));
	Scalar color = Scalar(0, 0, 255 );//红色

	//先加载一张图片,以灰度模式加载
	g_srcImage = imread("1.jpg", 0);
	if (g_srcImage.empty())
	
		return -1;
	

	// 创建窗口
	namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );
	namedWindow( WINDOW_NAME2, CV_WINDOW_AUTOSIZE );
	imshow( WINDOW_NAME1, g_srcImage );
	imshow( WINDOW_NAME2, g_srcImage );  //显示当前帧
	waitKey(1000);

	//打开摄像头
	capture.open(0);
	if(false == capture.isOpened())
	
		return -1;
		

	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);

	exposure = capture.get(CV_CAP_PROP_EXPOSURE);
	//显示曝光值
	cout << ">设置后: 曝光值= " << exposure << endl;

	double width = capture.get(CV_CAP_PROP_FRAME_WIDTH);
	double height = capture.get(CV_CAP_PROP_FRAME_HEIGHT);

	//显示尺寸
	cout << ">宽:= " << width << ";  高: =" << height << endl;


	exposure = 50 - exposure;
	createTrackbar("曝光值", WINDOW_NAME1, &exposure, 100, onExposureChange);
	onExposureChange(0, 0);

	createTrackbar( "canny阈值", WINDOW_NAME2, &g_nThresh, g_nThresh_max, onThreshChange );
	onThreshChange( 0, 0 );


	//鼠标回调函数——双击清空图片
	setMouseCallback(WINDOW_NAME2, onMouseCallback);

	//循环处理每一帧
	while(1)  
	  
		
		time0 = static_cast<double>(getTickCount( ));//记录起始时间

		capture >> g_srcImage;  //读取当前帧
		//若视频播放完成,退出循环
		if (g_srcImage.empty())
		
			break;
		

		imshow(WINDOW_NAME1, g_srcImage);  //显示当前帧

		//====================获取LED圆心======================
		// 转成灰度并模糊化降噪
		cvtColor( g_srcImage, g_grayImage, CV_BGR2GRAY );
		blur( g_grayImage, g_grayImage, Size(3,3) );

		// 用Canny算子检测边缘
		Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );

		// 寻找轮廓
		findContours( g_cannyMat_output, g_vContours, g_vHierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

		// 绘出轮廓或圆心
		//for( int i = 0; i < g_vContours.size(); i++ )
		if(g_vContours.size() > 0)
		
			
			//先只考虑对第一个轮廓
			//对给定的 2D 点集,寻找最小面积的包围圆
			minEnclosingCircle(Mat(g_vContours[0]), center, radius);

			if(true == first_detect)
			
				prev_center = center;
				first_detect = false;
			

			//用当前的圆心和前一次检测的圆心画线
			line(drawing, center, prev_center, color, 1, CV_AA);

			//保存当前的圆心,下次用
			prev_center = center;
			
		

		// 显示效果图
		imshow( WINDOW_NAME2, drawing );

		//显示帧率
		cout << ">帧率= " << getTickFrequency() / (getTickCount() - time0) << endl;

		char c = (char)waitKey(10);
		if( c == 27 )
			break;
	  

	return 0;     
  

//将Mat中的每个元素设置为某个数值
void setMatInt(Mat & input_image, uchar val)

	//行数
	int rows = input_image.rows;
	
	//列数x通道数=每一行的元素个数
	int cols = input_image.cols * input_image.channels();

	for(int i = 0; i< rows; i++)
	
		uchar *pdata = input_image.ptr<uchar>(i);
		for(int j = 0; j < cols; j++)
		
			pdata[j] = val;
		
	




//曝光值变化回调函数
void onExposureChange(int pos, void* userdata)

	exposure = 50 - exposure;	
	//设置曝光值
	capture.set(CV_CAP_PROP_EXPOSURE, exposure);


void onThreshChange(int, void* )

	;


//鼠标回调函数
void onMouseCallback(int event, int x, int y, int flags, void* userdata)

	if(event == EVENT_LBUTTONDBLCLK)
	
		setMatInt(drawing, 255);
	



这样就比较完美了!


代码整理打包上传:

1. 基于《Win7 64bits + Visual Studio 2012 + OpenCV 2.4.10 》的代码

http://download.csdn.net/detail/luoyouren/9736553


2. 基于《Win7 64bits + Qt 5.3.0 MinGW 32bit + OpenCV 2.4.10 》的代码

http://download.csdn.net/detail/luoyouren/9736660











以上是关于图像识别(10)——UVC预览+曝光滑动调节+Canny阈值调节+圆心打点的主要内容,如果未能解决你的问题,请参考以下文章

android studio USB UVC摄像头 预览 失败

工业相机里面的调节曝光时间还有增益是啥意思

Python+OpenCv实现图像边缘检测(滑动调节阈值)

相机曝光与增益

UVCAndroid,安卓UVC相机通用开发库(支持多预览和多摄像头)

图像识别(13)——手势识别——用matchShapes识别手形数字