Spaces:
Running
Running
import requests | |
import gradio as gr | |
import zipfile | |
from PIL import Image | |
from io import BytesIO | |
from rembg import remove | |
def download_image(image_url: str) -> Image.Image: | |
# ์ด๋ฏธ์ง ๋ค์ด๋ก๋ | |
response = requests.get(image_url) | |
if response.status_code == 200: | |
original_image = Image.open(BytesIO(response.content)) | |
return original_image | |
else: | |
raise Exception(f"Failed to download image. Status code: {response.status_code}") | |
def remove_background(image: Image.Image) -> Image.Image: | |
# ์ด๋ฏธ์ง ๋๋ผ๋ฐ๊ธฐ | |
try: | |
removebg_image = remove( | |
image, | |
post_process_mask=True, | |
alpha_matting=True, | |
alpha_matting_foreground_threshold=270, | |
alpha_matting_background_threshold=30, | |
alpha_matting_erode_size=15) | |
return removebg_image | |
except Exception as e: | |
print(f"Failed to remove background: {e}") | |
return None | |
def crop_image(image: Image.Image) -> Image.Image: | |
# ์ด๋ฏธ์ง ํฌ๋กญ | |
try: | |
# ์ํ ์ฑ๋์ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง์ ๊ฒฝ๊ณ ์์ญ ์ฐพ๊ธฐ | |
bbox = image.getbbox() | |
if bbox: | |
# ๊ฒฝ๊ณ ์์๋ก ์ด๋ฏธ์ง ํฌ๋กญ | |
cropped_image = image.crop(bbox) | |
return cropped_image | |
else: | |
print("No bounding box found.") | |
return image | |
except Exception as e: | |
print(f"Failed to crop image: {e}") | |
return None | |
def resize_image(image: Image.Image, max_size: int) -> Image.Image: | |
# ์ด๋ฏธ์ง ํฌ๊ธฐ ์กฐ์ | |
try: | |
# ์ด๋ฏธ์ง์ ํ์ฌ ๋๋น์ ๋์ด ๊ฐ์ ธ์ค๊ธฐ | |
width, height = image.size | |
# ๋๋น์ ๋์ด ์ค ๋ ํฐ ์ชฝ์ ๋น์จ์ ๋ง์ถฐ ํฌ๊ธฐ๋ฅผ ์กฐ์ | |
if width > height: | |
new_width = max_size | |
new_height = int((max_size / width) * height) | |
else: | |
new_height = max_size | |
new_width = int((max_size / height) * width) | |
resized_image = image.resize((new_width, new_height)) | |
return resized_image | |
except Exception as e: | |
print(f"Failed to resize image: {e}") | |
return None | |
def paste_to_background_type_a(background: Image.Image, product: Image.Image) -> Image.Image: | |
# ๋ฐฐ๊ฒฝ์ ์ ํ ์ด๋ฏธ์ง ํฉ์ฑ | |
try: | |
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
bg_width, bg_height = background.size | |
# ์ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
product_width, product_height = product.size | |
# ์ ํ ์ด๋ฏธ์ง๋ฅผ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ์ค์์ ์์น์ํค๊ธฐ | |
offset = ((bg_width - product_width) // 2, (bg_height - product_height) // 2) | |
# ์ํ ์ฑ๋์ ๊ณ ๋ คํ์ฌ ํฉ์ฑ | |
background.paste(product, offset, mask=product) | |
return background | |
except Exception as e: | |
print(f"Failed to paste product image to background: {e}") | |
return None | |
def paste_to_background_type_b(background: Image.Image, product: Image.Image, margin: int = 10) -> Image.Image: | |
try: | |
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
bg_width, bg_height = background.size | |
# ์ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
product_width, product_height = product.size | |
# ๋ ์ ํ ์ด๋ฏธ์ง๋ฅผ ์ํ ์ ์ฒด ๋๋น ๊ณ์ฐ (์ ํ ์ด๋ฏธ์ง ๋ ๊ฐ + ๋ง์ง) | |
total_width = (product_width * 2) + margin | |
if total_width > bg_width: | |
raise ValueError("Background is too narrow to fit two product images with the specified margin.") | |
# ์ฒซ ๋ฒ์งธ ์ ํ ์ด๋ฏธ์ง์ ์ผ์ชฝ ์๋จ ์ขํ ๊ณ์ฐ | |
left_offset = (bg_width - total_width) // 2 | |
top_offset = (bg_height - product_height) // 2 | |
# ๋ ๋ฒ์งธ ์ ํ ์ด๋ฏธ์ง์ ์ผ์ชฝ ์๋จ ์ขํ ๊ณ์ฐ | |
right_offset = left_offset + product_width + margin | |
# ์ฒซ ๋ฒ์งธ ์ ํ ์ด๋ฏธ์ง ๋ฐฐ๊ฒฝ์ ํฉ์ฑ | |
background.paste(product, (left_offset, top_offset), mask=product) | |
# ๋ ๋ฒ์งธ ์ ํ ์ด๋ฏธ์ง ๋ฐฐ๊ฒฝ์ ํฉ์ฑ | |
background.paste(product, (right_offset, top_offset), mask=product) | |
return background | |
except Exception as e: | |
print(f"Failed to paste product images to background: {e}") | |
return None | |
def paste_to_background_type_c(background: Image.Image, product: Image.Image, margin: int = 10, top_margin: int = 15) -> Image.Image: | |
try: | |
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
bg_width, bg_height = background.size | |
# ์ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ๊ฐ์ ธ์ค๊ธฐ | |
product_width, product_height = product.size | |
# ๋จผ์ type_b ํํ๋ก ์๋ ๋ ์ ํ ์ด๋ฏธ์ง๋ฅผ ๋ฐฐ์น | |
background_with_two_products = paste_to_background_type_b(background, product, margin) | |
# ์ค์ ์๋จ์ ์์นํ ์ ํ ์ด๋ฏธ์ง์ ์คํ์ ๊ณ์ฐ | |
center_offset_x = (bg_width - product_width) // 2 | |
center_offset_y = ((bg_height - product_height) // 2) + top_margin | |
if center_offset_y < 0: | |
raise ValueError("Background is too small to fit three product images with the specified top margin.") | |
# ์ธ ๋ฒ์งธ ์ ํ ์ด๋ฏธ์ง ๋ฐฐ๊ฒฝ์ ํฉ์ฑ (์ค์ ์๋จ) | |
background_with_two_products.paste(product, (center_offset_x, center_offset_y), mask=product) | |
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ ์ฅ ๋ฐ ๋ฐํ | |
return background_with_two_products | |
except Exception as e: | |
print(f"Failed to paste product images to background: {e}") | |
return None | |
def create_zip_file(images: list, zip_filename: str = "images.zip") -> bytes: | |
# ๋ฉ๋ชจ๋ฆฌ ๋ด์์ ZIP ํ์ผ ์์ฑ | |
zip_buffer = BytesIO() | |
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
for i, image in enumerate(images): | |
# ์ด๋ฏธ์ง๋ฅผ ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ์ ์ ์ฅ | |
image_buffer = BytesIO() | |
image.save(image_buffer, format="PNG") | |
image_buffer.seek(0) | |
# ๋ฒํผ ๋ด์ฉ์ ZIP ํ์ผ์ ์ถ๊ฐ | |
zipf.writestr(f"image_{i + 1}.png", image_buffer.getvalue()) | |
# ZIP ํ์ผ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ | |
zip_buffer.seek(0) | |
return zip_buffer.getvalue() | |
def image_processing_single(background_image: Image.Image, product_image_url: str): | |
# ๊ฐ์ข ์ค์ ๊ฐ | |
product_image_size = 650 # ๋ฐฐ๊ฒฝ์ด ์ ๊ฑฐ๋ ์ ํ ์ด๋ฏธ์ง์ ํฌ๊ธฐ | |
type_b_margin = 15 | |
type_c_margin_1, type_c_margin_2 = 15, 45 # (1=๊ฐ์ด๋ฐ ๋๊ฐ์ ๋ง์ง, 2= ์ค์ ํ๊ฐ์ top ๋ง์ง) | |
# ์ด๋ฏธ์ง ๋ค์ด๋ก๋ | |
original_image = download_image(product_image_url) | |
# ์ด๋ฏธ์ง ๋๋ผ๋ฐ๊ธฐ | |
removebg_image = remove_background(original_image) | |
# ์ด๋ฏธ์ง ํฌ๋กญ | |
cropped_image = crop_image(removebg_image) | |
# ํฌ๋กญ๋ ์ด๋ฏธ์ง ์ํ๋ ์ฌ์ด์ฆ๋ก resize | |
resized_image = resize_image(cropped_image, product_image_size) | |
# type_a ํฉ์ฑ | |
type_a_image = paste_to_background_type_a(background_image.copy(), resized_image) | |
type_b_image = paste_to_background_type_b(background_image.copy(), resized_image, type_b_margin) | |
type_c_image = paste_to_background_type_c(background_image.copy(), resized_image, type_c_margin_1, type_c_margin_2) | |
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง ๋ฐํ | |
image_list = [type_a_image, type_b_image, type_c_image] | |
image_zip_file = create_zip_file(image_list) | |
return image_list #, image_zip_file | |
def image_processing_multi(background_image: Image.Image, product_image_url_list: list): | |
# ๊ฐ์ข ์ค์ ๊ฐ | |
product_image_size = 650 # ๋ฐฐ๊ฒฝ์ด ์ ๊ฑฐ๋ ์ ํ ์ด๋ฏธ์ง์ ํฌ๊ธฐ | |
type_b_margin = 15 | |
type_c_margin_1, type_c_margin_2 = 15, 45 # (1=๊ฐ์ด๋ฐ ๋๊ฐ์ ๋ง์ง, 2= ์ค์ ํ๊ฐ์ top ๋ง์ง) | |
for idx, product_image_url in enumerate(product_image_url_list): | |
# ์ด๋ฏธ์ง ๋ค์ด๋ก๋ | |
original_image = download_image(product_image_url) | |
# ์ด๋ฏธ์ง ๋๋ผ๋ฐ๊ธฐ | |
removebg_image = remove_background(original_image) | |
# ์ด๋ฏธ์ง ํฌ๋กญ | |
cropped_image = crop_image(removebg_image) | |
# ํฌ๋กญ๋ ์ด๋ฏธ์ง ์ํ๋ ์ฌ์ด์ฆ๋ก resize | |
resized_image = resize_image(cropped_image, product_image_size) | |
# type_a ํฉ์ฑ | |
type_a_image = paste_to_background_type_a(background_image.copy(), resized_image) | |
type_b_image = paste_to_background_type_b(background_image.copy(), resized_image, type_b_margin) | |
type_c_image = paste_to_background_type_c(background_image.copy(), resized_image, type_c_margin_1, type_c_margin_2) | |
with gr.Blocks(theme=gr.themes.Monochrome()) as demo: | |
with gr.Row(): | |
background_image = gr.Image(label="Background Image", type="pil") | |
with gr.Tab("Single"): | |
link = gr.Textbox(label="Image URL") | |
btn_single = gr.Button("Generate Images") | |
with gr.Tab("Multi"): | |
links = gr.File(label="Image URLs (.txt file)") | |
btn_multi = gr.Button("Generate Images") | |
with gr.Row(): | |
preview = gr.Gallery(label="Generated images", show_label=False, elem_id="gallery", columns=[3], rows=[1], object_fit="contain", height="auto") | |
output_zip = gr.File(label="Download Result Zip File") | |
# evnets | |
btn_single.click(fn=image_processing_single, inputs=[background_image, link], outputs=[preview], api_name="image_processing") | |
demo.launch() |