I have a pixel array of shape (height, width, channels) of an image and I want to process each pixel efficiently (I would be processing each pixel about 60 times per second)
Given a numpy pixel array of the sort: pix = np.arange(60).reshape(4, 5, 3)
I want to do something like:
for i in pix:
for j in i:
some_func(j)
but in a more efficient manner. I tried using np.nditer, but I could get it to access only the channel values and not the pixel as a whole
Related
I have a 3D array representing a batch of images (batch_size x W x H)
images = np.random.rand(8,100,100)
and a 2D array (batch_size x 2)
indices = np.random.randint(0, 100, size=(8, 2))
which contains x,y indices for accessing pixel values of the images. The following
images[:,indices[:,0],indices[:,1]
returns an array of shape (8,8) but I would like to get an array of shape (8,) that contains pixel values for each image at the respective x, y positions stored in indices.
Looking for a way to index the array w/o using a for loop.
Think I solved it. Just needed to get the diagonal of the output:
output = images[:,indices[:,0],indices[:,1]
np.diag(output) gives pixel values for each image at x,y positions (indices).
I have a greyscale image, represented by a 2D array of integers, shape (1000, 1000).
I then use sklearn.feature_extraction.image.extract_patches_2d() to generate an array of 3x3 'patches' from this image, resulting in an array of shape (1000000, 3, 3), as there are 1 million 3x3 arrays for each pixel value in the original image.
I reshape this to (1000, 1000, 3, 3), which is a 1000x1000 array of 3x3 arrays, one 3x3 array for each pixel in the original image.
I now want to effectively subtract the 2D array from the 4D array. I have already found a method to do this, but I would like to make one using vectorisation.
I currently iterate through each pixel and subtract the value there from the 3x3 array at the same index. This is a little bit slow.
This is what currently loads images, formats the arrays before hand, and then performs this subtraction.
from PIL import Image, ImageOps
from skimage import io
from sklearn.feature_extraction import image
import numpy
jitter = 1
patchsize = (jitter*2)+1
#load image as greyscale image using PIL
original = load_image_greyscale(filename)
#create a padded version of the image so that 1000x1000 patches are made
#instead of 998x998
padded = numpy.asarray(ImageOps.expand(original,jitter))
#extract these 3x3 patches using sklearn
patches = image.extract_patches_2d(padded,(patchsize,patchsize))
#convert image to numpy array
pixel_array = numpy.asarray(original)
#then reshape the array of patches so it matches array_image
patch_array = numpy.reshape(patches, (pixel_array.shape[0],pixel_array.shape[1],patchsize,patchsize))
#create a copy for results
patch_array_copy = numpy.copy(patch_array)
#iterate over each 3x3 array in the patch array and subtract the pixel value
#at the same index in the pixel array
for x in range(pixel_array.shape[0]):
for y in range(pixel_array.shape[1]):
patch_array_copy[x,y] = patch_array[x,y] - pixel_array[x,y]
I would like a way to perform the final step in the for loop using matrix operations.
I would also like to extend this at some point to work with RGB images, effectively making it a subtraction of an array with shape(1000,1000,3) from an array with shape(1000,1000,3,3,3). But i'm trying to go one step at a time here.
Any help or tips or suggestions or links to helpful resources would be greatly appreciated.
So, basically i have a array with 16 RGB color values, and i have to calculate the distance between the RGB value of a pixel in the input image and all of these 16. The RGB value which has the lower distance will be the RGB value in the output image.
The problem is: I'm using nested for loops to do these operations, and it's REALLY slow. Excerpt as follow:
for i in range (row):
for j in range (columns):
pixel = img[i, j]
for color in colorsarray:
dist.append(np.linalg.norm(pixel - color))
img[i,j] = colorsarray[dist.index(min(dist))]
dist.clear()
Is there a numpy function that can help me optimize this?
You can calculate the distances by broadcasting the arrays.
If your image has shape (x,y,3) and your palette has shape (n,3), then you can calculate the distance between each pixel and each color as an array with shape (x,y,n):
# distance[x,y,n] is the distance from pixel (x,y) to
# color n
distance = np.linalg.norm(
img[:,:,None] - colors[None,None,:], axis=3)
The index : means "the entire axis" and the index None means "broadcast the value along this axis".
You can then choose the closest color index:
# pal_img[x,y] is the index of the color closest to
# pixel (x,y)
pal_img = np.argmin(distance, axis=2)
Finally, you can convert back to RGB:
# rgb_img[x,y] is the RGB color closest to pixel (x,y)
rgb_img = colors[pal_img]
This shows how you don't really need special functions in NumPy. Unfortunately, this can be a bit hard to understand.
Untested, but you could try to vectorize your function:
# reshape to have 1D array
dimx = image.shape[0]
image = image.reshape(-1, 3)
def f(pixel):
# TODO here: logic to return, given the pixel, the closest match in the list
# vectorize the function and apply it to the image
image = np.vectorize(f)(image)
# set the shape back to original
image = image.reshape( dimx, -1, 3 )
I am trying to convert an image into an array of pixels.
Here is my current code.
im = Image.open("beeleg.png")
pixels = im.load()
im.getdata() # doesn't work
print(pixels # doesn't work
Ideally, my end goal is to convert the image into a vector of just pixels, so for instance if I have an image of dimensions 100x100, then I want a vector of dimensions 1x10000, where each value is between [0, 255]. Then, divide each of the values in the array by 256 and add a bias of 1 in the front of the vector. However, I am not able to proceed with all this without being able to obtain an array. How to proceed?
Scipy's ndimage library is generally the go-to library for working with pixels as data (arrays). You can load an image from file (most common formats supported) using scipy.ndimage.imread into a numpy array which can be easily reshaped and mathematically operated on. The mode keyword can be used to specify a colorspace transformation upon load (convert an RGB image to black and white). In your case you asked for single color pixels from 0-255 (8bit grayscale) so you would use mode='L'. See The Documentation for usage / more useful functions.
If use OpenCV, gray=cv2.imread(image,0) will return a grayscale image with n rows x m cols single channel numpy array. rows, cols = gray.shape will return the height and width of the image.
I have an image that has 7 bands with 6938x752 pixels in each band. I want to do some processing on it so am using a python module called RIOS that deals with the reading and writing of the image to let the user focus on the processing. It reads the image in as a numpy array in blocks so that the processing is more efficient than reading in the whole image.
It reads the image in as a numpy array with the shape (7, 200, 200). I want to process the data by pixel so that I have the information from each band for each pixel. Is there a way to index the array so that for I can process just the 7 values (one for each band) for each pixel within image?
The only little code I can provide here is the function I use to read in, process and write the data.
def MASKimage(info, inputs, outputs):
inputs.image1 = inputs.image1.astype(numpy.float32) # Read the image in as an array with shape (7, 200, 200)
process = * Do some processing on the array which is the 7 values pixel by pixel * # has shape (1,7)
outputs.outimage = process
You can try using np.transpose and np.reshape:
inputs.image1 = input.images1.transpose((1,2,0)).reshape(200*200,7)
You can just iterate through the image with a single loop to do your processing as each element represents a pixel with 7 bands.