//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-----------------------------------------------------------------------------------------
#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);
}
}