Использовать numpy для маскировки изображения с помощью шаблона?

Я использую numpy для создания пиксельных массивов. Изображение 800x600 представляет собой трехмерный массив uint8, 800x600x3. У меня также есть аналогичный массив с фиксированным рисунком (шахматная доска, см. здесь). У меня есть другой массив, 800x600 значений маски. Если маска равна нулю, я хочу скопировать пиксель образца в пиксель изображения. Если маска не равна нулю, я хочу оставить один пиксель изображения.

>>> image.shape
(800, 600, 3)
>>> chex.shape
(800, 600, 3)
>>> mask.shape
(800, 600)

Похоже, что он должен работать:

image[mask == 0,...] = chex

но дает "ValueError: массив не доступен для правильной формы".

Что я могу использовать для копирования пикселей в пикселях в пикселях изображений, где маска равна нулю?

Ответы

Ответ 1

idx=(mask==0)
image[idx]=chex[idx]

Обратите внимание, что image имеет форму (800,600,3), а idx имеет форму (800 600). Правила для индексации состояния

если кортеж выбора меньше, чем n, то столько: объектов по мере необходимости добавляются к концу выбора кортеж, чтобы измененный выбор кортеж имеет длину N.

Таким образом, массивы индексирования имеют свою собственную способность вещания. Форма idx получает статус (800 600,:)

Ответ 2

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

import matplotlib.pyplot as plt
from scipy.ndimage import rotate


cat = plt.imread('cat.jpeg')
bg = plt.imread('background.jpeg')


rotcat = rotate(cat, angle=8, reshape=True) ## rotating creates some black edges
height, width, _ = rotcat.shape

bgcopy = bg.copy() ## create a copy of the background; paste on copy

x, y = 40, 50 
bgcopy[x:x+height, y:y+width] = rotcat
plt.imsave('cat-on-bg-mask.jpg', bgcopy)

bad pasting

Итак, я нахожу области маски и заменяю эти значения исходными значениями фона

mask_ind = (bgcopy == 0)
bgcopy[mask_ind] = bg[mask_ind]
plt.imsave('cat-on-bg.jpg', bgcopy)

good pasting

Следует также отметить, что PIL.Image (из библиотеки Pillow) имеет возможность вставлять изображение в другое изображение с меньшим количеством шагов.

Ответ 3

Try:

image[mask[:] == 0,...] = chex[mask[:] == 0,...]

Ответ 4

Я использовал массивы 8x6x3, 8x6x3 и 8x6 для представления вашего массива изображений, массива проверок и массива соответственно.

# first create mini-versions of your arrays:
mask = NP.random.random_integers(0, 1, 48).reshape(8, 6)
img = NP.random.random_integers(3, 9, 8*6*3).reshape(8, 6, 3)
chk = NP.ones((8, 6, 3))

# all the work done in these two lines
mask = mask[:,:,NP.newaxis]
res = NP.where(mask==0, chk, img)

Ответ 5

Я обнаружил, что проще всего создать маску, в которой 1 = "пиксель сохранить" и 0 = "пиксель удалить".

Затем я умножил свое изображение на эту маску, чтобы удалить ненужные пиксели. Пример сохранения только рамки (снаружи) портрета:

from scipy.misc import imread
import matplotlib.pyplot as plt
import numpy as np

im = imread('portrait.jpg', mode='L') # read in image
plt.imshow(im) # show the original image

enter image description here

mask = np.ones(im.shape) # create a mask with the image shape
bw = 0.1 # identify border width and height as fraction of image size
bx = int(im.shape[1] * bw) # get the x dimension border width
by = int(im.shape[0] * bw) # get the y dimension border height
mask[bx:-bx,by:-by] = 0 # create a mask with 1 for border and 0 for inside

masked = im * mask # multiply 'im' by the mask to zero out non-border pixels
plt.imshow(masked) # show the result of the masking operation

enter image description here