Python - Как обрезать изображение в соответствии с его значениями? - PullRequest
1 голос
/ 15 марта 2020

У меня есть изображение вроде этого: все ноль пикселей; квадрат с некоторыми ненулевыми значениями. Я хотел бы обрезать изображение, чтобы создать новое изображение только с ненулевыми значениями. Я пробовал что-то вроде image = np.extract(image != 0, image) или image = image[image != 0], но они возвращают массив, а не матрицу. Как я могу решить? Спасибо

пример изображения

Ответы [ 3 ]

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

Одним из способов является использование np.nonzero и ndarray.reshape:

x, y = np.nonzero(image)
xl,xr = x.min(),x.max()
yl,yr = y.min(),y.max()
image[xl:xr+1, yl:yr+1]

Использование выборочного массива:

image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])

print(image)

array([[0, 0, 0, 0, 0],
       [0, 0, 1, 2, 0],
       [0, 0, 3, 3, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

x, y = np.nonzero(image)
xl,xr = x.min(),x.max()
yl,yr = y.min(),y.max()
image[xl:xr+1, yl:yr+1]

array([[1, 2],
       [3, 3]])
0 голосов
/ 15 марта 2020

Вы можете использовать cv.boundingRect, если не хотите использовать numpy np.nonzero.

Кроме того, cv.boundingRect быстрее numpy (возможно, потому что связывания C ++?).

image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])

# the line below is usually not necessary when dealing with
# gray scale images opened with imread(), but you need it if 
# you're working with the array created above, to get uint8 values
image = cv.convertScaleAbs(image)

x, y, w, h = cv.boundingRect(image)
newImg = image[y:y+h, x:x+w]

Время

В приведенном выше примере с массивом 5x5 cv.boundingRect в 2 раза быстрее:

%timeit x, y = np.nonzero(image)
1.4 µs ± 219 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit x, y, w, h = cv.boundingRect(image)
722 ns ± 30.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

С Изображение 1000x1500, cv.boundingRect намного быстрее (от 40x до 2000x, в зависимости от содержимого изображения):

# blank (all zero) image 
image = np.zeros((1500,1000), dtype=np.uint8)

%timeit x, y = np.nonzero(image)
6.67 ms ± 40 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit x, y, w, h = cv.boundingRect(image)
159 µs ± 1.14 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# only non-zero pixels
image = np.ones((1500,1000), dtype=np.uint8)

%timeit x, y = np.nonzero(image)
17.2 ms ± 155 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit x, y, w, h = cv.boundingRect(image)
7.48 µs ± 46.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Numpy все еще достаточно быстро, если вы работаете только с одним изображением. Но, например, при обработке кадров живого видео все меняется.

0 голосов
/ 15 марта 2020

В качестве альтернативы решению @yatu вы можете использовать numpy .ix_ , который позволяет индексировать перекрестное произведение переданных массивов:

import numpy as np
image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])

x, y = np.nonzero(image)
image[np.ix_(np.unique(x),np.unique(y))]
array([[1, 2],
       [3, 3]])

, где

np.ix_(np.unique(x),np.unique(y))
(array([[1],
        [2]], dtype=int64), array([[2, 3]], dtype=int64))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...