I have images of different sizes but around 100×2000-800×8000 & 2000×100 in files: .jpg and corresponding files .txt with normalized bounding boxes (YOLOv8 format)
I want to resize images to height= 4096 or width=4096 depending on orientation but keep the aspect ration.
Later I want to paste them in middle in white image. And this part of the code works like charm.
from PIL import Image, ImageDraw
import os
import shutil
import numpy as np
class ImageProcessor:
def __init__(self, image: Image.Image) -> None:
self.image = image
def resize_to_square(self, width: int = 4096, height: int = 4096) -> Image.Image:
'''
Resize the image to a square with the specified dimensions.
The image is centered on a white background.
'''
# Calculate the new size while maintaining aspect ratio
aspect_ratio = self.image.width / self.image.height
if self.image.width > self.image.height:
new_width = width
new_height = int(width / aspect_ratio)
else:
new_height = height
new_width = int(height * aspect_ratio)
# Resize the image
resized_image = self.image.resize((new_width, new_height), Image.LANCZOS)
# Create a new white image with the specified dimensions
white_image = Image.new('RGB', (width, height), (255, 255, 255))
# Calculate the position to place the resized image in the middle
x = (width - new_width) // 2
y = (height - new_height) // 2
# Paste the resized image onto the white image
white_image.paste(resized_image, (x, y))
return white_image, x, y, new_width, new_height
The second part doesn’t work. I’m trying to format normalized bounding box to match the new image.
My tries:
class LabelProcessor:
def __init__(self, label_path: str) -> None:
self.label = label_path
self.bboxes = self._read_bounding_boxes()
def _read_bounding_boxes(self):
with open(self.label, 'r') as f:
lines = f.readlines()
boxes = []
for line in lines:
parts = line.strip().split()
class_id = int(parts[0])
x_center = float(parts[1])
y_center = float(parts[2])
width = float(parts[3])
height = float(parts[4])
boxes.append((class_id, x_center, y_center, width, height))
return boxes
def adjust_bounding_boxes(self, orig_width, orig_height, new_x, new_y, new_width, new_height, target_width=4096, target_height=4096):
adjusted_boxes = []
for class_id, x_center, y_center, width, height in self.bboxes:
# Convert to original pixel coordinates
x_center_pix = x_center * orig_width
y_center_pix = y_center * orig_height
width_pix = width * orig_width
height_pix = height * orig_height
# Adjust coordinates to the new image size
new_x_center_pix = x_center_pix + new_x
new_y_center_pix = y_center_pix + new_y
# Convert back to normalized coordinates
new_x_center = new_x_center_pix / target_width
new_y_center = new_y_center_pix / target_height
new_width = width_pix / target_width
new_height = height_pix / target_height
adjusted_boxes.append((class_id, new_x_center, new_y_center, new_width, new_height))
self.bboxes = adjusted_boxes
The original Bboxes:
3 0.19407051282051282 0.9483531651594479 0.3711217948717949 0.023960019038553073
0 0.4331410256410256 0.20447881960970968 0.787275641025641 0.050556877677296524
2 0.26346153846153847 0.8097858162779629 0.5161217948717949 0.016049500237981913
1 0.44384615384615383 0.06699190861494526 0.8877243589743591 0.008643503093764875
1 0.44144230769230763 0.05762970014278915 0.8828525641025641 0.007201332698714898
1 0.4450641025641026 0.04844359828653023 0.8804487179487179 0.009005235602094241
1 0.44144230769230763 0.04051880057115659 0.8828525641025641 0.007563065207044265
1 0.43900641025641024 0.032774869109947646 0.8683012820512821 0.007924797715373631
The original file and result: