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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|