Basic cropping with PIL and PyTorch
I'm embarrassed to say that even at this point in my life, I still have to look up this formatting to crop an image. Once and for all, I'll post it here so that I don't forget it and also in case you're looking for it, you found it.
PIL
from PIL import Image
from IPython.display import display
pil_im = Image.open('1_003_1_01_NN_V.bmp')
display(pil_im)
# original dims
width, height = pil_im.size
print(width, height)
# resize
newsize = (256, 256)
im1 = pil_im.resize(newsize)
print(im1.size)
display(im1)
Let's crop this into even quadrants. With the 256 x 256 image, crop out even sections that are 128 x 128 each. Knowing where 0 (zero'th) pixel starts and where the 256th pixel ends is key to setting crop points.
# Setting the points for cropped image
left_A = 0
top_A = 0
right_A = 256 - 256/2
bottom_A = 256 - 256/2
left_B = 256/2
top_B = 0
right_B = 256
bottom_B = 256 - 256/2
left_C = 0
top_C = 256 - 256/2
right_C = 256 - 256/2
bottom_C = 256
left_D = 256 - 256/2
top_D = 256 - 256/2
right_D = 256
bottom_D = 256
Crop the points on the original image.
A = im1.crop((left_A, top_A, right_A, bottom_A))
B = im1.crop((left_B, top_B, right_B, bottom_B))
C = im1.crop((left_C, top_C, right_C, bottom_C))
D = im1.crop((left_D, top_D, right_D, bottom_D))
# Shows the image in image viewer
display(A)
display(B)
display(C)
display(D)
PyTorch Tensors
Let's say we want to crop 4 patches on an image called X
transformed into a PyTorch Tensor returned from the Dataloader. You can achieve this easily
# where opt.img_width, opt.img_height = 256, 256
class ImageDataset(Dataset):
def __init__(self, root, transforms_=None, mode="train"):
self.transform = transforms.Compose(transforms_)
self.files = sorted(glob.glob(os.path.join(root, mode) + "/*.*"))
def __getitem__(self, index):
img = Image.open(self.files[index % len(self.files)])
img = self.transform(img)
return {"X": img}
def __len__(self):
return len(self.files)
transforms_ = [
transforms.Resize((opt.img_height, opt.img_width), Image.BICUBIC),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
]
dataloader = DataLoader(
ImageDataset(root = "data/%s" % opt.dataset_name,
transforms_=transforms_),
batch_size=opt.batch_size,
shuffle=True,
num_workers=opt.n_cpu,
drop_last=True,
)
#####
for epoch in range(opt.epoch, opt.n_epochs):
for i, batch in enumerate(dataloader):
X = Variable(batch["X"].type(Tensor))
# do cropping
# (x,y) = (0,0)
A = X[:, :, 0:0+opt.img_width//2, 0:0+opt.img_height//2]
# (x,y) = (0, 128)
B = X[:, :, 0:0+opt.img_width//2, 128:128+opt.img_height//2]
# (x,y)=(128,0)
C = X[:, :, 128:128+opt.img_width//2, 0:0+opt.img_height//2]
# (x,y) = (128,128)
D = X[:, :, 128:128+opt.img_width//2, 128:128+opt.img_height//2]
Why might you want to use crops? In this case, I've been using different sizes and number of crops as patches to pass through a contrastive loss function. Having control at a tensor-level can allow some more automatic ways of resizing, dividing, and scaling crops for a variety of experiments.