1. 程式人生 > >OpenCV顏色轉換和面板檢測

OpenCV顏色轉換和面板檢測

本筆記重點記錄OpenCV中的顏色轉換和利用色彩空間的特性進行面板檢測

顏色轉換

實現原理

之所以要引入色調/飽和度/亮度的色彩空間概念,是因為人們喜歡憑直覺分辨各種顏色,而它與這種方式吻合。實際上,人類更喜歡用色彩、彩度、亮度等直觀的屬性來描述顏色,而大多 數直覺色彩空間正是基於這三個屬性。

  • 色調(hue)表示主色,我們使用的顏色名稱(例如綠色、 黃色和紅色)就對應了不同的色調值;
  • 飽和度(saturation)表示顏色的鮮豔程度,柔和的顏色飽 和度較低,而彩虹的顏色飽和度就很高
  • 亮度(brightness)是一個主觀的屬性,表示某種 顏色的光亮程度。

其他直覺色彩空間使用顏色明度(value)或顏色亮度(lightness)的概念描述 有關顏色的強度。

利用這些顏色概念,能儘可能地模擬人類對顏色的直觀感知。因此,它們沒有標準的定義。 根據文獻資料,色調、飽和度和亮度都有多種不同的定義和計算公式。OpenCV 建議的兩種直覺 色彩空間的實現是 HSV 和 HLS 色彩空間,它們的轉換公式略有不同,但是結果非常相似。

亮度成分可能是最容易解釋的。在 OpenCV 對 HSV 的實現中,它被定義為三個 BGR 成分中 的最大值,以非常簡化的方式實現了亮度的概念。為了讓定義更符合人類視覺系統,應該使用均 勻感知的色彩空間 Lab和 Luv的 L 通道。舉個例子,L 通道已經考慮到了,在強度相同的 情況下,人們會覺得綠色比藍色等顏色的亮度更高。

OpenCV 用一個公式來計算飽和度,該公式基於 BGR 元件的最小值和最大值:

其原理是:灰度顏色包含的 R、G、B 的成分是相等的,相當於一種極不飽和的顏色,因此 它的飽和度是 0(飽和度是一個 0~1.0 的值)。對於 8 點陣圖像,飽和度被調節成一個 0~255 的值, 並且作為灰度影象顯示的時候,較亮區域對應的顏色具有較高的飽和度。

利用opencv把RGB圖片像HSV顏色空間轉變(CV_BGR2HSV)的時候,

H通道的值範圍為: 0-180

S: 0-255

V:0-255

實現程式碼


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <vector>

int main()
{
    // 讀入影象
    cv::Mat image= cv::imread("boldt.jpg");
    if (!image.data)
        return 0;

    // 原始影象
    cv::namedWindow("Original image");
    cv::imshow("Original image",image);

    // 轉換成HSV色彩空間
    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);

    // 把三個通道分割進三幅影象中
    std::vector<cv::Mat> channels;
    cv::split(hsv,channels);
    // channels[0] 色調
    // channels[1] 飽和度
    // channels[2] 亮度

    // 亮度
    cv::namedWindow("Value");
    cv::imshow("Value",channels[2]);

    // display 飽和度
    cv::namedWindow("Saturation");
    cv::imshow("Saturation",channels[1]);

    // display 色調
    cv::namedWindow("Hue");
    cv::imshow("Hue",channels[0]);
    cv::waitKey();
}

實現效果

面板檢測

8 位版本的色調在 0~180,飽和度在 0~255

實現原理

在對特定物體做初步檢測時,顏色資訊非常有用。例如輔助駕駛程式中的路標檢測功能,就要憑藉標準路標的顏色快速識別可能是路標的資訊。另一個例子是膚色檢測,檢測到的面板區域 可作為影象中有人存在的標誌。手勢識別就經常使用膚色檢測確定手的位置。

膚色檢測領域的大量研究已經表明,來自不同人種的人群的面板顏色,可以在色調、飽和度、色彩空間中很好地歸類。

實現程式碼


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <vector>

void detectHScolor(const cv::Mat& image,       // input image
                   double minHue, double maxHue,   // Hue interval
                   double minSat, double maxSat,   // saturation interval
                   cv::Mat& mask) {             // output mask

    // convert into HSV space
    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);

    // split the 3 channels into 3 images
    std::vector<cv::Mat> channels;
    cv::split(hsv, channels);
    // channels[0] is the Hue
    // channels[1] is the Saturation
    // channels[2] is the Value

    // Hue masking
    cv::Mat mask1; // below maxHue
    cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
    cv::Mat mask2; // over minHue
    cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);

    cv::Mat hueMask; // hue mask
    if (minHue < maxHue)
        hueMask = mask1 & mask2;
    else // if interval crosses the zero-degree axis
        hueMask = mask1 | mask2;

    // Saturation masking
    // below maxSat
    cv::threshold(channels[1], mask1, maxSat, 255, cv::THRESH_BINARY_INV);
    // over minSat
    cv::threshold(channels[1], mask2, minSat, 255, cv::THRESH_BINARY);

    cv::Mat satMask; // saturation mask
    satMask = mask1 & mask2;

    // combined mask
    mask = hueMask&satMask;
}

int main()
{
    // 讀入影象
    cv::Mat image= cv::imread("girl.jpg");
    if (!image.data)
        return 0;
    // show original image
    cv::namedWindow("Original image");
    cv::imshow("Original image",image);
    // detect skin tone
    cv::Mat mask;
    detectHScolor(image,
              160, 10, // hue from 320 degrees to 20 degrees
              25, 166, // saturation from ~0.1 to 0.65
              mask);
// show masked image
    cv::Mat detected(image.size(), CV_8UC3, cv::Scalar(0, 0, 0));
    image.copyTo(detected, mask);
    cv::imshow("Detection result",detected);
    cv::waitKey();
}

實現效果

可改進的地方

在檢測時沒有考慮顏色的亮度。在實際應用中,排除較高亮度的顏色可以降低把明亮的淡紅色誤認為面板的可能性。所以要想對面板顏色進行可靠和準確的檢測, 還需要更加精確的分析。對不同的影象進行檢測,也很難保證效果都好,因為攝影時影響彩色再 現的因素有很多,如白平衡和光照條件等。