Цветовой порог: почему маска имеет существенное значение в соответствии с указанными пределами?

Мы хотим применить пороговое значение цвета к изображению RGB:

исходное изображение

Когда мы указываем нижний предел как [0, 0, 0], а верхний предел как [255, 255, 255], результат будет следующим:

маска с 0

И когда нижний предел равен [1, 1, 1], а верхний предел равен [255, 255, 255], результат будет следующим:

маска с 1

Почему разница в один пиксель так резко меняет маскировку?

Код:

lower_blue = np.array([0,0,0]) 
upper_blue = np.array([255,255,255])
mask = cv2.inRange(image_copy, lower_blue, upper_blue)
plt.imshow(mask,cmap='gray')

person Akash Antony    schedule 24.10.2019    source источник
comment
Пожалуйста, ознакомьтесь с как задавать (хорошие) вопросы здесь: НЕ публиковать изображения кода, данных, сообщений об ошибках и т. д. — скопируйте или введите текст в вопрос. Укажите минимальный воспроизводимый пример. Есть ли у вас какие-либо другие (предварительные) этапы обработки, не показанные здесь?   -  person HansHirse    schedule 24.10.2019
comment
Когда вы загружаете изображение, проверьте, загружаете ли вы также альфа-канал...   -  person Mark Setchell    schedule 24.10.2019
comment
Извиняюсь @HansHirse, это был мой первый раз... но изображения были необходимы для понимания...   -  person Akash Antony    schedule 24.10.2019
comment
@MarkSetchell нет альфа-канала. Маскирование обычно выбирает диапазон, который нужно передать, и изменяет область маски на черную... но почему внезапное изменение нижнего предела с 0 на 1 может так сильно изменить маску?   -  person Akash Antony    schedule 24.10.2019
comment
Какова форма вашего изображения после загрузки image.shape, пожалуйста?   -  person Mark Setchell    schedule 24.10.2019
comment
Предоставьте фактическое изображение, которое вы открываете и анализируете, а не его график/скриншот. Спасибо.   -  person Mark Setchell    schedule 24.10.2019
comment
@MarkSetchell приносит извинения за ошибку. Я прикрепил исходное изображение. Форма изображения (514, 816, 3). Мне нужно замаскировать синий экран... но для общей дополнительной информации я хотел знать, почему это происходит.   -  person Akash Antony    schedule 25.10.2019
comment
Просто используйте lower_blue=(11,36,251) и upper_blue=(11,36,251), так как это постоянные значения R,G,B для вашего синего фона. Или немного измените его, например, lower_blue=(0,0,240) и upper_blue=(20,50,255), если синий не был постоянным.   -  person fmw42    schedule 25.10.2019
comment
Когда вы используете диапазоны (0,0,0) и (255,255,255), вы включаете все возможные цвета — все значения от 0 до 255 в каждом из красного, зеленого и синего каналов вашего изображения. Если у вас есть только синий цвет, то ограничьте диапазоны только узким набором значений ниже и выше значений красного, зеленого и синего для вашего синего цвета, как я упоминал выше.   -  person fmw42    schedule 25.10.2019


Ответы (1)


Ваша основная «проблема» - это функция Matplotlib imshow здесь .

В первом случае вы просто маскируете ВСЕ пиксели изображения, чтобы все пиксели в mask имели значение 255. При использовании imshow без каких-либо параметров на таких изображениях применяется автоматическое масштабирование цвета, так что соответствующий график устанавливается на 0 для всех пикселей, поскольку все пиксели имеют одинаковое значение. Если вы явно установите vmin и vmax (см. связанную страницу документации) в вызове imshow, вы увидите ожидаемый полностью белый график.

Незначительные изменения в вашем втором случае приводят к тому, что некоторые пиксели в mask становятся 0, так что даже стандартный вызов imshow будет давать «правильное» масштабирование цвета, поскольку пиксели в mask покрывают весь «диапазон» [0 ... 255], потому что есть только пиксели значения 0 и 255.

Теперь, чтобы обнаружить синий фон: в вашем случае синий фон имеет фиксированное значение RGB, поэтому с помощью OpenCV inRange со стандартным изображением BGR. В общем, для цветовой маскировки преобразование изображения в цветовое пространство HSV/HSL, с моей точки зрения, является более сложным. Для краткого введения, выбирая правильные значения H, S, L, см. этот ответ, который я дал на более ранний вопрос.

Я сделал некоторый код для вышеупомянутых сравнений и для фактического обнаружения синего фона:

import cv2
import numpy as np
import matplotlib.pyplot as plt

image = cv2.imread('8au0O.jpg')

lower_blue = np.array([0, 0, 0])
upper_blue = np.array([255, 255, 255])
mask_lb000 = cv2.inRange(image, lower_blue, upper_blue)

plt.figure()
plt.subplot(2, 3, 1)
plt.imshow(mask_lb000, cmap='gray')
plt.title('imshow without explicit vmin, vmax')
plt.subplot(2, 3, 4)
plt.imshow(mask_lb000, cmap='gray', vmin=0, vmax=255)
plt.title('imshow with explicit vmin, vmax')

lower_blue = np.array([1, 1, 1])
upper_blue = np.array([255, 255, 255])
mask_lb111 = cv2.inRange(image, lower_blue, upper_blue)

plt.subplot(2, 3, 2)
plt.imshow(mask_lb111, cmap='gray')
plt.title('imshow without explicit vmin, vmax')
plt.subplot(2, 3, 5)
plt.imshow(mask_lb111, cmap='gray', vmin=0, vmax=255)
plt.title('imshow with explicit vmin, vmax')

# Detect blue-ish areas in HSL converted image
# H value must be appropriate (see HSL color space), e.g. within [200 ... 260]
# L value can be arbitrary (we want everything between bright and dark blue), e.g. within [0.0 ... 1.0]
# S value must be above some threshold (we want at least some saturation), e.g. within [0.35 ... 1.0]
lower_blue = np.array([np.round(200 / 2), np.round(0.00 * 255), np.round(0.35 * 255)])
upper_blue = np.array([np.round(260 / 2), np.round(1.00 * 255), np.round(1.00 * 255)])
mask_lb = cv2.inRange(cv2.cvtColor(image, cv2.COLOR_BGR2HSV), lower_blue, upper_blue)

plt.subplot(2, 3, 3)
plt.imshow(mask_lb, cmap='gray')
plt.title('imshow without explicit vmin, vmax')
plt.subplot(2, 3, 6)
plt.imshow(mask_lb, cmap='gray', vmin=0, vmax=255)
plt.title('imshow with explicit vmin, vmax')

plt.show()

Это сгенерированный вывод:

Вывод

Надеюсь, это поможет!

person HansHirse    schedule 25.10.2019