Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use numpy to mask an image with a pattern?

Tags:

I'm using numpy to build pixel arrays. An 800x600 image is an 3-dimensional array of uint8, 800x600x3. I also have a similar array with a fixed pattern (a checkerboard, see here). I have another array, 800x600 of mask values. Where the mask is zero, I want to copy the pattern pixel to the image pixel. Where the mask is not zero, I want to leave the image pixel alone.

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

This feels like it should work:

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

but gives "ValueError: array is not broadcastable to correct shape".

What do I use to copy chex pixels to image pixels where mask is zero?

like image 729
Ned Batchelder Avatar asked Jan 30 '10 21:01

Ned Batchelder


People also ask

How do you create a binary mask in Python?

import numpy as np arr = np. arange(27). reshape(3,3,3) #3 channel image mask = np. zeros(shape=(3,3)) mask[1,1] = 1 # binary mask mask_3d = np.

What is a mask in NumPy?

A masked array is the combination of a standard numpy. ndarray and a mask. A mask is either nomask , indicating that no value of the associated array is invalid, or an array of booleans that determines for each element of the associated array whether the value is valid or not.


2 Answers

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

Note that image has shape (800,600,3), while idx has shape (800,600). The rules for indexing state

if the selection tuple is smaller than n, then as many : objects as needed are added to the end of the selection tuple so that the modified selection tuple has length N.

Thus indexing arrays have a sort of broadcasting ability of their own. idx's shape gets promoted to (800,600,:)

like image 75
unutbu Avatar answered Sep 17 '22 22:09

unutbu


I wanted to illustrate an example using @unutbu answer. In this scenario, I have an image of a cat that I rotate. This rotation causes some black edges that look ugly especially when pasted on a non-black background.

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

So, I find the areas of the mask and replace those values with the original background values

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

good pasting

I should also note that PIL.Image (from the Pillow library) has the ability to paste an image onto another image with fewer steps.

like image 20
Jon Avatar answered Sep 18 '22 22:09

Jon