Обновлено
Теперь, когда ваша фактическая намеченная обработка стала более ясной, вам, вероятно, будет лучше обслуживаться функция OpenCV inRange()
. Например:
#!/usr/local/bin/python3
import cv2 as cv
import numpy as np
# Load the image and convert to HLS
image = cv.imread("image.jpg")
hls = cv.cvtColor(image,cv.COLOR_BGR2HLS)
# Define lower and uppper limits for each component
lo = np.array([50,0,0])
hi = np.array([70,255,255])
# Mask image to only select filtered pixels
mask = cv.inRange(hls,lo,hi)
# Change image to white where we found our colour
image[mask>0]=(255,255,255)
cv.imwrite("result.png",image)
Итак, если мы используем это изображение:
Мы выбираем оттенки в диапазоне 50- 70, и делая их белыми:
Если вы go здесь для преобразователя цвета, вы можете видеть, что " Зеленый - это Hue = 120, но OpenCV делит Hues на 2, так что 360 градусов становится 180 и все еще умещается в uint8. Итак, наши 60 в коде означают 120 в онлайн-преобразователях цвета.
Диапазоны, которые OpenCV использует для изображений uint8:
- Оттенок 0..180
- Легкость 0..255
- Насыщенность 0..255
Как я уже говорил, вы должны войти в привычку смотреть на ваши типы данных, формы и диапазоны в вашем отладчике. Чтобы увидеть shape
, dtype
и максимальный оттенок, легкость и насыщенность, используйте:
print(hls.dtype, hls.shape)
print(hls[...,0].max())
print(hls[...,1].max())
print(hls[...,2].max())
Оригинальный ответ
Есть несколько способов сделать который. Наиболее производительным является, вероятно, функция OpenCV cv2.inRange()
, и в StackOverflow есть множество ответов на этот счет.
Вот способ Numpy. Если вы прочитаете комментарии и посмотрите на напечатанные значения, вы увидите, как объединить логическое И с логическим ИЛИ и т. Д., А также как обращаться к указанным c каналам.
#!/usr/bin/env python3
from random import randint, seed
import numpy as np
# Generate a repeatable random HSV image
np.random.seed(42)
h, w = 4, 5
HSV = np.random.randint(1,100,(h,w,3),dtype=np.uint8)
print('Initial HSV\n',HSV)
# Create mask of all pixels with acceptable Hue, i.e. H > 50
HueOK = HSV[...,0] > 50
print('HueOK\n',HueOK)
# Create mask of all pixels with acceptable Saturation, i.e. S > 20 AND S < 80
SatOK = np.logical_and(HSV[...,1]>20, HSV[...,1]<80)
print('SatOK\n',SatOK)
# Create mask of all pixels with acceptable value, i.e. V < 20 OR V > 60
ValOK = np.logical_or(HSV[...,2]<20, HSV[...,2]>60)
print('ValOK\n',ValOK)
# Combine masks
combinedMask = HueOK & SatOK & ValOK
print('Combined\n',combinedMask)
# Now, if you just want to set the masked pixels to 255
HSV[combinedMask] = 255
print('Result1\n',HSV)
# Or, if you want to set the masked pixels to one value and the others to another value
HSV = np.where(combinedMask,255,0)
print('Result2\n',HSV)
Пример вывода
Initial HSV
[[[93 98 96]
[52 62 76]
[93 4 99]
[15 22 47]
[60 72 85]]
[[26 72 61]
[47 66 26]
[21 45 76]
[25 87 40]
[25 35 83]]
[[66 40 87]
[24 26 75]
[18 95 15]
[75 86 18]
[88 57 62]]
[[94 86 45]
[99 26 19]
[37 24 63]
[69 54 3]
[33 33 39]]]
HueOK
[[ True True True False True]
[False False False False False]
[ True False False True True]
[ True True False True False]]
SatOK
[[False True False True True]
[ True True True False True]
[ True True False False True]
[False True True True True]]
ValOK
[[ True True True False True]
[ True False True False True]
[ True True True True True]
[False True True True False]]
Combined
[[False True False False True]
[False False False False False]
[ True False False False True]
[False True False True False]]
Result1
[[[ 93 98 96]
[255 255 255]
[ 93 4 99]
[ 15 22 47]
[255 255 255]]
[[ 26 72 61]
[ 47 66 26]
[ 21 45 76]
[ 25 87 40]
[ 25 35 83]]
[[255 255 255]
[ 24 26 75]
[ 18 95 15]
[ 75 86 18]
[255 255 255]]
[[ 94 86 45]
[255 255 255]
[ 37 24 63]
[255 255 255]
[ 33 33 39]]]
Result2
[[ 0 255 0 0 255]
[ 0 0 0 0 0]
[255 0 0 0 255]
[ 0 255 0 255 0]]
Примечания :
1) Вы также можете получить доступ к пикселям, не выбранным маской, используя отрицание:
# All unmasked pixels become 3
HSV[~combinedMask] = 3
2) Многоточие (...
) - это просто сокращение, означающее «все остальные измерения, которые я не потрудился перечислить» , поэтому HSV[...,1]
совпадает с HSV[:,:,1]
3) Если вам не нравится писать HSV[...,0]
для оттенка и HSV[...,1]
для насыщенности, вы можете разделить каналы
H, S, V = cv2.split(HSV)
Тогда вы можете просто использовать H
вместо HSV[...,0]
. Когда вы закончите, если вы хотите собрать каналы обратно в 3-канальное изображение, вы можете сделать:
HSV = cv2.merge((H,S,V))
или
HSV = np.dstack((H,S,V))