1. 程式人生 > 程式設計 >opencv之顏色過濾只留下圖片中的紅色區域操作

opencv之顏色過濾只留下圖片中的紅色區域操作

如圖,這次需要在圖片中找到捲尺的紅色刻度,所以需要對影象做過濾,只留下紅色部分。

opencv之顏色過濾只留下圖片中的紅色區域操作

一開始的想法是分別找到RGB值,然後找到紅色區域的部分保留就可以了,不過好像很難確定紅色區域的RGB取值範圍,所以要把圖片轉化到HSV空間中去。

在opencv中直接使用cvCvtColor函式就可以啦。

IplImage* hsv = cvCreateImage( cvGetSize(image),8,3 );

cvCvtColor(image,hsv,CV_BGR2HSV);

opencv 的H範圍是0~180,紅色的H範圍大概是(0~8)∪(160,180) ,S是飽和度,一般是大於一個值,S過低就是灰色(參考值S>80),V是亮度,過低就是黑色,過高就是白色(參考值220>V>50)。

所以接下來要做的就是遍歷影象,獲取影象每個畫素點的H,S,V分量,然後做判斷,滿足條件的就保留,不滿足的就賦值為黑色。

我是用opencv中的IplImage來儲存圖片的。

IplImage獲取畫素點的方式如下:

CvScalar s_hsv = cvGet2D(hsv,j,i);//獲取畫素點為(i,j)點的HSV的值,i是width值,j是height值

IplImage對畫素點賦值的方式如下:

CvScalar s;

cvSet2D(hsv,i,s);//對(i,j)處的畫素點賦值

分別取得H,V分量,注意影象轉化的時候BGR2HSV,所以s.val[0]是B或H的值,s.val[1]是G或S的值,s.val[2]則是R或V的值。

因為師弟喜歡用CvMat,所以輸入都改成了CvMat,使用的時候inputImage是希望過濾的圖片,outputImage則為輸出圖片,因為outputImage會在函式中進行空間申請與賦值,所以傳入引數的時候直接把它設成NULL就可以了。

另外要注意一點,因為是對彩色影象做實驗,所以如果傳入的圖片不是3通道的彩色圖片,那麼就會出記憶體錯誤。

以下開啟圖片或建立圖片的方式都是單通道方式,會出現記憶體錯誤。

IplImage *input = cvLoadImage(path,0),
CvMat* M = cvCreateMat(4,4,CV_32FC1); //或是8UC1, 因為C1表示nChannel = 1,也就是單通道

void colorFilter(CvMat *inputImage,CvMat *&outputImage)
{
 int i,j;
 IplImage* image = cvCreateImage(cvGetSize(inputImage),3);
 cvGetImage(inputImage,image); 
 IplImage* hsv = cvCreateImage( cvGetSize(image),3 ); 
 
 cvCvtColor(image,CV_BGR2HSV);
 int width = hsv->width;
 int height = hsv->height;
 for (i = 0; i < height; i++)
 for (j = 0; j < width; j++)
 {
 CvScalar s_hsv = cvGet2D(hsv,j);//獲取畫素點為(j,i)點的HSV的值 
 /*
 opencv 的H範圍是0~180,紅色的H範圍大概是(0~8)∪(160,180) 
 S是飽和度,一般是大於一個值,S過低就是灰色(參考值S>80),
 V是亮度,過低就是黑色,過高就是白色(參考值220>V>50)。
 */
 CvScalar s;
 if (!(((s_hsv.val[0]>0)&&(s_hsv.val[0]<8)) || (s_hsv.val[0]>120)&&(s_hsv.val[0]<180)))
 {
 s.val[0] =0;
 s.val[1]=0;
 s.val[2]=0;
 cvSet2D(hsv,s);
 }
 
 }
 outputImage = cvCreateMat( hsv->height,hsv->width,CV_8UC3 );
 cvConvert(hsv,outputImage);
 cvNamedWindow("filter");
 cvShowImage("filter",hsv);
 waitKey(0);
 cvReleaseImage(&hsv);
}

關於函式還有一點要說明,H分量我取得是(0,8),(120,180),S與V分量沒有做篩選,如果按照註釋部分的進行篩選結果不是很好。

結果如圖:

opencv之顏色過濾只留下圖片中的紅色區域操作

補充知識:opencv實現影象去除單一顏色背景

思路

opencv之顏色過濾只留下圖片中的紅色區域操作

因為背景是固定顏色,很容易篩選出背景,然後將其設為白色完全透明即可。

程式碼

#coding=utf-8
import cv2 as cv
bg_color = [197,102,6]
threshold = 3000

def calc_diff(pixel):
'''
計算pixel與背景的離差平方和,作為當前畫素點與背景相似程度的度量
'''
  return (pixel[0]-bg_color[0])**2 + (pixel[1]-bg_color[1])**2 + (pixel[2]-bg_color[2])**2

def remove_bg():
  image_path = './logo.png'
  logo = cv.imread(image_path)
  logo = cv.cvtColor(logo,cv.COLOR_BGR2BGRA) #將影象轉成帶透明通道的BGRA格式
  h,w = logo.shape[0:2]
  for i in range(h):
    for j in range(w):
      if calc_diff(logo[i][j]) < threshold:
      #若果logo[i][j]為背景,將其顏色設為白色,且完全透明
        logo[i][j][0] = 255
        logo[i][j][1] = 255
        logo[i][j][2] = 255
        logo[i][j][3] = 0
 
  cv.imwrite("./logo_rmbg.png",logo)
        
if __name__ == '__main__':
  remove_bg()

使用方法

修改第5行的bg_color為圖片背景的bgr值,以及第6行的threshold(threshold越大,覆蓋的畫素越多)。

效果:

opencv之顏色過濾只留下圖片中的紅色區域操作

emmm,事實證明背景附近的顏色不是嚴格的背景色,後來將字填充後好多了。

opencv之顏色過濾只留下圖片中的紅色區域操作

以上這篇opencv之顏色過濾只留下圖片中的紅色區域操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。