1. 程式人生 > >【opencv】在hsv顏色空間識別區域顏色

【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畫的顏色圖,圖中可以看到顏色都正確的標識了。第三行不是沒有識別出來,而是字母的顏色與本來的顏色一樣,這裡懶得設定了。