【opencv】在hsv颜色空间识别区域颜色

大纲


1. hsv颜色空间简介
2. 为什么是HSV
3. 识别方法说明
4. 识别步骤解析(代码片段)
4. 检测结果


一、HSV颜色空间


        由色调(Hue)、饱和度(Saturation)、亮度(Value)三个分量构成,HSV更接近于人眼的主观感受。我们可以通过下面的图来展示HSV颜色分布情况:



    使用了下面的matlab程序画出上面的图形,感兴趣的可以仿真一下。程序很简单。

% 创建hsv分量
hue        = repmat(linspace(0,1,100),100,1);
saturation = repmat([linspace(0,1,50) linspace(1,0,50)].',1,100);
value      = repmat([ones(1,50) linspace(1,0,50)].',1,100);
% 生成hsv图像
hsvImage = cat(3,hue,saturation,value); 
% 转换成rgb图像
rgbImage = hsv2rgb(hsvImage); 


% 构造座标系
theta = linspace(0,2*pi,100);  
Xcor = [zeros(1,100); cos(theta); zeros(1,100)];
Ycor = [zeros(1,100); sin(theta); zeros(1,100)];
Zcor = [2.*ones(2,100); zeros(1,100)];


surf(Xcor,Ycor,Zcor,rgbImage,'Clipping','on','FaceColor','texturemap','EdgeColor','none');
axis equal

二、为什么是HSV


        对于图像而言,识别相应的颜色在RGB空间、HSV空间或者其它颜色空间都是可行的。之所以选择HSV,是因为H代表的色调基本上可以确定某种颜色,再结合饱和度和亮度信息判断大于某一个阈值(这里是40到255)。而RGB由三个分量构成,需要判断每种分量的贡献比例。比如:R = 200, G = 20, B = 30,可以看到R值很大,所以是红色,再看GB值相对较小,可以判断为深红色。但如果变成:R = 200, G = 190, B = 180,实际上颜色已经接近灰色。



三、识别方法说明


        基本原理很简单,读入图片后,首先转换成HSV颜色空间。然后逐一的判断每个像素是否在一定范围内,并标识出来(是就标识为255,不是就标识为0)。这样就可以用查找轮廓的方式,把每个颜色区域标识出来。


四、识别步骤解析(代码片段)


1. 读入待测试图片,并预览。

	image = imread("test4.png", CV_LOAD_IMAGE_COLOR);
	if (!image.data)
	{
		cout << "Could not open or find the image" << std::endl;
		getchar();
		return -1;
	}
	imshow("Display image", image);

2.  默认读入的颜色空间为RGB,这里首先转换成HSV。

cvtColor(image, hsvImg, COLOR_BGR2HSV);


3. 指定识别颜色的取值范围,这里大概的分成了R、G、B三种色彩,如果需要识别更多颜色,可以增加取值,也可以调整值的范围,满足特定需要。

enum colorType{Red = 0, Green, Blue, ColorButt};

const Scalar hsvRedLo( 0,  40,  40);
const Scalar hsvRedHi(40, 255, 255);

const Scalar hsvGreenLo(41,  40,  40);
const Scalar hsvGreenHi(90, 255, 255);

const Scalar hsvBlueLo(100,  40,  40);
const Scalar hsvBlueHi(140, 255, 255);

vector<Scalar> hsvLo{hsvRedLo, hsvGreenLo, hsvBlueLo};
vector<Scalar> hsvHi{hsvRedHi, hsvGreenHi, hsvBlueHi};

vector<String> textColor{"R", "G", "B"};

 4. 针对每一种颜色,做下面的几个步骤。

1)在图片中查找相关颜色,并转换成二值图

        // 查找指定范围内的颜色
        inRange(hsvImg, hsvLo[colorIdx], hsvHi[colorIdx], imgThresholded);
        // 转换成二值图
        threshold(imgThresholded, imgThresholded, 1, 255, THRESH_BINARY);

2)将所得的二值图像四边都增加一个像素,再查找轮廓。这样做的一个明显情况是当图像为纯色的时候,整图只有一种颜色的判断。当然可能还有各种情况,需要分别判断。

        copyMakeBorder(imgThresholded, imag_1, 1, 1, 1, 1, BORDER_CONSTANT, 0);
        vector<vector<Point> > contours0;
        vector<Vec4i> hierarchy;
        findContours(imag_1, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

3) 检查所有的轮廓中心点,如果非0,判断为所需要查找的颜色区域,用文本标记颜色。如蓝色标记为字母‘B’。

        for (int idx = 0; idx < contours0.size(); idx++ )
        {
            Rect bound = boundingRect(Mat(contours0[idx]));
            Point bc = Point(bound.x + bound.width / 2,
                             bound.y + bound.height / 2);
            uchar x = imgThresholded.at<uchar>(bc);

            if (x > 0)
            {
                org = bc;
                putText(image, textColor[colorIdx], org, fontFace, 1, color,
                thickness, lineType, bottomLeftOrigin);
            }
        }

5. 重复上面步骤,直到所有颜色都识别完毕。


五、检测结果


        用excel画的颜色图,图中可以看到颜色都正确的标识了。第三行不是没有识别出来,而是字母的颜色与本来的颜色一样,这里懒得设置了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章