OpenCV顏色識別
彩色模型
數字影象處理中常用的採用模型是RGB(紅,綠,藍)模型和HSV(色調,飽和度,亮度),RGB廣泛應用於彩色監視器和彩色視訊攝像機,我們平時的圖片一般都是RGB模型。而HSV模型更符合人描述和解釋顏色的方式,HSV的彩色描述對人來說是自然且非常直觀的。
HSV模型
HSV模型中顏色的引數分別是:色調(H:hue),飽和度(S:saturation),亮度(V:value)。由A. R. Smith在1978年建立的一種顏色空間, 也稱六角錐體模型(Hexcone Model)。 色調(H:hue):用角度度量,取值範圍為0°~360°,從紅色開始按逆時針方向計算,紅色為0°,綠色為120°,藍色為240°。它們的補色是:黃色為60°,青色為180°,品紅為300°; 飽和度(S:saturation):取值範圍為0.0~1.0,值越大,顏色越飽和。 亮度(V:value):取值範圍為0(黑色)~255(白色)。
RGB轉HSV
設 (r, g, b) 分別是一個顏色的紅、綠和藍座標,它們的值是在 0 到 1 之間的實數。設 max 等價於 r, g 和 b 中的最大者。設 min 等於這些值中的最小者。要找到在 HSV 空間中的 (h, s, v) 值,這裡的 h ∈ [0, 360)是角度的色相角,而 s, v ∈ [0,1] 是飽和度和亮度,計算為:
max=max(R,G,B) min=min(R,G,B) if R = max, H = (G-B)/(max-min) if G = max, H = 2 + (B-R)/(max-min) if B = max, H = 4 + (R-G)/(max-min) H = H * 60 if H < 0, H = H + 360 V=max(R,G,B) S=(max-min)/max
OpenCV下有個函式可以直接將RGB模型轉換為HSV模型,注意的是OpenCV中H∈ [0, 180), S ∈ [0, 255], V ∈ [0, 255]。我們知道H分量基本能表示一個物體的顏色,但是S和V的取值也要在一定範圍內,因為S代表的是H所表示的那個顏色和白色的混合程度,也就說S越小,顏色越發白,也就是越淺;V代表的是H所表示的那個顏色和黑色的混合程度,也就說V越小,顏色越發黑。經過實驗,識別藍色的取值是 H在100到140,S和V都在90到255之間。一些基本的顏色H的取值可以如下設定:
Orange 0-22 Yellow 22- 38 Green 38-75 Blue 75-130 Violet 130-160 Red 160-179
OpenCV實現 首先我們讀取一張圖片或從視訊讀取一幀影象,用下面的函式轉為HSV模型。
cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV);
然後我們對彩色影象做直方圖均衡化
//因為我們讀取的是彩色圖,直方圖均衡化需要在HSV空間做
split(imgHSV, hsvSplit);
equalizeHist(hsvSplit[2],hsvSplit[2]);
merge(hsvSplit,imgHSV);
接著就是進行顏色檢測,我們用void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);函式進行顏色檢測,這個函式的作用就是檢測src影象的每一個畫素是不是在lowerb和upperb之間,如果是,這個畫素就設定為255,並儲存在dst影象中,否則為0。
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);
整個程式碼實現
#include <iostream>
#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 web cam" << endl;
return -1;
}
namedWindow("Control", CV_WINDOW_AUTOSIZE); //create a window called "Control"
int iLowH = 100;
int iHighH = 140;
int iLowS = 90;
int iHighS = 255;
int iLowV = 90;
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<Mat> 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);
imshow("Thresholded Image", imgThresholded); //show the thresholded image
imshow("Original", imgOriginal); //show the original image
char key = (char) waitKey(300);
if(key == 27)
break;
}
return 0;
}
實驗結果圖:
顏色識別的應用
經典的顏色識別的經典應用就是車牌定位了,因為中國的車牌無非就是藍色和黃色,還有就是交通標誌定位也是個應用。比如下面兩張圖片,有很明顯的顏色區分。