Search code examples
python-3.ximagecroppgm

Error generating cropped images using python


I'm doing some machine learning and need some images to be resized to fit the rest of the dataset. I'm doing some sloppy cropping of the images and I'm getting result which confuse me. The code is very basic and is provided below. The problem I'm experiencing is that sometimes I get images that are unreadable and can't be opened, some of these are only 40 bytes while others are at a more reasonable size. The files are of type ".pgm" and is being saved as ".pgm".

from matplotlib import pyplot
from matplotlib.image import imread
import cv2
import matplotlib.pyplot as plt
import os
import random

root = "/non-pedestrian/"
imageDir = root + "NonPedestrians/"
outDir = root + "cropped/"
xSize, ySize = (48, 96)
offset = 10 #Nothing good happends at the edges

#5000 images, 15000 crops
for idx, fname in enumerate(os.listdir(imageDir)):
    if idx >= 5000:
        break
    path = imageDir + fname
    img = cv2.imread(path, -1)
    for i in range(3):
        width, height = img.shape[:2]
        cropXmin = random.randint(offset, width - xSize - offset)
        cropYmin = random.randint(offset, height - ySize - offset)
        cropXmax = cropXmin + xSize
        cropYmax = cropYmin + ySize
        if cropYmax - cropYmin < ySize or cropXmax - cropXmin < xSize:
            # This has never happend
            print("wtf?")
            print(cropXmin, cropYmin, cropXmax, cropYmax, width, height)
            time.sleep(1000)
    
        cropped = img[cropYmin:cropYmax, cropXmin:cropXmax] # y0 : y1 , x0 : x1 
        cv2.imwrite(outDir + "{:06d}.pgm".format(idx + i * 5000), cropped)
        print("{:06d}.pgm".format(idx + i * 5000))

Solution

  • You switched width and height.
    It should be: height, width = img.shape[:2].

    You may use img = cv2.imread(path, cv2.IMREAD_GRAYSCALE), if you don't care about the colors.
    All pgm images must be Grayscale?

    I may also suggest a protection, in case input image is too small:

    if (cropXmin >= 0) and (cropYmin >= 0) and (cropXmax <= width) and (cropYmax <= height):   
        cropped = img[cropYmin:cropYmax, cropXmin:cropXmax] # y0 : y1 , x0 : x1 
    

    Here is a code sample that applies single image, and single cropping:

    xSize, ySize = (48, 96)
    
    offset = 10 # Nothing good happens at the edges
    
    # In case image is colored it's converted to Grayscale, and the crop is going to work.
    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)  # Read input image as Graysacle
    
    # height comes before width
    height, width = img.shape[:2]
    cropXmin = random.randint(offset, width - xSize - offset)
    cropYmin = random.randint(offset, height - ySize - offset)
    cropXmax = cropXmin + xSize
    cropYmax = cropYmin + ySize
    
    # Protection - required if input image is too small
    if (cropXmin >= 0) and (cropYmin >= 0) and (cropXmax <= width) and (cropYmax <= height):   
        cropped = img[cropYmin:cropYmax, cropXmin:cropXmax] # y0 : y1 , x0 : x1