Change array shape of an image in python - image

When I read a colour image in OpenCV, it is showing the dimensions as 256x256x3. But I need to pass it as 3x256x256 array to my neural network. How do I change the array shape, retaining the pixel locations in BGR.

You can simply transpose the array. For an example, my picture is a 10 x 10 picture:
import numpy as np
#my picture
wrong_format = np.arange(300).reshape(10,10,3)
correct_format = wrong_format.T
If it works properly, then correct_format(0,1,1) should be equal to wrong_format(1,1,0). And we can see that it is:
correct_format(0,1,1) == wrong_format(1,1,0)
True

Related

Joining edited images in python using numpy image slicer

I am learning image manipulation as a beginner in python. My goal is to section my image into an nxn grid where each square is the average color (greyscale image) of the original, respectively. I succeeded in splitting the image, changing its pixel data and saving the new images. My problem is now stitching the image back together. I know the join function is pointing back to the original image, I had hoped that by saving over the tiles I could work around this.
This is my first time posting to stackoverflow (and I am super, super new to python), so apologies if I am not clear or if the formatting is wrong.
# Import packages
import numpy as np
from numpy import matlib
import PIL
import image_slicer
import math
import glob
from image_slicer import join
from PIL import Image
### Use PIL to import image
##img = Image.open("einstein.jpg")
# Display original image
# img.show()
##new_img = img.resize((256,256))
##new_img.save('einstein-256x256','png')
### new_img.show()
#Slice image into four pieces
tiles = image_slicer.slice("einstein.jpg", 16)
# Use glob to open every .png file with for loop
for filename in glob.glob("*.png"):
img=Image.open(filename)
pixels = img.load() # create the pixel map
pixelMap = img.load() #create the pixel map
#convert to array
arr = np.asarray(img)
#find mean
pixelMean = arr.mean(0).mean(0)[0]
# Convert mean to integer
IntMean = math.floor(pixelMean)
print(IntMean)
##pixel = pixelMap[0,0] #get the first pixel's value
##print(pixel)
# Loop for going through every pixel in image and converting it
for i in range(img.size[0]): # for every col:
for j in range(img.size[1]): # For every row
pixels[i,j] = (IntMean,IntMean,IntMean) # set the colour accordingly
# Save new monotone images
img.save(filename)
# Join new images into one
image = join(tiles)
# Save new image
image.save("einsteinJoined.jpg")
image.show()
Your question seems to be missing the error you get with your current code.
However, if I read it correctly, you will get back your original image, as was the problem in Split and Join images in Python. Similar to the answer accepted there, the solution is to change the image in each tile by ending your loop with:
tile.image = Image.open(filename)
Where tile is the tile corresponding to the file, you should loop over the tiles from the image_slicer.slice-function to do so. This is also given in answer to the question linked to.

Keras Image Data Generator show labels

I am using an ImageDataGenerator to augment my images. I need to get the y labels from the generator.
Example : I have 10 training images, 7 are label 0 and 3 are label 1. I want to increase training set size to 100.
total_training_images = 100
total_val_images = 50
model.fit_generator(
train_generator,
steps_per_epoch= total_training_images // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps= total_val_images // batch_size)
By my understanding, this trains a model on 100 training images for each epoch, with each image being augmented in some way or the other according to my data generator, and then validates on 50 images.
If I do train_generator.classes, I get an output [0,0,0,0,0,0,0,1,1,1]. This corresponds to my 7 images of label 0 and 3 images of label 1.
For these new 100 images, how do I get the y-labels?
Does this mean when I am augmenting this to 100 images, my new train_generator labels are the same thing, but repeated 10 times? Essentially np.append(train_generator.classes) 10 times?
I am following this tutorial, if that helps :
https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
The labels generate as one-hot-encoding with the images.Hope this helps !
training_set.class_indices
from keras.preprocessing import image
import matplotlib.pyplot as plt
x,y = train_generator.next()
for i in range(0,3):
image = x[i]
label = y[i]
print (label)
plt.imshow(image)
plt.show()
Based on what you're saying about the generator, yes.
It will replicate the same label for each augmented image. (Otherwise the model would not train properly).
One simple way to check what the generator is outputting is to get what it yields:
X,Y = train_generator.next() #or next(train_generator)
Just remember that this will place the generator in a position to yield the second element, not the first anymore. (This would make the fit method start from the second element).

How save bidimensional list to image in python?

I have a big bidimensional list of integer value. Each value represent a pixel and needs to match a color but obviously similar value needs to have similar color. Here an example of my list:
list=[[0,10,3,9,23,0], [7,0,0,0,0,10], [12,1,2,7,11,12], [0,0,0,34,1,9]]
"list" is a rectangle of 4 rows and each row have 6 columns. 0 value needs to match to no color, in other word 0 value is trasparent color. I try to use PIL but I didn't obtain the right result. Here the test code:
from PIL import Image
list=[[0,10,3,9,23,0], [7,0,0,0,0,10], [12,1,2,7,11,12], [0,0,0,34,1,9]]
new=Image.new("P", (4,6))
new.putdata(list)
new.save('test.tif')
The cause for the failure is during new.putdata(list), which expects a sequence object (I guess a 2D array doesn't count as a sequence object).
The fix is to convert your 2D array into a 1D array. One example of how to do this is:
sequence = [list[x][y] for x in range(len(list)) for y in range(len(list[0]))]
So the following code should work properly:
from PIL import Image
list=[[0,10,3,9,23,0], [7,0,0,0,0,10], [12,1,2,7,11,12], [0,0,0,34,1,9]]
new=Image.new("P", (6,4))
sequence = [list[x][y] for x in range(len(list)) for y in range(len(list[0]))]
new.putdata(sequence)
new.save('test.tif')

Python regionprops sci-kit image

I am using sci-kit image to get the "regionprops" of a segmented image. I then wish to replace each of the segment labels with their corresponding statistic (e.g eccentricity).
from skimage import segmentation
from skimage.measure import regionprops
#a segmented image
labels = segmentation.slic(img1, compactness=10, n_segments=200)
propimage = labels
#props loop
for region in regionprops(labels1, properties ='eccentricity') :
eccentricity = region.eccentricity
propimage[propimage==region] = eccentricity
This runs, but the propimage values do not change from their original labels
I have also tried:
for i in range(0,max(labels)):
prop = regions[i].eccentricity #the way to cal a single prop
propimage[i]= prop
This delivers this error
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I am a recent migrant from matlab where I have implemented this, but the data structures used are completely different.
Can any one help me with this?
Thanks
Use ndimage from scipy : the sum() function can operate using your label array.
from scipy import ndimage as nd
sizes = nd.sum(label_file[0]>0, labels=label_file[0], index=np.arange(0,label_file[1])
You can then evaluate the distribution with numpy.histogram and so on.

Converting a grayscale image to black and white

I have a grayscale image that only has the values 60 and 117. How can I convert the image to only black and white without graylevels?
I tried the matlab function gray2ind, but didn't get the expected output.
Thanks.
Try im2bw(img, level) with level = 0.5.
This is a matlab function that takes a grayscale image img, applies a threshold of level (a value between [0,1]) and returns a black and white image.
This function is part of the Image Processing Toolbox. Your case is simple enough that you could also try something like:
bwImg = false(size(img));
bwImg(img == 117) = true;
I edited the above to set values equal to false/true to more closely mimic Matlab's im2bw() which returns a matrix of logical values rather than ints.
2nd Edit: Modified the code block to reflect improvements suggested by #Amro

Resources