天天看點

[OpenCV新手向]一個OpenCV顔色空間轉化的執行個體

最近在OpenCV中文論壇上解答了個問題,大概問題是這樣的,把下圖中綠色的八卦部分摳出來:

[OpenCV新手向]一個OpenCV顔色空間轉化的執行個體

可以看出問題解決方案很直接:周遊圖檔的每個像素,然後如果像素的顔色接近于綠色,保留此像素;反之遺棄,設值為0。解決思路跟photoshop的顔色選擇功能類似。

問題主要的難點在于如何去比較顔色。輸入圖像的RGB色彩并不适用于顔色的比較;這裡就要引入HSV色彩空間,把RGB顔色轉化成H色相,S飽和度,V色調(亮度)。根據餅狀圖,我們發現綠色範圍(轉化成0~255區間)大概在35到90之間。是以,周遊過程中,我們留下H通道值在35~90範圍内,并且飽和度和色調足夠高(保證像素足夠明亮)的像素;反之,剩下的我們認為是背景和噪點。

代碼如下:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
void getGreenMask(Mat& src, Mat& dst)
{
	cvtColor(src, dst, cv::COLOR_BGR2HSV);
	int hi = 90, lo = 35;
	int lo_sat_v = 50;
	for(int i = 0; i < src.rows; i ++)
	{
		Vec3b * row_ptr = dst.ptr<Vec3b>(i);
		for(int j = 0; j < src.cols; j ++)
		{
			Vec3b hsv = row_ptr[j];
			if((hsv[1] < lo_sat_v || hsv[2] < lo_sat_v) // 飽和度和亮度過低
				|| (hsv[0] > hi || hsv[0] < lo))        // 色相不在範圍内
			{
				row_ptr[j] = Vec3b::all(0);             // 剔除不在範圍内的像素
			}
		}
	}
	cvtColor(dst, dst, cv::COLOR_HSV2BGR);
}
int main(int argc, char* argv[])
{
	Mat in = imread("F:/test.JPG");
	namedWindow("green channel");
	Mat out(in.size(), CV_8UC3, Scalar::all(0));
	getGreenMask(in, out);
	imshow("green channel", out);
	waitKey();
    return 0;
}
           

效果如下圖:

[OpenCV新手向]一個OpenCV顔色空間轉化的執行個體