本次来我们用opencv来实现识别跟踪蓝色物体并返回位置坐标的功能。
该功能分为两部分,识别颜色,跟踪颜色。
要想实现颜色的识别,我们要打开摄像头,读取捕获的图像。将图像的颜色通道转化为HSV,设置选取的特定颜色的参数。使用inRange函数将图像转变为二值图,其中蓝色部分显示为白色,其余为黑色。
代码:
VideoCapture cap(0);//打开摄像头
if ( !cap.isOpened() )
{
cout << "Cannot open the camera" << endl;
return -1;
}
int iLowH = 100; int iHighH = 140; int iLowS = 90; int iHighS = 255; int iLowV = 90; int iHighV = 255;//设置蓝色的颜色参量。
Mat imgOriginal; bool bSuccess = cap.read(imgOriginal); if (!bSuccess) { cout << "Cannot read a frame from video stream" << endl; break; } Mat imgHSV; vectorhsvSplit;
cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV); //因为我们读取的是彩色图,直方图均衡化需要在HSV空间做
split(imgHSV, hsvSplit);
equalizeHist(hsvSplit[2],hsvSplit[2]);
merge(hsvSplit,imgHSV);
Mat imgThresholded;
inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded); //开操作 (去除一些噪点)
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
morphologyEx(imgThresholded, imgThresholded, MORPH_OPEN, element); //闭操作 (连接一些连通域)
morphologyEx(imgThresholded, imgThresholded, MORPH_CLOSE, element);
//对灰度图进行滤波
GaussianBlur(imgThresholded,imgThresholded, Size(3, 3), 0, 0);
imshow("滤波后的图像", imgThresholded);
颜色识别过程至此结束。
要想跟踪蓝色,将其在原图像中用矩形框出,首先要将二值图中白色的轮廓描出
Mat cannyImage;
Canny(imgThresholded, cannyImage, 128, 255, 3);
接下来就是使用vector计算出外边缘的像素个数,之后再用矩形框圈出。并在中心画出十字,返回十字的坐标。
vector> contours; vectorhierarchy; findContours(cannyImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); //绘制轮廓 for (int i = 0; i < (int)contours.size(); i++) { drawContours(cannyImage, contours, i, Scalar(255), 1, 8); } imshow("处理后的图像", cannyImage); //用矩形圈出轮廓并返回位置坐标 for(int i=0;ipoints=contours[i];
//对给定的2D点集,寻找最小面积的包围矩形
RotatedRect box=minAreaRect(Mat(points));
Point2f vertex[4];
box.points(vertex);
//绘制出最小面积的包围矩形
line(imgOriginal,vertex[0],vertex[1],Scalar(100,200,211),6,LINE_AA);
line(imgOriginal,vertex[1],vertex[2],Scalar(100,200,211),6,LINE_AA);
line(imgOriginal,vertex[2],vertex[3],Scalar(100,200,211),6,LINE_AA);
line(imgOriginal,vertex[3],vertex[0],Scalar(100,200,211),6,LINE_AA);
//绘制中心的光标
Point s1,l,r,u,d;
s1.x=(vertex[0].x+vertex[2].x)/2.0;
s1.y=(vertex[0].y+vertex[2].y)/2.0;
l.x=s1.x-10;
l.y=s1.y;
r.x=s1.x+10;
r.y=s1.y;
u.x=s1.x;
u.y=s1.y-10;
d.x=s1.x;
d.y=s1.y+10;
line(imgOriginal,l,r,Scalar(100,200,211),2,LINE_AA);
line(imgOriginal,u,d,Scalar(100,200,211),2,LINE_AA);
cout<<"Blue\n"<<"( "<<x<<","<<y<<" )"<<endl;
但是这个代码的功能还是远远不够,后期可考虑增强功能,如只显示最大的矩形,自动根据光照来改变阈值来应对不同颜色状况下的情况。总之,有点那个意思了,再接再厉。
完整代码(文本有缺失,上传图片)
爱你呦,方宇。