Простой способ извлечь определенный цветовой диапазон из изображения в Python? - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь извлечь определенный цвет из изображения в пределах определенного диапазона RGB, используя модуль cv2. В приведенном ниже примере я пытаюсь изолировать огонь от выхлопа космического челнока между значениями RGB желтого и белого, а затем распечатать процент значений RGB в этом диапазоне по сравнению с остальной частью изображения.

Вот мой минимальный рабочий пример:

import cv2
import numpy as np
from matplotlib import pyplot as plt
import imageio

img = imageio.imread(r"shuttle.jpg")
plt.imshow(img)

Это выходное изображение. Это из Википедии.

enter image description here

img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

color1 = (255,255,0) #yellow
color2 = (255,255,255) #white
boundaries = [([color1[0], color1[1], color1[2]], [color2[0], color2[1], color2[2]])]
for (lower, upper) in boundaries:
    lower = np.array(lower, dtype=np.uint8)
    upper = np.array(upper, dtype=np.uint8)
    mask = cv2.inRange(img, lower, upper)
    output = cv2.bitwise_and(img, img, mask=mask)
    ratio = cv2.countNonZero(mask)/(img.size/3)
    print('pixel percentage:', np.round(ratio*100, 2))
    plt.imshow(mask)

Однако, похоже, это не работает, потому что я получаю 0% пикселей между желтым и белым значениями. Я не совсем уверен, где я иду не так:

[([255, 255, 0], [255, 255, 255])]
pixel percentage: 0.0

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

enter image description here

Примечание. Я не использовал встроенные средства просмотра изображений в cv2, такие как cv2.imshow (), cv2.waitKey () и cv2.destroyAllWindows (), потому что их вызовы приводили к сбою моей IDE (Spyder 3.3.1) в Windows 8.1. Не уверен, что именно поэтому изображение выглядит синим / фиолетовым?

Также, когда я просто пытаюсь вывести исходное изображение, оно появляется в странном перевернутом цветовом формате:

plt.imshow(img)

enter image description here

Во всяком случае, я пытался следовать аналогичному методу, чтобы обнаружить определенный диапазон цветов, ранее описанный здесь 1037 * однако этот конкретный метод доставлял мне проблемы во время компиляции и несколько раз зависал и приводил к падению компьютера, когда я пытался реализовать что-то вроде этого:

imask = mask>0
exhaust_color = np.zeros_like(img, np.uint8)
green[imask] = img[exhaust_color]

Полагаю, что я пытаюсь добиться здесь чего-то вроде изображения ниже, где отображаются только цвета между желтым и белым, а затем распечатать процент пикселей, состоящих из этих цветов. Для изображения ниже я только что отфильтровал все цвета ниже RGB (255, 255, 0) с помощью основного программного обеспечения для обработки изображений.

Есть ли способ добиться этого с помощью кода, который я уже написал или аналогичного?

enter image description here

РЕДАКТ. 1: Следуйте приведенным ниже советам, чтобы сначала преобразовать в цветовое пространство HSV. Однако это все еще не работает, и процент пикселей от желтого до белого все еще равен 0% Выходные графики все те же и показывают все черное или фиолетовое. Также мне удалось заставить работать cv2.imshow (), передав 1 в cs2.waitKey (1). (По какой-то причине не работает с 0).

#CONVERT TO HSV COLORS
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
color1 = np.uint8([[[0, 255, 255 ]]]) #yellow
color2 = np.uint8([[[255, 255, 255]]]) #white
hsv_color1 = cv2.cvtColor(color1,cv2.COLOR_BGR2HSV)
hsv_color2 = cv2.cvtColor(color2,cv2.COLOR_BGR2HSV)

print(hsv_color1)
print(hsv_color2)

#Define threshold color range to filter
mask = cv2.inRange(hsv_img, hsv_color1, hsv_color2)

# Bitwise-AND mask and original image
res = cv2.bitwise_and(hsv_img, hsv_img, mask=mask)
ratio = cv2.countNonZero(mask)/(hsv_img.size/3)
print('pixel percentage:', np.round(ratio*100, 2))
#plt.imshow(mask)

cv2.imshow('mask',res)
cv2.waitKey(1) 

выход

[[[ 30 255 255]]]
[[[  0   0 255]]]
pixel percentage: 0.0

1 Ответ

0 голосов
/ 14 сентября 2018

Это была довольно простая проблема;Вы дали больший цвет перед меньшим cv2.inRange, поэтому не было действительного пересечения!Вот некоторый рабочий код, который показывает вывод.Это должно быть легко адаптировано к вашему собственному сценарию.

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

img = cv2.imread('shuttle.jpg')   # you can read in images with opencv
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

hsv_color1 = np.asarray([0, 0, 255])   # white!
hsv_color2 = np.asarray([30, 255, 255])   # yellow! note the order

mask = cv2.inRange(img_hsv, hsv_color1, hsv_color2)

plt.imshow(mask, cmap='gray')   # this colormap will display in black / white
plt.show()

enter image description here

...