Reputation: 305
I have a question regarding the pre-processing of some images using python. Most of the answers I found use Java and I need to use Python.
I have a training set of 2050 images and I want to resize them to 224 by 224 to later feed them to a convolutional neural network (CNN). The big problem is that I can't do it without losing the ratio of the images. Not all the images are the same size. For example, I have images 1000 by 700 pixels and 700 by 600 pixels.
My idea was to fill the smaller side of the image with pixels using the average of the surrounding ones. But I don't really know how to incorporate that with what I already have. I have heard of the cv2 library but I have never been able to make it work.
My code is the following:
training_set = pd.DataFrame({'Images': training_imgs,'Labels': training_labels})
train_dataGen = ImageDataGenerator(rescale=1./255)
train_generator = train_dataGen .flow_from_dataframe(
dataframe = training_set, directory="",
x_col="Images", y_col="Labels",
class_mode="categorical",
target_size=(224,224), batch_size=32)
## Steps to plot the images
imgs, labels = next(train_generator)
for i in range(batch_size):
image = imgs[i]
plt.imshow(image)
plt.show()
Upvotes: 2
Views: 1503
Reputation: 41
Here is a resizing program that I wrote based on your description:
from PIL import Image
import math
def ResizeImage(Img, SourceWidth, SourceHeight, DestinationWidth, DestinationHeight, Average=True):
tmp = [None] * DestinationWidth * DestinationHeight
x_ratio = SourceWidth / float(DestinationWidth); y_ratio = SourceHeight / float(DestinationHeight)
for i in range(0, DestinationWidth):
for j in range(0, DestinationHeight):
if Average:
tmp[i*DestinationWidth+j] = AverageOfSurrounding(Img, math.floor(j*x_ratio), math.floor(i*y_ratio))
else:
tmp[i*DestinationWidth+j] = Img.getpixel((math.floor(j*x_ratio),math.floor(i*y_ratio)))
im2 = Image.new(Img.mode, (DestinationWidth,DestinationHeight))
im2.putdata(tmp)
return im2
def AverageOfSurrounding(Img, x, y):
if (x == 0): # Left
if (y == 0): # Bottom left
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x+1,y)); p3 = Img.getpixel((x+1,y+1)); p4 = Img.getpixel((x,y+1))
return (int((p1[0]+p2[0]+p3[0]+p4[0])/4), int((p1[1]+p2[1]+p3[1]+p4[1])/4), int((p1[2]+p2[2]+p3[2]+p4[2])/4), int((p1[3]+p2[3]+p3[3]+p4[3])/4))
elif (y == Img.height): # Top left
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x+1,y)); p3 = Img.getpixel((x+1,y-1)); p4 = Img.getpixel((x,y-1))
return (int((p1[0]+p2[0]+p3[0]+p4[0])/4), int((p1[1]+p2[1]+p3[1]+p4[1])/4), int((p1[2]+p2[2]+p3[2]+p4[2])/4), int((p1[3]+p2[3]+p3[3]+p4[3])/4))
else:
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x+1,y)); p3 = Img.getpixel((x+1,y+1)); p4 = Img.getpixel((x,y+1)); p5 = Img.getpixel((x,y-1)); p6 = Img.getpixel((x+1,y-1))
return (int((p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0])/6), int((p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1])/6), int((p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2])/6), int((p1[3]+p2[3]+p3[3]+p4[3]+p5[3]+p6[3])/6))
elif (x == Img.width): # Right
if (y == 0): # Bottom Right
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x-1,y)); p3 = Img.getpixel((x-1,y+1)); p4 = Img.getpixel((x,y+1))
return (int((p1[0]+p2[0]+p3[0]+p4[0])/4), int((p1[1]+p2[1]+p3[1]+p4[1])/4), int((p1[2]+p2[2]+p3[2]+p4[2])/4), int((p1[3]+p2[3]+p3[3]+p4[3])/4))
elif (y == Img.height): # Top Right
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x-1,y)); p3 = Img.getpixel((x-1,y-1)); p4 = Img.getpixel((x,y-1))
return (int((p1[0]+p2[0]+p3[0]+p4[0])/4), int((p1[1]+p2[1]+p3[1]+p4[1])/4), int((p1[2]+p2[2]+p3[2]+p4[2])/4), int((p1[3]+p2[3]+p3[3]+p4[3])/4))
else:
p1 = Img.getpixel((x,y)); p2 = Img.getpixel((x-1,y)); p3 = Img.getpixel((x-1,y+1)); p4 = Img.getpixel((x,y+1)); p5 = Img.getpixel((x,y-1)); p6 = Img.getpixel((x-1,y-1))
return (int((p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0])/6), int((p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1])/6), int((p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2])/6), int((p1[3]+p2[3]+p3[3]+p4[3]+p5[3]+p6[3])/6))
else:
p1 = Img.getpixel((x-1,y+1)); p2 = Img.getpixel((x,y+1)); p3 = Img.getpixel((x+1,y+1))
p4 = Img.getpixel((x-1,y)); p5 = Img.getpixel((x,y)); p6 = Img.getpixel((x+1,y))
p7 = Img.getpixel((x-1,y-1)); p8 = Img.getpixel((x,y-1)); p9 = Img.getpixel((x+1,y-1))
A = (p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0]+p7[0]+p8[0]+p9[0])/9
R = (p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1]+p7[1]+p8[1]+p9[1])/9
G = (p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2]+p7[2]+p8[2]+p9[2])/9
B = (p1[3]+p2[3]+p3[3]+p4[3]+p5[3]+p6[3]+p7[3]+p8[3]+p9[3])/9
return (int(A), int(R), int(G), int(B))
im = Image.open("MyImage.png")
im = ResizeImage(im, im.width, im.height, 224, 224, False)
im.show()
I used Pillow library, because it is quite efficient for small tasks like this and cv2 felt like shooting a mouse with bazooka.
EDIT: If you want to lock the image ratio for x and y (ratio = SourceWidth/SourceHeight), you can easily edit the code for that and maybe use zero pixel padding for the extra pixels.
Upvotes: 1
Reputation: 1777
You are almost done. You do not need opencv here if you use keras.
image = imgs[i,:,:,:] # batch_size, height, width, channels
print(np.shape(image) # should be (224,224) in case your image is grayscale
plt.imshow(image)
plt.show()
This will display your resized image and print the shape of it. If you want to change the interpolation method for your resizing method, you can check the documentation. It is bilinear as default, and I assume this is what you are looking for.
EDIT 0: If you want to create your custom function for any kind of preprocessesing on your images (resizing etc.), you might define preprocessing_function
in your ImageDataGenerator
method. This function is applied to every image in the batch.
import cv2
def preprocess(image):
# feel free to define your own function here
# be sure this function returns an image
processed_image = cv2.resize(image, dsize=(224,224))
return processed_image
train_dataGen = ImageDataGenerator(preprocessing_function=preprocess,
rescale=1./255)
Upvotes: 1