1. 程式人生 > >OpenCV顏色識別

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;
 
}

實驗結果圖:

顏色識別的應用

經典的顏色識別的經典應用就是車牌定位了,因為中國的車牌無非就是藍色和黃色,還有就是交通標誌定位也是個應用。比如下面兩張圖片,有很明顯的顏色區分。