2014-02-18 76 views
2

我想對opencv cv2圖像執行多色閾值處理。我想解決的問題是以下幾點:OpenCV多色閾值處理

  • R,G,B各有一個「有效」列表
  • 如果像素的R,G,B都認爲是有效的,然後進行像素(0, 0,0),否則,使其(255,255,255)

例如

  • [221,180,50]被認爲是R通道有效
  • [23,18 ,2]在G中被認爲是有效的信道
  • [84,22,48]被認爲是B通道

然後有效如果像素具有任何以下值(RGB排列)

  • (221,23,84)
  • (221,23,22)
  • (221,23,48)
  • (221,18,84)
  • (221,18,22)
  • (221,18,48)
  • ...
  • (50,2,48)

它將轉化爲(0,0,0),否則(255,255,255)

目前,我具有嵌套這樣做的for循環:

for x in range(width): 
    for y in range(height): 
     imcv[y, x] = threshold(imcv[y, x]) 

其中threshold功能執行上面描述的邏輯。請注意,雖然我是在原地進行此操作,但不需要就地轉換。

我目前使用的方法有效,但速度很慢。我相信在OpenCV/Numpy中必須有更好的方法。我對這兩個框架都很陌生,無法弄清楚。

我研究了OpenCV閾值函數,看起來它們只能工作在單通道灰度圖像上,範圍也需要是連續的範圍。我需要的是在離散值上對所有3個通道進行閾值處理。我想有需要傳遞一個自定義函數,但我無法在他們的文檔中找到正確的API。

我也查找了可能使用的numpy API,比如ufunc。看來我無法實現我在這裏使用它的目的,或者我沒有看到如何。

任何幫助表示讚賞。

編輯:

由於雙方AbidRahmanK和HYRY,既解決方案不是性能X1500改良實現了。

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 1.576 1.576 1.576 1.576 test.py:48(preprocess_cv2_image) 
    1 0.000 0.000 0.001 0.001 test.py:79(preprocess_cv2_image3) 
    1 0.000 0.000 0.001 0.001 test.py:66(preprocess_cv2_image2) 
+1

首先,使用'xrange'而不是'range'。後者實際上會建立一個指定大小的完整列表,然後迭代它,而前者返回一個生成器,它不必預先計算整個列表並允許您迭代它。 –

+0

嗨@SchighSchagh,謝謝你的建議。使用'range'的C實現肯定有幫助。我認爲我的瓶頸在於訪問和更改python中的每個像素。我認爲如果有一個API允許我將它推入C實現numpy或opencv將大大加速它。 – xbtsw

+0

是[221,18,48]也有效嗎? –

回答

2

請試試這個:

z1 = np.dstack([np.in1d(img[...,0],B),np.in1d(img[...,1],G),np.in1d(img[...,2],R)]).reshape(img.shape) 
q = np.all(z1,axis=2) 
out = np.uint8(q)*255 

np.in1d(a,b)給你相同長度的布爾數組作爲與True如果該元素是B,否則False。它只是Python中in方法的向量化對象。或簡稱:

np.in1d(A,B)< ==> [真爲我的,如果我在b,否則假]

你執行它的所有通道即檢查B中有效值的第一個通道,第二個G和第三個R。

然後使用np.dstack將它們堆疊在z方向上。爲什麼z方向?因爲我們想在BGR-BGR-BGR ...格式。

但請記住,這是一維數組,因此我們使用X.reshape(img.shape)方法將其重塑爲原始圖像形狀。

所以現在你有一個布爾值掩碼,其中如果有效則爲真,否則爲假。

這一切都在第一行代碼中。

現在你想看到有效的BGR組合。如果所有B,G,R分量均爲真,則組合是有效的。所以你在z方向上應用np.all()。再次,您將得到一個布爾掩碼q

q將是一個布爾值掩碼,其有效顏色爲True,其他爲False。

所以要轉換爲整數數據類型,真 - > 1和假 - > 0

然後你用255乘以如果你想反轉圖像,你可以使用np.bitwise_not

+0

嗨@AbidRahmanK,謝謝你的回答!您能否稍微解釋一下代碼?我想讓你的代碼片段適應我的代碼並測試性能,但是我無法輸出一個cv2圖像。 – xbtsw

+0

現在嘗試'out = np.uint8(q)* 255'。我會盡快更新答案。 –

+0

更新....... –

1

你可以爲R,G,B三個布爾數組,如果該值有效的R,然後R[value]爲真,那麼你可以使用Rm[img[:, :, 2]] & Gm[img[:, :, 1]] & Bm[img[:, :, 0]]得到結果:

import numpy as np 

img = np.random.randint(0, 256, (2000, 2000, 3)) 

def make_mask(idx): 
    b = np.zeros(256, np.bool) 
    b[idx] = True 
    return b 

R = [221, 180, 50] 
G = [23, 18, 2] 
B = [84, 22, 48] 


Rm, Gm, Bm = [make_mask(v) for v in [R, G, B]] 
a = Rm[img[:, :, 2]] & Gm[img[:, :, 1]] & Bm[img[:, :, 0]] 

最後,得到的結果圖像:

v = np.array([[255,255,255], [0,0,0]], np.uint8) 
v[a.astype(np.uint8)] 
+0

謝謝@HYRY表現非常好。你的方法很容易理解。自從他回答第一個問題以來,我正在給AbidRahmanK作答。 – xbtsw