下面的这个应用主要完成的是Verybot跟踪色标的功能,识别部分还是居于OpenCV编写,色标跟踪一般需要将图像的颜色模式进行转换,将RGB转换为HSV,因为对HSV格式下的图像进行识别时受光线的影响比较小,但是也有采用RGB模式来进行识别的情况,这种情况一般光线条件比较固定,背景跟识别物在颜色上很容易区分出来。
下面这个程序的流程大致是这样的:
1、先将颜色模式进行转换,也就是将RGB模式转换为HSV模式;
2、然后将HSV模式下的图像分成H、S、V3个平面;
3、对H通道在识别颜色范围内的点进行标定;
4、对S通道在识别颜色范围内的点进行标定;
5、将H通道标定的点与S通道标定的点进行与运算;
6、对与运算的结果进行腐蚀,去掉离散的点;
7、计算最后识别出的点的几何中心;
8、根据几何中心位置来进行跟踪。
下面是该程序:
#include "cv.h"
#include "highgui.h"
#include "stdio.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char** argv)
{
////////////////////////////////////////////
... //此处省去串口初始化的代码
////////////////////////////////////////////
// cvNamedWindow("vedio",0);
CvCapture* capture;
if(1 == argc)
{
capture = cvCreateCameraCapture(0);
}
else
{
capture = cvCreateCameraCapture(atoi(argv[1]));
}
assert(NULL != capture);
// 设置采集分辨率
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 320);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT,240);
IplImage* frame;
char keyCode;
frame = cvQueryFrame(capture);
if(!frame)
{
printf("sould exit1\n");
return 0;
}
IplImage* gray = cvCreateImage( cvGetSize(frame), 8, 1 );
CvMemStorage* storage = cvCreateMemStorage(0);
IplImage* tHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3); // hsv指向颜色转换为HSV模式以后的图像
IplImage* hc = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1); // 分割之后的H通道数据
IplImage* sc = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1); // 分割之后的S通道数据
IplImage* vc = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1); // 分割之后的V通道数据
IplImage* tH = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1);
IplImage* tS = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
IplImage* tImg=cvCreateImage(cvGetSize(frame),8,3); // 用于存放高斯模糊后的图像
double m00, m10, m01;
CvMoments moment;
int cx, cy;
while((keyCode = cvWaitKey(15)))
{
if(keyCode == 'q')
{
break;
}
frame = cvQueryFrame(capture);
if(!frame)
{
break;
}
cvSmooth(frame,tImg,CV_GAUSSIAN,3,3); // 高斯模糊
cvCvtColor(tImg, tHSV, CV_BGR2HSV ); // 颜色转换
cvCvtPixToPlane(tHSV,hc,sc,vc,0); // 图像分割成H、S、V三个通道
cvInRangeS(hc,cvScalar(60,0.0,0,0),cvScalar(100,0.0,0,0),tH); // 标定H通道在范围内的点
cvInRangeS(sc,cvScalar(70,0.0,0,0),cvScalar(180,0.0,0,0),tS); // 标定S通道在范围内的点
cvAnd(tH,tS,tH,0); // 将H通道在范围内的点与S通道在范围内的点进行与运算
cvErode(tH,tH,NULL,3); // 图像进行腐蚀,去掉离散点
cvMoments( tH, &moment, 1); // 下面这几行代码求标定出的点的几何中心
m00 = cvGetSpatialMoment( &moment, 0, 0 );
if( m00 != 0)
{
m10 = cvGetSpatialMoment( &moment, 1, 0 );
m01 = cvGetSpatialMoment( &moment, 0, 1 );
cx = (int) (m10/m00);
cy = (int) (m01/m00);
// printf("%d ,%d \n",cx,cy);
if((cx>=110)&&(cx<=210))
{
... //机器人前进代码
}
if(cx<110)
{
... //机器人左转代码
}
if(cx>210)
{
... //机器人右转代码
}
}
else //如果找不到目标
{
... //机器人停止代码
}
// cvShowImage("vedio",tmpH1);
}
close(fd);
cvReleaseImage(&frame);
cvDestroyAllWindows();
return 0;
}
这个程序的运行效果还是不错的,效率跟准确度都还不错,只是由于目前使用的摄像头的焦距比较长,视角很小,所以不能将色标移动太远,之后换上广角一些的摄像头,再调整好Verybot的转弯速度,跟踪效果应该会好很多。
下面是Verybot跟踪色标的视频:
http://v.youku.com/v_show/id_XNjYxNjk1MDQ4.html