Операция на пиксель с условием в Python без медленных циклов - PullRequest
0 голосов
/ 18 февраля 2020

Я пытаюсь применить порог к изображению, но не обычный простой порог.

Мне нужно установить черные пиксели, если они соответствуют условному, и, если нет, установить их белым.

Я мог бы просто l oop над пикселями, но на изображении 1080p это слишком долго.

Я использую HSV для сравнений, которые мне нужно сделать.

Вот условие (в этом примере я использовал бы его, если бы оно было в al oop):

if abs(input_pixel_color.hue - reference.hue) < 2 and input_pixel_color.saturation >= 0.25 and input_pixel_color.brightness >= 0.42:
    set_to_black
else:
    set_to_white

input_pixel - это значение HSV пикселя в l oop .

reference - это переменная для сравнения.

Я думал об использовании numpy, но я действительно не знаю, как написать это: /

Заранее спасибо

1 Ответ

0 голосов
/ 18 февраля 2020

Обновлено

Теперь, когда ваша фактическая намеченная обработка стала более ясной, вам, вероятно, будет лучше обслуживаться функция 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) 

Итак, если мы используем это изображение:

enter image description here

Мы выбираем оттенки в диапазоне 50- 70, и делая их белыми:

enter image description here

Если вы go здесь для преобразователя цвета, вы можете видеть, что " Зеленый - это Hue = 120, но OpenCV делит Hues на 2, так что 360 градусов становится 180 и все еще умещается в uint8. Итак, наши 60 в коде означают 120 в онлайн-преобразователях цвета.

enter image description here

Диапазоны, которые 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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...