Как посчитать значения пикселей, удовлетворяющие предикату? - PullRequest
0 голосов
/ 05 марта 2020

Учитывая массив NumPy формы (8, 24, 3), соответствующий HSV-изображению с высотой 8 и шириной 24, я хотел бы подсчитать количество пикселей, удовлетворяющих некоторому предикату, определенному функцией.

Обычно с массивами NumPy мы можем сделать что-то вроде этого:

def isSmall(x):
  return x < 3

a = np.array([1,2,3,4,5])

isSmall(a)
output: array([ True,  True, False, False, False])

В какой момент мы можем посчитать количество True значений в выходных данных? Могу ли я сделать что-то подобное с предикатом, который ожидает три значения, соответствующие значениям HSV в массиве формы (8, 24, 3)?

Примерно так:

def isRed(x):
    h, s, v = (x[0], x[1], x[2])
    return ((170 <= h <= 180 or 0 <= h <= 10) and 100 <= s <= 255)

a = image of shape (8,24,3)

isRed(a)
Desired output: array([[ True,  True, ..., False, False],
                      ... , ...
                      [False, True, ..., False, False]])

Это создает форму ошибка, однако, поскольку, по-видимому, весь массив передается в функцию, а не NumPy, выполняющий свои фильтрующие маги c.

Ответы [ 2 ]

1 голос
/ 05 марта 2020

Вот один из способов использования индексации логического массива и двоичных битовых операторов :

a = np.random.randint(0,255,(8,24,3))

h = a[...,0]
s = a[...,1]

m = (((170 <= h) & (180 >= h)) | ((0 <= h) & (10 >= h))) & ((100 <= s) & (255 >= s))

a[m]

array([[  0, 154,  31],
       [  1, 101,  63],
       [  7, 118, 112],
       [179, 154,  13],
       [170, 163,  58],
       [176, 105, 143],
       [  2, 237, 161],
       [  1, 107,  33],
       [  3, 152, 235],
       [  8, 233, 231],
       [  4, 128,  47],
       [174, 165,  75]])
1 голос
/ 05 марта 2020

Использование NumPy индексации логического массива и функций bitwise_and и bitwise_or (используется как & и |) объединить эти логические массивы. Наконец, подсчитайте True значения в полученном массиве, используя count_nonzero:

import cv2
import numpy as np


def is_red(img):
    h, s = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV))[:2]
    idx = (((h >= 170) & (h <= 180)) | ((h >= 0) & (h <= 10))) & ((s >= 100) & (s <= 255))

    # Just for visual debugging
    cv2.imshow('image', image)
    cv2.imshow('red_mask', idx.astype(np.uint8) * 255)

    return idx, np.count_nonzero(idx)


image = cv2.imread('images/paddington.png')
mask, n_pixels = is_red(image)
print('Red mask:\n', mask, '\n')
print('Number of red pixels: ', n_pixels)

cv2.waitKey(0)
cv2.destroyAllWindows()

Это мое стандартное тестовое изображение (хотя и не соответствует закону Сетчелла ):

Input image

Это будет "красная маска" в соответствии с вашими отсечками:

Red mask

И вот что получается:

Red mask:
 [[False False False ... False False False]
 [False False False ... False False False]
 [False False False ... False False False]
 ...
 [False False False ... False False False]
 [False False False ... False False False]
 [False False False ... False False False]] 

Number of red pixels:  31938

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

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
NumPy:       1.18.1
OpenCV:      4.2.0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...