devskale
commited on
Commit
·
e997429
1
Parent(s):
8f00e6a
cropping update
Browse files- gradio_imager.py +1 -1
- image_processor.py +36 -166
gradio_imager.py
CHANGED
|
@@ -201,7 +201,7 @@ with gr.Blocks(title="IMAGER ___ v0.2 Image Processing Tool") as demo:
|
|
| 201 |
container=True
|
| 202 |
)
|
| 203 |
with gr.Row():
|
| 204 |
-
crop = gr.Checkbox(label="Crop", container=True)
|
| 205 |
remove_bg = gr.Checkbox(label="Remove Background", container=True)
|
| 206 |
|
| 207 |
# Size and Background Settings
|
|
|
|
| 201 |
container=True
|
| 202 |
)
|
| 203 |
with gr.Row():
|
| 204 |
+
crop = gr.Checkbox(label="Crop on Object", container=True)
|
| 205 |
remove_bg = gr.Checkbox(label="Remove Background", container=True)
|
| 206 |
|
| 207 |
# Size and Background Settings
|
image_processor.py
CHANGED
|
@@ -44,6 +44,38 @@ def add_background(image, background, default_color="#FFFFFF"):
|
|
| 44 |
return final_img
|
| 45 |
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
def autocrop_image(image):
|
| 48 |
"""
|
| 49 |
Autocrops an image, focusing on the non-transparent pixels.
|
|
@@ -55,6 +87,7 @@ def autocrop_image(image):
|
|
| 55 |
- PIL.Image.Image: The autocropped image.
|
| 56 |
"""
|
| 57 |
bbox = image.getbbox()
|
|
|
|
| 58 |
if bbox:
|
| 59 |
return image.crop(bbox)
|
| 60 |
return image
|
|
@@ -102,8 +135,10 @@ def process_image(img, crop=False, remove_bg=False, resize=None, padding=0, back
|
|
| 102 |
if remove_bg:
|
| 103 |
img = remove_bg_func(img)
|
| 104 |
|
| 105 |
-
if crop:
|
| 106 |
img = autocrop_image(img)
|
|
|
|
|
|
|
| 107 |
|
| 108 |
if resize:
|
| 109 |
img = resize_and_pad_image(img, resize, padding)
|
|
@@ -114,41 +149,6 @@ def process_image(img, crop=False, remove_bg=False, resize=None, padding=0, back
|
|
| 114 |
return img
|
| 115 |
|
| 116 |
|
| 117 |
-
def process_image2(image_data, crop=False, remove_bg=False, resize=None, padding=0, background=None):
|
| 118 |
-
"""
|
| 119 |
-
Processes a single image based on the provided options.
|
| 120 |
-
|
| 121 |
-
Args:
|
| 122 |
-
- image_data (PIL.Image.Image): The input image.
|
| 123 |
-
- crop (bool): Whether to autocrop the image.
|
| 124 |
-
- remove_bg (bool): Whether to remove the background of the image.
|
| 125 |
-
- resize (tuple): Optional dimensions (width, height) to resize the image.
|
| 126 |
-
- padding (int): Number of padding pixels to add around the image.
|
| 127 |
-
- background (str): Optional background color (hex code or name) or path to an image file to set as the background.
|
| 128 |
-
|
| 129 |
-
Returns:
|
| 130 |
-
- PIL.Image.Image: The processed image.
|
| 131 |
-
"""
|
| 132 |
-
# Assume image_data is a PIL.Image.Image object
|
| 133 |
-
|
| 134 |
-
if remove_bg:
|
| 135 |
-
# Assuming remove_bg function returns a PIL image
|
| 136 |
-
image_data = remove_bg_func(image_data)
|
| 137 |
-
|
| 138 |
-
if crop:
|
| 139 |
-
# Assuming autocrop_image function modifies the image in place or returns a new PIL image
|
| 140 |
-
image_data = autocrop_image(image_data)
|
| 141 |
-
|
| 142 |
-
if resize:
|
| 143 |
-
# Assuming resize_and_pad_image function modifies the image in place or returns a new PIL image
|
| 144 |
-
image_data = resize_and_pad_image(image_data, resize, padding)
|
| 145 |
-
|
| 146 |
-
if background:
|
| 147 |
-
# Assuming add_background function modifies the image in place or returns a new PIL image
|
| 148 |
-
image_data = add_background(image_data, background)
|
| 149 |
-
|
| 150 |
-
return image_data
|
| 151 |
-
|
| 152 |
|
| 153 |
def resize_and_pad_image(image, dimensions, padding=0):
|
| 154 |
"""
|
|
@@ -235,47 +235,6 @@ def generate_output_filename(input_path, remove_bg=False, crop=False, resize=Non
|
|
| 235 |
# Ensure to pass the crop argument to process_image and adjust the output filename generation accordingly
|
| 236 |
|
| 237 |
|
| 238 |
-
def process_images2(input_dir="./input", output_dir="./output", crop=False, remove_bg=False, resize=None, padding=0, background=None):
|
| 239 |
-
"""
|
| 240 |
-
Processes images in the specified directory based on the provided options.
|
| 241 |
-
|
| 242 |
-
Args:
|
| 243 |
-
- input_dir (str): Directory containing the images to be processed.
|
| 244 |
-
- output_dir (str): Directory where processed images will be saved.
|
| 245 |
-
- crop (bool): Whether to crop the images.
|
| 246 |
-
- remove_bg (bool): Whether to remove the background of the images.
|
| 247 |
-
- resize (tuple): Optional dimensions (width, height) to resize the image.
|
| 248 |
-
- padding (int): Number of padding pixels to add around the image.
|
| 249 |
-
- background (str): Optional background color (hex code or name) or path to an image file to set as the background.
|
| 250 |
-
"""
|
| 251 |
-
processed_input_dir = os.path.join(input_dir, "processed")
|
| 252 |
-
os.makedirs(processed_input_dir, exist_ok=True)
|
| 253 |
-
os.makedirs(output_dir, exist_ok=True)
|
| 254 |
-
|
| 255 |
-
inputs = [os.path.join(input_dir, f) for f in os.listdir(
|
| 256 |
-
input_dir) if os.path.isfile(os.path.join(input_dir, f))]
|
| 257 |
-
|
| 258 |
-
# if images are not in the input directory, print a message and return
|
| 259 |
-
if not inputs:
|
| 260 |
-
print("No images found in the input directory.")
|
| 261 |
-
return
|
| 262 |
-
|
| 263 |
-
for i, input_path in enumerate(inputs, start=1):
|
| 264 |
-
filename = os.path.basename(input_path)
|
| 265 |
-
output_filename = generate_output_filename(
|
| 266 |
-
input_path, remove_bg=remove_bg, crop=crop, resize=resize, background=background)
|
| 267 |
-
output_path = os.path.join(output_dir, output_filename)
|
| 268 |
-
print(f"Processing image {i}/{len(inputs)}...{filename}")
|
| 269 |
-
|
| 270 |
-
# Update the call to process_image with all parameters including background
|
| 271 |
-
process_image(input_path, output_path, crop=crop, remove_bg=remove_bg,
|
| 272 |
-
resize=resize, padding=padding, background=background)
|
| 273 |
-
|
| 274 |
-
shutil.move(input_path, os.path.join(processed_input_dir, filename))
|
| 275 |
-
|
| 276 |
-
print("All images have been processed.")
|
| 277 |
-
|
| 278 |
-
|
| 279 |
def process_images(input_dir="./input", output_dir="./output", crop=False, remove_bg=False, resize=None, padding=0, background=None):
|
| 280 |
"""
|
| 281 |
Processes images in the specified directory based on the provided options.
|
|
@@ -370,92 +329,3 @@ def save_image_with_format(image, output_path, format='webp', quality=90, custom
|
|
| 370 |
raise ValueError(f"Unsupported format: {format}")
|
| 371 |
|
| 372 |
return final_path
|
| 373 |
-
|
| 374 |
-
"""
|
| 375 |
-
Saves the image in the specified format with appropriate settings.
|
| 376 |
-
|
| 377 |
-
Args:
|
| 378 |
-
- image (PIL.Image.Image): The image to save
|
| 379 |
-
- output_path (str): Base path for the output file (without extension)
|
| 380 |
-
- format (str): 'webp', 'png', 'png-transparent', or 'jpg'
|
| 381 |
-
- quality (int): Quality setting for compression (1-100)
|
| 382 |
-
- custom_filename (str): Optional custom filename for the output
|
| 383 |
-
"""
|
| 384 |
-
# Get image dimensions for filename
|
| 385 |
-
width, height = image.size
|
| 386 |
-
|
| 387 |
-
# Generate the complete filename with path
|
| 388 |
-
if custom_filename:
|
| 389 |
-
base_dir = os.path.dirname(output_path)
|
| 390 |
-
final_path = os.path.join(base_dir, f"{custom_filename}_{width}x{height}")
|
| 391 |
-
else:
|
| 392 |
-
final_path = output_path
|
| 393 |
-
|
| 394 |
-
if format == 'webp':
|
| 395 |
-
final_path = f"{final_path}.webp"
|
| 396 |
-
image.save(final_path, 'webp', quality=quality)
|
| 397 |
-
elif format == 'png-transparent':
|
| 398 |
-
final_path = f"{final_path}.png"
|
| 399 |
-
image.save(final_path, 'PNG', optimize=True)
|
| 400 |
-
elif format == 'png':
|
| 401 |
-
final_path = f"{final_path}.png"
|
| 402 |
-
if image.mode in ('RGBA', 'LA'):
|
| 403 |
-
background = Image.new('RGB', image.size, 'white')
|
| 404 |
-
background.paste(image, mask=image.split()[-1])
|
| 405 |
-
background.save(final_path, 'PNG', optimize=True)
|
| 406 |
-
else:
|
| 407 |
-
image.save(final_path, 'PNG', optimize=True)
|
| 408 |
-
elif format == 'jpg':
|
| 409 |
-
final_path = f"{final_path}.jpg"
|
| 410 |
-
if image.mode in ('RGBA', 'LA'):
|
| 411 |
-
background = Image.new('RGB', image.size, 'white')
|
| 412 |
-
background.paste(image, mask=image.split()[-1])
|
| 413 |
-
background.save(final_path, 'JPEG', quality=quality, optimize=True)
|
| 414 |
-
else:
|
| 415 |
-
image.convert('RGB').save(final_path, 'JPEG', quality=quality, optimize=True)
|
| 416 |
-
else:
|
| 417 |
-
raise ValueError(f"Unsupported format: {format}")
|
| 418 |
-
|
| 419 |
-
return final_path
|
| 420 |
-
|
| 421 |
-
"""
|
| 422 |
-
Saves the image in the specified format with appropriate settings.
|
| 423 |
-
|
| 424 |
-
Args:
|
| 425 |
-
- image (PIL.Image.Image): The image to save
|
| 426 |
-
- output_path (str): Base path for the output file (without extension)
|
| 427 |
-
- format (str): 'webp', 'png', 'png-transparent', or 'jpg'
|
| 428 |
-
- quality (int): Quality setting for compression (1-100)
|
| 429 |
-
"""
|
| 430 |
-
if format == 'webp':
|
| 431 |
-
# Save as WebP with specified quality
|
| 432 |
-
final_path = f"{output_path}.webp"
|
| 433 |
-
image.save(final_path, 'webp', quality=quality)
|
| 434 |
-
elif format == 'png-transparent':
|
| 435 |
-
# Save as PNG with transparency
|
| 436 |
-
final_path = f"{output_path}.png"
|
| 437 |
-
image.save(final_path, 'PNG', optimize=True)
|
| 438 |
-
elif format == 'png':
|
| 439 |
-
# Save as PNG without transparency, with white background
|
| 440 |
-
final_path = f"{output_path}.png"
|
| 441 |
-
if image.mode in ('RGBA', 'LA'):
|
| 442 |
-
background = Image.new('RGB', image.size, 'white')
|
| 443 |
-
background.paste(image, mask=image.split()[-1])
|
| 444 |
-
background.save(final_path, 'PNG', optimize=True)
|
| 445 |
-
else:
|
| 446 |
-
image.save(final_path, 'PNG', optimize=True)
|
| 447 |
-
elif format == 'jpg':
|
| 448 |
-
# Save as JPG with white background
|
| 449 |
-
final_path = f"{output_path}.jpg"
|
| 450 |
-
if image.mode in ('RGBA', 'LA'):
|
| 451 |
-
# Convert transparent background to white for JPG
|
| 452 |
-
background = Image.new('RGB', image.size, 'white')
|
| 453 |
-
background.paste(image, mask=image.split()[-1])
|
| 454 |
-
background.save(final_path, 'JPEG', quality=quality, optimize=True)
|
| 455 |
-
else:
|
| 456 |
-
# Save directly if no transparency
|
| 457 |
-
image.convert('RGB').save(final_path, 'JPEG', quality=quality, optimize=True)
|
| 458 |
-
else:
|
| 459 |
-
raise ValueError(f"Unsupported format: {format}")
|
| 460 |
-
|
| 461 |
-
return final_path
|
|
|
|
| 44 |
return final_img
|
| 45 |
|
| 46 |
|
| 47 |
+
def cropnontrans(image, padding=0):
|
| 48 |
+
"""
|
| 49 |
+
crops a nontransparent image
|
| 50 |
+
|
| 51 |
+
Args:
|
| 52 |
+
- image (PIL.Image.Image): Image to be cropped.
|
| 53 |
+
|
| 54 |
+
Returns:
|
| 55 |
+
- PIL.Image.Image: The autocropped image.
|
| 56 |
+
"""
|
| 57 |
+
# first,
|
| 58 |
+
# Convert the PIL Image to bytes
|
| 59 |
+
img_byte_arr = io.BytesIO()
|
| 60 |
+
image.save(img_byte_arr, format='PNG')
|
| 61 |
+
img_byte_arr = img_byte_arr.getvalue()
|
| 62 |
+
# Use rembg to remove the background
|
| 63 |
+
result_bytes = remove(img_byte_arr)
|
| 64 |
+
|
| 65 |
+
# Convert the result bytes back to a PIL Image
|
| 66 |
+
transparent_image = Image.open(io.BytesIO(result_bytes))
|
| 67 |
+
bbox = transparent_image.getbbox()
|
| 68 |
+
# add padding area to the original bbox
|
| 69 |
+
if bbox:
|
| 70 |
+
bbox = (bbox[0]-padding, bbox[1]-padding, bbox[2]+padding, bbox[3]+padding)
|
| 71 |
+
#delimig the bbox to the image size
|
| 72 |
+
bbox = (max(0, bbox[0]), max(0, bbox[1]), min(transparent_image.width, bbox[2]), min(transparent_image.height, bbox[3]))
|
| 73 |
+
print(f"Bounding box: {bbox}")
|
| 74 |
+
return image.crop(bbox)
|
| 75 |
+
return image
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
|
| 79 |
def autocrop_image(image):
|
| 80 |
"""
|
| 81 |
Autocrops an image, focusing on the non-transparent pixels.
|
|
|
|
| 87 |
- PIL.Image.Image: The autocropped image.
|
| 88 |
"""
|
| 89 |
bbox = image.getbbox()
|
| 90 |
+
print(f"Bounding box: {bbox}")
|
| 91 |
if bbox:
|
| 92 |
return image.crop(bbox)
|
| 93 |
return image
|
|
|
|
| 135 |
if remove_bg:
|
| 136 |
img = remove_bg_func(img)
|
| 137 |
|
| 138 |
+
if crop and remove_bg:
|
| 139 |
img = autocrop_image(img)
|
| 140 |
+
if crop and not remove_bg:
|
| 141 |
+
img = cropnontrans(img, padding)
|
| 142 |
|
| 143 |
if resize:
|
| 144 |
img = resize_and_pad_image(img, resize, padding)
|
|
|
|
| 149 |
return img
|
| 150 |
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
def resize_and_pad_image(image, dimensions, padding=0):
|
| 154 |
"""
|
|
|
|
| 235 |
# Ensure to pass the crop argument to process_image and adjust the output filename generation accordingly
|
| 236 |
|
| 237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
def process_images(input_dir="./input", output_dir="./output", crop=False, remove_bg=False, resize=None, padding=0, background=None):
|
| 239 |
"""
|
| 240 |
Processes images in the specified directory based on the provided options.
|
|
|
|
| 329 |
raise ValueError(f"Unsupported format: {format}")
|
| 330 |
|
| 331 |
return final_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|