利用OpenCV检测特定颜色的物体

下载本文PDF 版本:链接:https://pan.baidu.com/s/1rXHySccGioWhNYLMmgi5BQ 
提取码:73ey 
 

1.    需求

利用摄像头实时检测一个红色的小球

2.    原料/前期准备

装有OpenCV的树莓派(OpenCV2.4.9)

树莓派摄像头模块(可以用罗技的USB摄像头代替)

3.    原理/实施步骤

a、最初的头文件和定义两个命名空间cvstd

#include   
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  

using namespace cv;  
using namespace std;  

 

 

b、为了实时检测小球的位置,我们首先需要打开树莓派的摄像头(PiCamera)

 

 

 

VideoCapture cap(0); //capture the video from web cam 

if ( !cap.isOpened() )  // if not success, exit program 
{ 
cout << "Cannot open the  cam" << endl; 
return -1; 
} 

 

 

如果使用的是USB摄像头,需要将VideoCapturecap(0)中的0改1。

 

如果opencv提供的cvCaptureFromCAM(0)函数无法找到Pi Cam但是换上普通usb摄像头之后就可以打开摄像头。运行起来就会发现找不到/dev/video0设备,但是树莓派官方自带的raspistill却能够用起来,这怎么回事呢?

树莓派中的camera module是放在/boot/目录下以固件的形式加载的,不是一个标准的v4l2的摄像头ko驱动,所以加载起来之后会找不到/dev/video0的设备节点,这是因为这个驱动是在底层的,v4l2这个驱动框架还没有加载,所以要在/etc/下面的modules-load.d/rpi-camera.conf里面添加一行bcm2835-v4l2,这句话意思是在系统启动之后会加载这个文件中模块名,这个模块会在树莓派系统的/lib/modules/xxx/xxx/xxx下面,添加之后重启系统,就会在/dev/下面发现video0设备节点了。这个文件名可能不是叫modules-load.d/rpi-camera.conf,也有可能直接就是/etc/modules,我用的是树莓派2,就是/etc/modules。
https://wiki.archlinux.org/index.php/Raspberry_Pi,这里讲了很多关于启动的问题,其中Raspberry Pi camera module这一章节就是说如何起camera。

修改/etc/modules,加上一行: bcm2835-v412

如下:

snd-bcm2835

bcm2835-v4l2

(v4l2l 不是1 )

然后重启, ls -l /dev/video0,应该能找到。

 

c、从摄像头中实时取图

 

Mat imgOriginal; 

bool bSuccess = cap.read(imgOriginal); // read a new frame from video 

if (!bSuccess) //if not success, break loop 

{ 

cout << "Cannot read a frame from video stream" << endl; 

}

 

 

这里声明了一个Mat型的图像imgOriginal,之后有一个名为bSuccess的bool变量,用于判断取图是否成功。

 

d、识别红色

通过控制RGB通道很难找到红色的准确范围,于是我们选用HSV空间。HSV(Hue, Saturation,Value)是根据颜色的直观特性而创建的一种颜色空间,

H:色调          S:饱和度         V:明度

利用OpenCV检测特定颜色的物体_第1张图片

这是一个模糊范围,把部分紫色归为红色

 

Mat imgHSV; 

vector hsvSplit; 

cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV);

//Convert the captured frame from BGR to HSV

 

split(imgHSV, hsvSplit); 

equalizeHist(hsvSplit[2],hsvSplit[2]); 

merge(hsvSplit,imgHSV);

 


imgHSV是将imgOriginal的RGB空间转换为HSV空间后的得到的图像,之后是分离HSV三通道。cvEqualizeHist函数用于将直方图均衡化,可以将比较淡的图像变换为比较深的图像(即增强图像的亮度及对比度)。cvMerge:把几个单通道图像合并为一个多通道图像,这样我们就获得了一个HSV空间的图像。并且通过调节HSV的值基本可以滤掉所有非红色区域。

 

e、二值化

二值化是将彩色图片转换文纯黑纯白,cvCvtColor可以将图片转为灰度图,但是不是二值图。CvThreshold是二值化函数。获得的图片原红色部分是白色,其余部分是黑色。

 

f、对红色区域画圆

 

vector circles; 

HoughCircles( imgThresholded, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 ); 

 

for( size_t i = 0; i < circles.size(); i++ ) 

