Векторизованный подход к маскировке красных и синих каналов на изображении

#python #numpy #opencv #mask #pixel-manipulation

Вопрос:

Я пытаюсь изменить все красные и синие пиксели на изображении на черные, чтобы иметь только зеленые пиксели (в зависимости от определенных условий).

Чтобы сделать это прямо сейчас, я использую несколько циклов for, и процесс, хотя и работает, идет чрезвычайно медленно.

Код, который у меня есть до сих пор —

 ### Test image is my original RGB image
mat = np.asarray(testim)

for elemento in mat: 

    for pixel in element:

        if ((pixel[0]   pixel[2]) >= (2*pixel[1])): #Non-vegetation background changing to black according to the rule (R   B >= 2G)
          pixel[0] = 0
          pixel[1] = 0
          pixel[2] = 0
        
        elif pixel[1] > pixel[0] and pixel[1] > pixel[2] and pixel[1] > 25: # Treat these as green vegetation and do not change anything
          continue
        
        else: # Change background to black
          pixel[0] = 0
          pixel[1] = 0
          pixel[2] = 0
cv2_imshow(testim)
print(testim.shape)
 

Есть ли какой-либо способ векторизовать это с помощью Numpy без использования вложенных циклов for, чтобы ускорить работу одного и того же процесса? Я немного новичок в операциях NumPy и не понимаю, как это сделать. Я ценю вашу помощь!

Например : Мое входное изображение — [1]: https://i.stack.imgur.com/zWGtA.jpg

Выходное изображение, которое у меня сейчас есть с приведенной выше логикой — [2]: https://i.stack.imgur.com/VkmLC.jpg

Я хотел бы получить тот же результат с более быстрым кодом, предпочтительно с использованием NumPy вместо вложенных циклов for, которые у меня есть в настоящее время

Комментарии:

1. У вас есть данные для testim работы?

2. @JoostVn только что отредактировал вопрос с образцом изображения и выводом

Ответ №1:

Я разделил массив изображений на три массива (r, g, b), чтобы сделать правила более интуитивно понятными. В этом формате должно быть легко добавлять любые новые!

 r, g, b = mat[:,:,0], mat[:,:,1], mat[:,:,2]
rule_1 = (r   b > 2 * g)
rule_2 = ~((g > r) amp; (g > b) amp; (g > 25))
mat[rule_1 | rule_2] = 0
 

Комментарии:

1. Этот подход тоже сработал! Большое спасибо за помощь!

Ответ №2:

Вы должны иметь возможность получить доступ к своей красной матрице с mat[:,:,0] помощью зеленого и синего и аналогично с ними.

Ваша маска из зеленых пикселей затем:

 mask = (mat[:,:,1]>mat[:,:,0]) amp; (mat[:,:,1]>mat[:,:,2]) amp; (mat[:,:,1]>25)
 

где вы проводите сравнения по элементам и по элементам И объединяете сравнения в логическую 2D-матрицу.

Затем вы можете обнулить пиксели друг друга, выполнив:

 # Repeat mask along the three channels
mask = np.repeat(mask[:,:,np.newaxis], 3, axis=2)

# Zero non-green elements
mat[~mask] = 0
 

Комментарии:

1. Большое вам спасибо за быстрый ответ и объяснение! Это сработало именно так, как я хотел

Ответ №3:

Из вашего кода следует, что вы не меняете значения, когда

 pixel[1] > pixel[0] and pixel[1] > pixel[2] and pixel[1] > 25
 

Таким образом, мы можем сформировать логический массив этого условия и проиндексировать его обратно в массив и установить эти места равными 0:

 # since used more than once, assign to a variable
green = mat[:, :, 1]

# your "elif" condition
not_change_condition = (green > mat[:, :, 0]) amp; (green > mat[:, :, 2]) amp; (green > 25)

# index with its inverse and change
mat[~not_change_condition] = 0
 

Комментарии:

1. Этот подход тоже сработал, и ваши комментарии помогли мне понять, почему.. Большое спасибо за помощь!