如何计算满足谓词的像素值?

时间:2020-03-05 11:13:27

标签: python image numpy filtering vectorization

给定一个形状为(8, 24, 3)的NumPy数组,它对应于高度为8和宽度为24的HSV图像,我想计算满足由a定义的某些谓词的像素数量功能。

通常使用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值的数量? 我可以对期望三个值的谓词做类似的事情吗? 对应于形状为(8, 24, 3)的数组中的HSV值?

类似这样的东西:

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进行了过滤。

2 个答案:

答案 0 :(得分:1)

使用NumPy的boolean array indexingbitwise_andbitwise_or函数(分别用作&|)来组合这些布尔数组。最后,使用count_nonzero在结果数组中计算True个值:

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()

这是我的标准测试图片(尽管不符合Setchell's law):

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

答案 1 :(得分:1)

这是使用boolean array indexingbinary bitwise operators的一种方法:

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]])