How to replace empty numpy array by grayscale image values - python

EDIT: I have found a workaround, which is assigning it to an array, then use that array to create a numpy array:
a = []
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
a.append(roi)
arr = np.asarray(a) #HERE
ORIGINAL QUESTION:
I have created an empty numpy array of shape (180,28,28), which should hold 180 gray scale images size 28x28.
height, width = img.shape[:2]
arr = np.empty(((height/image_size)*(width/image_size), 28, 28 )) #arr.shape = (180,28,28)
I have multiple image regions size 28x28 that I want to populate into arr
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
#HERE - how can I set the value in arr to be an (28x28) roi
Thank you.

I have found a workaround, which is assigning it to an array, then use that array to create a numpy array:
a = []
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
a.append(roi)
arr = np.asarray(a) #assign it to numpy array here
However, I'm not sure if there is a better, or more elegant way to do it.

Related

Image Array "ValueError: setting an array element with a sequence"

I want to do some operation in numpy array. Actually I'm trying to zoom an image using the nearest neighbour rule. I have facing that above titled issue.
import cv2
import numpy as np
from numpy import ndarray
img = cv2.imread('abc.jpg')
rows = img.shape[0]*2
cols = img.shape[1]*2
zoomed = np.zeros((rows, cols), dtype=img.dtype)
for i in range(0, rows):
for j in range(0, cols):
zoomed[i][j] = img[int(i/2)][int(j/2)]
cv2.imshow('Input Image', img)
cv2.imshow('Zoomed Image', zoomed)
cv2.waitKey(0)
Try:
zoomed = np.zeros((rows, cols, 3), dtype=img.dtype)
The error you're getting is happening because img[int(i/2)][int(j/2)] is actually three RGB values and zoomed[i][j] can only hold integers. Creating zoomed to have shape (rows, cols, 3) allows zoomed to hold 3 integers at every row, column location.

Using numpy.histogram on an array of images

I'm trying to calculate image histograms of an numpy array of images. The array of images is of shape (n_images, width, height, colour_channels) and I want to return an array of shape (n_images, count_in_each_bin (i.e. 255)). This is done via two intermediary steps of averaging each colour channel for each image and then flattening each 2D image to a 1D one.
I think have successfully done this with the code below, however I have cheated a bit with the for loop at the end. My question is this - is there a way of getting rid of the last for loop and using an optimised numpy function instead?
def histogram_helper(flattened_image: np.array) -> np.array:
counts, _ = np.histogram(flattened_image, bins=[n for n in range(0, 256)])
return counts
# Using 10 RGB images of width and height 300
images = np.zeros((10, 300, 300, 3))
# Take the mean of the three colour channels
channel_avg = np.mean(images, axis=3)
# Flatten each image in the array of images, resulting in a 1D representation of each image.
flat_images = channel_avg.reshape(*channel_avg.shape[:-2], -1)
# Now calculate the counts in each of the colour bins for each image in the array.
# This will provide us with a count of how many times each colour appears in an image.
result = np.empty((0, len(self.histogram_bins) - 1), dtype=np.int32)
for image in flat_images:
colour_counts = self.histogram_helper(image)
colour_counts = colour_counts.reshape(1, -1)
result = np.concatenate([result, colour_counts])
You don't necessarily need to call np.histogram or np.bincount for this, since pixel values are in the range 0 to N. That means that you can treat them as indices and simply use a counter.
Here's how I would transform the initial images, which I imaging are of dtype np.uint8:
images = np.random.randint(0, 255, size=(10, 5, 5, 3)) # 10 5x5 images, 3 channels
reshaped = np.round(images.reshape(images.shape[0], -1, images.shape[-1]).mean(-1)).astype(images.dtype)
Now you can simply count the histograms using unbuffered addition with np.add.at:
result = np.zeros((images.shape[0], 256), int)
index = np.arange(len(images))[:, None]
np.add.at(result, (index, reshaped), 1)
The last operation is in-place and therefore returns None, but the answer will be in result nevertheless.

Convert a RGB image to grayscale img

arr = []
for i in range(len(x1)):
image = x1[i].reshape(150, 150, 3)
grayscale = image[0:150, 0:150, 1]
grayscale = grayscale.reshape(22500)
arr = np.append(arr, np.array(grayscale), axis=0)
print(arr.shape) # (742500,)
I am working on a school project, and I have created more data with augmentation in RGB format. I would like to convert this to grayscale after augmentation because it will require fewer computations. However, for some reason, I am having problems with appending the reshaped version into a new array. It is append everything into one row and not to a separate rows, I want to have (33,22500) not (742500), can anyone help plz
there are several ways;
way1:
arr = []
for i in range(len(x1)):
image = x1[i].reshape(150,150,3)
grayscale = image[:150,:150,1]
grayscale = grayscale.reshape(22500)
arr.append(grayscale)
arr = np.array(arr)

How to Correctly mask 3D Array with numpy

I'm trying to mask a 3D array (RGB image) with numpy.
However, my current approach is reshaping the masked array (output below).
I have tried to follow the approach described on the SciKit-Image crash course.
Crash Course
I have looked in the Stackoverflow and a similar question has been asked, but with no accepted answer (similar question here)
What is the best way to accomplish masking like this?
Here is my attempt:
# create some random numbers to fill array
tmp = np.random.random((10, 10))
# create a 3D array to be masked
a = np.dstack((tmp, tmp, tmp))
# create a boolean mask of zeros
mask = np.zeros_like(a, bool)
# set a few values in the mask to true
mask[1:5,0,0] = 1
mask[1:5,0,1] = 1
# Try to mask the original array
masked_array = a[:,:,:][mask == 1]
# Check that masked array is still 3D for plotting with imshow
print(a.shape)
(10, 10, 3)
print(mask.shape)
(10, 10, 3)
print(masked_array.shape)
(8,)
# plot original array and masked array, for comparison
plt.imshow(a)
plt.imshow(masked_array)
plt.show()
NumPy broadcasting allows you to use a mask with a different shape than the image. E.g.,
import numpy as np
import matplotlib.pyplot as plt
# Construct a random 50x50 RGB image
image = np.random.random((50, 50, 3))
# Construct mask according to some condition;
# in this case, select all pixels with a red value > 0.3
mask = image[..., 0] > 0.3
# Set all masked pixels to zero
masked = image.copy()
masked[mask] = 0
# Display original and masked images side-by-side
f, (ax0, ax1) = plt.subplots(1, 2)
ax0.imshow(image)
ax1.imshow(masked)
plt.show()
After finding the following post on loss of dimensions HERE, I have found a solution using numpy.where:
masked_array = np.where(mask==1, a , 0)
This appears to work well.

Import RGB value of each pixel in an image to 1-D array

How to import RGB value of each pixel in an image to 1-D array?
I am using following thing:
from PIL import Image
im = Image.open("bride.jpg")
pix = im.load()
print pix[x,y]
this imports it into 2-D array which is not iterable.
I want this same thing but in 1-D array.
You can flatten the pixels into a 1D array as follows:
width, height = im.size
pixels = [pix[i, j] for i in range(width) for j in range(height)]
Easy if you're using numpy, and no need to load the image.
from PIL import Image
import numpy as np
im = Image.open("bride.jpg")
pix_flatiter = np.asarray(im).flat # is an iterable
If you want to load the whole array, you can do:
pix_flat = np.asarray(im).flatten() # is an array

Categories