2014-02-18 2 views
2

Я пытаюсь сделать многоцветное пороговое значение на изображении opvv 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 x in range(width): 
    for y in range(height): 
     imcv[y, x] = threshold(imcv[y, x]) 

где threshold функция выполнения логики, описанной выше. Обратите внимание, что, хотя я сделал это на месте, преобразование на месте не требуется.

Метод, который я использую в настоящее время, но очень медленный. Я считаю, что в OpenCV/Numpy должен быть лучший метод. Я очень новичок в обеих рамках и не могу понять, как это сделать.

Я исследовал функции пороговых значений OpenCV, кажется, что они могут работать только на одноканальном изображении с серой шкалой, а диапазон должен быть последовательным. То, что мне нужно, - это пороговое значение для всех трех каналов по дискретным значениям. Я предполагаю, что должна быть специальная функция для передачи, но я не могу найти правильный API в своих документах.

Я также искал возможно многомерный API, который мог бы использовать, например ufunc. Кажется, я не могу достичь того, что я хотел здесь использовать, или я не видел, как это сделать.

Любая помощь приветствуется.

EDIT:

Благодаря как 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, спасибо за ваше предложение. Использование C реализации 'range' определенно помогает. Я думаю, что мое узкое место здесь доступно и меняет каждый пиксель в python. Я думаю, что если есть api, позвольте мне нажать его на реализацию C numpy или opencv, это ускорит ее. – xbtsw

+0

is [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, если этот элемент находится в б, в противном случае False. Это всего лишь векторный аналог метода in в Python. Или короче:

np.in1d ​​(а, б) < ==> [Правда для г в, если я в б еще Ложные]

Вы выполняете это для всех каналов , то есть проверить первый канал для допустимых значений в B, второй с G и третий с R.

Затем вы складываете их в направлении z, используя np.dstack. Почему z-направление? Потому что мы хотим в формате BGR-BGR-BGR ....

Но помните, что это 1D массив, поэтому мы переформатируем его до нашей исходной формы изображения, используя метод X.reshape(img.shape).

Итак, у вас есть булевская маска, где True, если она действительна, иначе False.

Это все в первой строке кода.

Теперь вы хотите увидеть действительные комбинации BGR. Комбинация действительна, если все компоненты B, G, R равны True. Таким образом, вы применяете np.all() в z-направлении. Снова вы получите булевскую маску q

q будет булевой маской с допустимыми цветами как True, а другие как False.

Таким образом, вы преобразовать в целое число типа данных, True -> 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

Смежные вопросы