图像识别(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摄像头 预览 失败