{ 

Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 

int radius = cvRound(circles[i][2]); 

//绘制圆心 

circle( imgThresholded, center, 3, Scalar(0,255,0), -1, 8, 0 ); 

//绘制圆轮廓 

circle( imgThresholded, center, radius, Scalar(155,50,255), 3, 8, 0 ); 

}
 

 

首先用霍夫圆变换检测圆:cvHougeCircles函数有这样几个参数:第一个是输入图片,第二个是内存,第三个是方式、算法,第

四个是分辨率:设为1的时候分辨率相同,2分辨率为一般,第五个是让算法能明显区分的两个圆之间的最小距离。之后两个是阈值,

之后是能发现的圆的半径最大值和最小值。cvPointOpenCV中的数据类型,表示二维中的点。center是圆心。其实绘制圆心和绘

制圆是一回事,用的都是cvCircle函数,只是绘制的圆半径为0的时候,就变成了绘制圆心。
 

g、其他

由于不同时间光线条件不同,最好能有一个控制界面实时调节HSV使得识别红色的效果达到最好。OpenCV有专门的图形界面编写函数,写起来也很方便。

4.代码

 

 

#include  

#include "opencv2/highgui/highgui.hpp" 

#include "opencv2/imgproc/imgproc.hpp" 

using namespace cv; 

using namespace std; 

int main( int argc, char** argv ) 

 { 

       VideoCapture cap(0); //capture the video from web cam 

       if ( !cap.isOpened() )  // if not success, exit program 

       { 

         cout << "Cannot open the  cam" << endl; 

         return -1; 

        }

        namedWindow("Control", CV_WINDOW_AUTOSIZE);

//create a window called "Control" 

        int iLowH = 156; 

        int iHighH = 180; 

        int iLowS = 43;  

        int iHighS = 255; 

        int iLowV = 46; 

        int iHighV = 255; 

        //Create trackbars in "Control" window 

        cvCreateTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179) 

        cvCreateTrackbar("HighH", "Control", &iHighH, 179); 

        cvCreateTrackbar("LowS", "Control", &iLowS, 255);

//Saturation (0 - 255) 

        cvCreateTrackbar("HighS", "Control", &iHighS, 255); 

        cvCreateTrackbar("LowV", "Control", &iLowV, 255);

//Value (0 - 255) 

        cvCreateTrackbar("HighV", "Control", &iHighV, 255); 

        while (true) 

        { 

          Mat imgOriginal; 

          bool bSuccess = cap.read(imgOriginal);

// read a new frame from video 

          if (!bSuccess) //if not success, break loop 

           { 

             cout << "Cannot read a frame from video stream" << endl; 

             break; 

            } 

        Mat imgHSV; 

        vector hsvSplit; 

        cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV);

//Convert the captured frame from BGR to HSV 

         //因为我们读取的是彩色图,直方图均衡化需要在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); //Threshold the image 

        /* //开操作 (去除一些噪点) 

        Mat element = getStructuringElement(MORPH_RECT, Size(5, 5)); 

        morphologyEx(imgThresholded, imgThresholded, MORPH_OPEN, element); 

        //闭操作 (连接一些连通域) 

        morphologyEx(imgThresholded, imgThresholded, MORPH_CLOSE, element); 

          */

        vector circles; 

        HoughCircles( imgThresholded, circles, CV_HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 ); 

        //依次在图中绘制出圆 

        for( size_t i = 0; i < circles.size(); i++ ) 

         { 

            Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 

            int radius = cvRound(circles[i][2]); 

             //绘制圆心 

            circle( imgThresholded, center, 3, Scalar(0,255,0), -1, 8, 0 ); 

             //绘制圆轮廓 

            circle( imgThresholded, center, radius, Scalar(155,50,255), 3, 8, 0 ); 

           }

         imshow("Thresholded Image", img); //show the thresholded image 

         imshow("Original", imgOriginal); //show the original image 

         char key = (char) waitKey(300); 

         if(key == 27) 

         break; 

         } 

    return 0; 

} 

 


5.一些注意事项

要先识别颜色再识别形状。

树莓派的摄像头存在打不开的情况,首选重启(reboot)。

窗口显示有延迟。

6.扫描二维码有惊喜

利用OpenCV检测特定颜色的物体_第2张图片

你可能感兴趣的:(树莓派)