大纲

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

一、HSV颜色空间

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

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

[plain] 
view plain  
copy

  1. % 创建hsv分量  
  2. hue        = repmat(linspace(0,1,100),100,1);  
  3. saturation = repmat([linspace(0,1,50) linspace(1,0,50)].',1,100);  
  4. value      = repmat([ones(1,50) linspace(1,0,50)].',1,100);  
  5. % 生成hsv图像  
  6. hsvImage = cat(3,hue,saturation,value);   
  7. % 转换成rgb图像  
  8. rgbImage = hsv2rgb(hsvImage);   
  9.   
  10.   
  11. % 构造坐标系  
  12. theta = linspace(0,2*pi,100);    
  13. Xcor = [zeros(1,100); cos(theta); zeros(1,100)];  
  14. Ycor = [zeros(1,100); sin(theta); zeros(1,100)];  
  15. Zcor = [2.*ones(2,100); zeros(1,100)];  
  16.   
  17.   
  18. surf(Xcor,Ycor,Zcor,rgbImage,'Clipping','on','FaceColor','texturemap','EdgeColor','none');  
  19. 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. 读入待测试图片,并预览。

[cpp] 
view plain  
copy

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

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

[cpp] 
view plain  
copy

  1. cvtColor(image, hsvImg, COLOR_BGR2HSV);  

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

[cpp] 
view plain  
copy

  1. enum colorType{Red = 0, Green, Blue, ColorButt};  
  2.   
  3. const Scalar hsvRedLo( 0,  40,  40);  
  4. const Scalar hsvRedHi(40, 255, 255);  
  5.   
  6. const Scalar hsvGreenLo(41,  40,  40);  
  7. const Scalar hsvGreenHi(90, 255, 255);  
  8.   
  9. const Scalar hsvBlueLo(100,  40,  40);  
  10. const Scalar hsvBlueHi(140, 255, 255);  
  11.   
  12. vector<Scalar> hsvLo{hsvRedLo, hsvGreenLo, hsvBlueLo};  
  13. vector<Scalar> hsvHi{hsvRedHi, hsvGreenHi, hsvBlueHi};  
  14.   
  15. vector<String> textColor{ "R""G""B"};  

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

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

[cpp] 
view plain  
copy

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

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

[cpp] 
view plain  
copy

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

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

[cpp] 
view plain  
copy

  1. for (int idx = 0; idx < contours0.size(); idx++ )  
  2. {  
  3.     Rect bound = boundingRect(Mat(contours0[idx]));  
  4.     Point bc = Point(bound.x + bound.width / 2,  
  5.                      bound.y + bound.height / 2);  
  6.     uchar x = imgThresholded.at<uchar>(bc);  
  7.   
  8.     if (x > 0)  
  9.     {  
  10.         org = bc;  
  11.         putText(image, textColor[colorIdx], org, fontFace, 1, color,  
  12.         thickness, lineType, bottomLeftOrigin);  
  13.     }  
  14. }  

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

五、检测结果

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

声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。