|
import os |
|
import tempfile |
|
from PIL import Image |
|
import gradio as gr |
|
import logging |
|
import re |
|
import time |
|
|
|
from google import genai |
|
from google.genai import types |
|
from dotenv import load_dotenv |
|
from transformers import pipeline |
|
|
|
load_dotenv() |
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
def remove_background(image): |
|
if image is None: |
|
return None, "์ด๋ฏธ์ง๊ฐ ์
๋ก๋๋์ง ์์์ต๋๋ค." |
|
|
|
try: |
|
logger.info("๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์์") |
|
|
|
|
|
pipe = pipeline("image-segmentation", model="briaai/RMBG-1.4", trust_remote_code=True) |
|
|
|
|
|
output_image = pipe(image) |
|
|
|
logger.info("๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์๋ฃ") |
|
return output_image, "๋ฐฐ๊ฒฝ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ๊ฑฐ๋์์ต๋๋ค." |
|
except Exception as e: |
|
logger.exception("๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์ค ์ค๋ฅ ๋ฐ์:") |
|
return None, f"์ค๋ฅ ๋ฐ์: {str(e)}" |
|
|
|
|
|
def save_binary_file(file_name, data): |
|
with open(file_name, "wb") as f: |
|
f.write(data) |
|
|
|
|
|
|
|
import cv2 |
|
import numpy as np |
|
from PIL import Image, ImageEnhance, ImageFilter |
|
import tempfile |
|
from datetime import datetime, timedelta |
|
|
|
|
|
def adjust_brightness(image, value): |
|
"""์ด๋ฏธ์ง ๋ฐ๊ธฐ ์กฐ์ """ |
|
value = float(value - 1) * 100 |
|
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
h, s, v = cv2.split(hsv) |
|
v = cv2.add(v, value) |
|
v = np.clip(v, 0, 255) |
|
final_hsv = cv2.merge((h, s, v)) |
|
return cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR) |
|
|
|
def adjust_contrast(image, value): |
|
"""์ด๋ฏธ์ง ๋๋น ์กฐ์ """ |
|
value = float(value) |
|
return np.clip(image * value, 0, 255).astype(np.uint8) |
|
|
|
def adjust_saturation(image, value): |
|
"""์ด๋ฏธ์ง ์ฑ๋ ์กฐ์ """ |
|
value = float(value - 1) * 100 |
|
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
h, s, v = cv2.split(hsv) |
|
s = cv2.add(s, value) |
|
s = np.clip(s, 0, 255) |
|
final_hsv = cv2.merge((h, s, v)) |
|
return cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR) |
|
|
|
def adjust_temperature(image, value): |
|
"""์ด๋ฏธ์ง ์์จ๋ ์กฐ์ (์์ ๋ฐธ๋ฐ์ค)""" |
|
value = float(value) * 30 |
|
b, g, r = cv2.split(image) |
|
if value > 0: |
|
r = cv2.add(r, value) |
|
b = cv2.subtract(b, value) |
|
else: |
|
r = cv2.add(r, value) |
|
b = cv2.subtract(b, value) |
|
|
|
r = np.clip(r, 0, 255) |
|
b = np.clip(b, 0, 255) |
|
return cv2.merge([b, g, r]) |
|
|
|
def adjust_tint(image, value): |
|
"""์ด๋ฏธ์ง ์์กฐ ์กฐ์ """ |
|
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) |
|
h, s, v = cv2.split(hsv_image) |
|
h = cv2.add(h, int(value)) |
|
h = np.clip(h, 0, 179) |
|
final_hsv = cv2.merge((h, s, v)) |
|
return cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR) |
|
|
|
def adjust_exposure(image, value): |
|
"""์ด๋ฏธ์ง ๋
ธ์ถ ์กฐ์ """ |
|
enhancer = ImageEnhance.Brightness(Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))) |
|
img_enhanced = enhancer.enhance(1 + float(value) / 5.0) |
|
return cv2.cvtColor(np.array(img_enhanced), cv2.COLOR_RGB2BGR) |
|
|
|
def adjust_vibrance(image, value): |
|
"""์ด๋ฏธ์ง ํ๊ธฐ ์กฐ์ """ |
|
img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
converter = ImageEnhance.Color(img) |
|
factor = 1 + (float(value) / 100.0) |
|
img = converter.enhance(factor) |
|
return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) |
|
|
|
def adjust_color_mixer_blues(image, value): |
|
"""์ด๋ฏธ์ง ์ปฌ๋ฌ ๋ฏน์ (๋ธ๋ฃจ) ์กฐ์ """ |
|
b, g, r = cv2.split(image) |
|
b = cv2.add(b, float(value)) |
|
b = np.clip(b, 0, 255) |
|
return cv2.merge([b, g, r]) |
|
|
|
def adjust_shadows(image, value): |
|
"""์ด๋ฏธ์ง ๊ทธ๋ฆผ์ ์กฐ์ """ |
|
pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
enhancer = ImageEnhance.Brightness(pil_image) |
|
factor = 1 + (float(value) / 100.0) |
|
pil_image = enhancer.enhance(factor) |
|
return cv2.cvtColor(np.array(pil_image), cv2.COLOR_BGR2RGB) |
|
|
|
def process_image(image, brightness, contrast, saturation, temperature, tint, exposure, vibrance, color_mixer_blues, shadows): |
|
"""๋ชจ๋ ์กฐ์ ์ฌํญ์ ์ด๋ฏธ์ง์ ์ ์ฉ""" |
|
if image is None: |
|
return None |
|
|
|
|
|
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) |
|
|
|
|
|
image = adjust_brightness(image, brightness) |
|
image = adjust_contrast(image, contrast) |
|
image = adjust_saturation(image, saturation) |
|
image = adjust_temperature(image, temperature) |
|
image = adjust_tint(image, tint) |
|
image = adjust_exposure(image, exposure) |
|
image = adjust_vibrance(image, vibrance) |
|
image = adjust_color_mixer_blues(image, color_mixer_blues) |
|
image = adjust_shadows(image, shadows) |
|
|
|
|
|
return Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
|
|
|
|
def translate_prompt_to_english(prompt): |
|
|
|
if not re.search("[๊ฐ-ํฃ]", prompt): |
|
return prompt |
|
|
|
prompt = prompt.replace("#1", "IMAGE_TAG_ONE") |
|
prompt = prompt.replace("#2", "IMAGE_TAG_TWO") |
|
prompt = prompt.replace("#3", "IMAGE_TAG_THREE") |
|
|
|
try: |
|
api_key = os.environ.get("GEMINI_API_KEY") |
|
if not api_key: |
|
logger.error("Gemini API ํค๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
prompt = prompt.replace("IMAGE_TAG_ONE", "#1") |
|
prompt = prompt.replace("IMAGE_TAG_TWO", "#2") |
|
prompt = prompt.replace("IMAGE_TAG_THREE", "#3") |
|
return prompt |
|
|
|
client = genai.Client(api_key=api_key) |
|
translation_prompt = f""" |
|
Translate the following Korean text to English: |
|
|
|
{prompt} |
|
|
|
IMPORTANT: The tokens IMAGE_TAG_ONE, IMAGE_TAG_TWO, and IMAGE_TAG_THREE are special tags |
|
and must be preserved exactly as is in your translation. Do not translate these tokens. |
|
""" |
|
|
|
logger.info(f"Translation prompt: {translation_prompt}") |
|
response = client.models.generate_content( |
|
model="gemini-2.0-flash", |
|
contents=[translation_prompt], |
|
config=types.GenerateContentConfig( |
|
response_modalities=['Text'], |
|
temperature=0.2, |
|
top_p=0.95, |
|
top_k=40, |
|
max_output_tokens=512 |
|
) |
|
) |
|
|
|
translated_text = "" |
|
for part in response.candidates[0].content.parts: |
|
if hasattr(part, 'text') and part.text: |
|
translated_text += part.text |
|
|
|
if translated_text.strip(): |
|
translated_text = translated_text.replace("IMAGE_TAG_ONE", "#1") |
|
translated_text = translated_text.replace("IMAGE_TAG_TWO", "#2") |
|
translated_text = translated_text.replace("IMAGE_TAG_THREE", "#3") |
|
logger.info(f"Translated text: {translated_text.strip()}") |
|
return translated_text.strip() |
|
else: |
|
logger.warning("๋ฒ์ญ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค. ์๋ณธ ํ๋กฌํํธ ์ฌ์ฉ") |
|
prompt = prompt.replace("IMAGE_TAG_ONE", "#1") |
|
prompt = prompt.replace("IMAGE_TAG_TWO", "#2") |
|
prompt = prompt.replace("IMAGE_TAG_THREE", "#3") |
|
return prompt |
|
except Exception as e: |
|
logger.exception("๋ฒ์ญ ์ค ์ค๋ฅ ๋ฐ์:") |
|
prompt = prompt.replace("IMAGE_TAG_ONE", "#1") |
|
prompt = prompt.replace("IMAGE_TAG_TWO", "#2") |
|
prompt = prompt.replace("IMAGE_TAG_THREE", "#3") |
|
return prompt |
|
|
|
def preprocess_prompt(prompt, image1, image2, image3): |
|
|
|
has_img1 = image1 is not None |
|
has_img2 = image2 is not None |
|
has_img3 = image3 is not None |
|
|
|
if "#1" in prompt and not has_img1: |
|
prompt = prompt.replace("#1", "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง(์์)") |
|
else: |
|
prompt = prompt.replace("#1", "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง") |
|
|
|
if "#2" in prompt and not has_img2: |
|
prompt = prompt.replace("#2", "๋ ๋ฒ์งธ ์ด๋ฏธ์ง(์์)") |
|
else: |
|
prompt = prompt.replace("#2", "๋ ๋ฒ์งธ ์ด๋ฏธ์ง") |
|
|
|
if "#3" in prompt and not has_img3: |
|
prompt = prompt.replace("#3", "์ธ ๋ฒ์งธ ์ด๋ฏธ์ง(์์)") |
|
else: |
|
prompt = prompt.replace("#3", "์ธ ๋ฒ์งธ ์ด๋ฏธ์ง") |
|
|
|
if "1. ์ด๋ฏธ์ง ๋ณ๊ฒฝ" in prompt: |
|
desc_match = re.search(r'#1์ "(.*?)"์ผ๋ก ๋ฐ๊ฟ๋ผ', prompt) |
|
if desc_match: |
|
description = desc_match.group(1) |
|
prompt = f"์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ {description}์ผ๋ก ๋ณ๊ฒฝํด์ฃผ์ธ์. ์๋ณธ ์ด๋ฏธ์ง์ ์ฃผ์ ๋ด์ฉ์ ์ ์งํ๋ ์๋ก์ด ์คํ์ผ๊ณผ ๋ถ์๊ธฐ๋ก ์ฌํด์ํด์ฃผ์ธ์." |
|
else: |
|
prompt = "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ์ฐฝ์์ ์ผ๋ก ๋ณํํด์ฃผ์ธ์. ๋ ์์ํ๊ณ ์์ ์ ์ธ ๋ฒ์ ์ผ๋ก ๋ง๋ค์ด์ฃผ์ธ์." |
|
|
|
elif "2. ๊ธ์์ง์ฐ๊ธฐ" in prompt: |
|
text_match = re.search(r'#1์์ "(.*?)"๋ฅผ ์ง์๋ผ', prompt) |
|
if text_match: |
|
text_to_remove = text_match.group(1) |
|
prompt = f"์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์์ '{text_to_remove}' ํ
์คํธ๋ฅผ ์ฐพ์ ์์ฐ์ค๋ฝ๊ฒ ์ ๊ฑฐํด์ฃผ์ธ์. ํ
์คํธ๊ฐ ์๋ ๋ถ๋ถ์ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ๋กญ๊ฒ ์ฑ์์ฃผ์ธ์." |
|
else: |
|
prompt = "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์์ ๋ชจ๋ ํ
์คํธ๋ฅผ ์ฐพ์ ์์ฐ์ค๋ฝ๊ฒ ์ ๊ฑฐํด์ฃผ์ธ์. ๊น๋ํ ์ด๋ฏธ์ง๋ก ๋ง๋ค์ด์ฃผ์ธ์." |
|
|
|
elif "4. ์ท๋ฐ๊พธ๊ธฐ" in prompt: |
|
prompt = "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์ ์ธ๋ฌผ ์์์ ๋ ๋ฒ์งธ ์ด๋ฏธ์ง์ ์์์ผ๋ก ๋ณ๊ฒฝํด์ฃผ์ธ์. ์์์ ์คํ์ผ๊ณผ ์์์ ๋ ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ๋ฐ๋ฅด๋, ์ ์ฒด ๋น์จ๊ณผ ํฌ์ฆ๋ ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ฅผ ์ ์งํด์ฃผ์ธ์." |
|
|
|
elif "5. ๋ฐฐ๊ฒฝ๋ฐ๊พธ๊ธฐ" in prompt: |
|
prompt = "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์ ๋ฐฐ๊ฒฝ์ ๋ ๋ฒ์งธ ์ด๋ฏธ์ง์ ๋ฐฐ๊ฒฝ์ผ๋ก ๋ณ๊ฒฝํด์ฃผ์ธ์. ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์ ์ฃผ์ ํผ์ฌ์ฒด๋ ์ ์งํ๊ณ , ๋ ๋ฒ์งธ ์ด๋ฏธ์ง์ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ๋กญ๊ฒ ํฉ์ฑํด์ฃผ์ธ์." |
|
|
|
elif "6. ์ด๋ฏธ์ง ํฉ์ฑ(์ํํฌํจ)" in prompt: |
|
prompt = "์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง์ ๋ ๋ฒ์งธ ์ด๋ฏธ์ง(๋๋ ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง)๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ํฉ์ฑํด์ฃผ์ธ์. ๋ชจ๋ ์ด๋ฏธ์ง์ ์ฃผ์ ์์๋ฅผ ํฌํจํ๊ณ , ํนํ ์ํ์ด ๋๋ณด์ด๋๋ก ์กฐํ๋กญ๊ฒ ํตํฉํด์ฃผ์ธ์." |
|
|
|
prompt += " ์ด๋ฏธ์ง๋ฅผ ์์ฑํด์ฃผ์ธ์. ์ด๋ฏธ์ง์ ํ
์คํธ๋ ๊ธ์๋ฅผ ํฌํจํ์ง ๋ง์ธ์." |
|
return prompt |
|
|
|
def generate_with_images(prompt, images, variation_index=0): |
|
|
|
try: |
|
api_key = os.environ.get("GEMINI_API_KEY") |
|
if not api_key: |
|
return None, "API ํค๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค. ํ๊ฒฝ๋ณ์๋ฅผ ํ์ธํด์ฃผ์ธ์." |
|
|
|
client = genai.Client(api_key=api_key) |
|
logger.info(f"Gemini API ์์ฒญ ์์ - ํ๋กฌํํธ: {prompt}, ๋ณํ ์ธ๋ฑ์ค: {variation_index}") |
|
|
|
variation_suffixes = [ |
|
" Create this as the first variation. Do not add any text, watermarks, or labels to the image.", |
|
" Create this as the second variation with more vivid colors. Do not add any text, watermarks, or labels to the image.", |
|
" Create this as the third variation with a more creative style. Do not add any text, watermarks, or labels to the image.", |
|
" Create this as the fourth variation with enhanced details. Do not add any text, watermarks, or labels to the image." |
|
] |
|
|
|
if variation_index < len(variation_suffixes): |
|
prompt = prompt + variation_suffixes[variation_index] |
|
else: |
|
prompt = prompt + " Do not add any text, watermarks, or labels to the image." |
|
|
|
contents = [prompt] |
|
for idx, img in enumerate(images, 1): |
|
if img is not None: |
|
contents.append(img) |
|
logger.info(f"์ด๋ฏธ์ง #{idx} ์ถ๊ฐ๋จ") |
|
|
|
response = client.models.generate_content( |
|
model="gemini-2.0-flash-exp-image-generation", |
|
contents=contents, |
|
config=types.GenerateContentConfig( |
|
response_modalities=['Text', 'Image'], |
|
temperature=1, |
|
top_p=0.95, |
|
top_k=40, |
|
max_output_tokens=8192 |
|
) |
|
) |
|
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp: |
|
temp_path = tmp.name |
|
result_text = "" |
|
image_found = False |
|
for part in response.candidates[0].content.parts: |
|
if hasattr(part, 'text') and part.text: |
|
result_text += part.text |
|
logger.info(f"์๋ต ํ
์คํธ: {part.text}") |
|
elif hasattr(part, 'inline_data') and part.inline_data: |
|
save_binary_file(temp_path, part.inline_data.data) |
|
image_found = True |
|
logger.info("์๋ต์์ ์ด๋ฏธ์ง ์ถ์ถ ์ฑ๊ณต") |
|
if not image_found: |
|
return None, f"API์์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ์ง ๋ชปํ์ต๋๋ค. ์๋ต ํ
์คํธ: {result_text}" |
|
|
|
result_img = Image.open(temp_path) |
|
if result_img.mode == "RGBA": |
|
result_img = result_img.convert("RGB") |
|
|
|
|
|
result_img.save(temp_path, format="JPEG", quality=95) |
|
|
|
|
|
return temp_path, f"์ด๋ฏธ์ง๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋์์ต๋๋ค. {result_text}" |
|
except Exception as e: |
|
logger.exception("์ด๋ฏธ์ง ์์ฑ ์ค ์ค๋ฅ ๋ฐ์:") |
|
return None, f"์ค๋ฅ ๋ฐ์: {str(e)}" |
|
|
|
def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0, max_retries=3): |
|
|
|
retry_count = 0 |
|
last_error = None |
|
|
|
while retry_count < max_retries: |
|
try: |
|
images = [image1, image2, image3] |
|
valid_images = [img for img in images if img is not None] |
|
if not valid_images: |
|
return None, "์ ์ด๋ ํ๋์ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํด์ฃผ์ธ์.", "" |
|
|
|
if prompt and prompt.strip(): |
|
processed_prompt = preprocess_prompt(prompt, image1, image2, image3) |
|
if re.search("[๊ฐ-ํฃ]", processed_prompt): |
|
final_prompt = translate_prompt_to_english(processed_prompt) |
|
else: |
|
final_prompt = processed_prompt |
|
else: |
|
if len(valid_images) == 1: |
|
final_prompt = "Please creatively transform this image into a more vivid and artistic version. Do not include any text or watermarks in the generated image." |
|
logger.info("Default prompt generated for single image") |
|
elif len(valid_images) == 2: |
|
final_prompt = "Please seamlessly composite these two images, integrating their key elements harmoniously into a single image. Do not include any text or watermarks in the generated image." |
|
logger.info("Default prompt generated for two images") |
|
else: |
|
final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene. Do not include any text or watermarks in the generated image." |
|
logger.info("Default prompt generated for three images") |
|
|
|
result_img, status = generate_with_images(final_prompt, valid_images, variation_index) |
|
if result_img is not None: |
|
|
|
return result_img, status, final_prompt |
|
else: |
|
last_error = status |
|
retry_count += 1 |
|
logger.warning(f"์ด๋ฏธ์ง ์์ฑ ์คํจ, ์ฌ์๋ {retry_count}/{max_retries}: {status}") |
|
time.sleep(1) |
|
except Exception as e: |
|
last_error = str(e) |
|
retry_count += 1 |
|
logger.exception(f"์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์, ์ฌ์๋ {retry_count}/{max_retries}:") |
|
time.sleep(1) |
|
|
|
return None, f"์ต๋ ์ฌ์๋ ํ์({max_retries}ํ) ์ด๊ณผ ํ ์คํจ: {last_error}", prompt |
|
|
|
def generate_multiple_images(image1, image2, image3, prompt, progress=gr.Progress()): |
|
|
|
results = [] |
|
statuses = [] |
|
prompts = [] |
|
|
|
num_images = 4 |
|
max_retries = 3 |
|
|
|
progress(0, desc="์ด๋ฏธ์ง ์์ฑ ์ค๋น ์ค...") |
|
|
|
for i in range(num_images): |
|
progress((i / num_images), desc=f"{i+1}/{num_images} ์ด๋ฏธ์ง ์์ฑ ์ค...") |
|
result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt, i, max_retries) |
|
|
|
if result_img is not None: |
|
|
|
results.append(result_img) |
|
statuses.append(f"์ด๋ฏธ์ง #{i+1}: {status}") |
|
prompts.append(f"์ด๋ฏธ์ง #{i+1}: {final_prompt}") |
|
else: |
|
results.append(None) |
|
statuses.append(f"์ด๋ฏธ์ง #{i+1} ์์ฑ ์คํจ: {status}") |
|
prompts.append(f"์ด๋ฏธ์ง #{i+1}: {final_prompt}") |
|
|
|
time.sleep(1) |
|
|
|
progress(1.0, desc="์ด๋ฏธ์ง ์์ฑ ์๋ฃ!") |
|
|
|
while len(results) < 4: |
|
results.append(None) |
|
|
|
combined_status = "\n".join(statuses) |
|
combined_prompts = "\n".join(prompts) |
|
|
|
return results[0], results[1], results[2], results[3], combined_status, combined_prompts |
|
|
|
|
|
|
|
import sys |
|
from torchvision.transforms import functional |
|
sys.modules["torchvision.transforms.functional_tensor"] = functional |
|
|
|
from basicsr.archs.srvgg_arch import SRVGGNetCompact |
|
from gfpgan.utils import GFPGANer |
|
from realesrgan.utils import RealESRGANer |
|
|
|
import torch |
|
import cv2 |
|
|
|
|
|
if not os.path.exists('realesr-general-x4v3.pth'): |
|
os.system("wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth -P .") |
|
if not os.path.exists('GFPGANv1.4.pth'): |
|
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth -P .") |
|
if not os.path.exists('RestoreFormer.pth'): |
|
os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth -P .") |
|
|
|
model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu') |
|
model_path = 'realesr-general-x4v3.pth' |
|
half = True if torch.cuda.is_available() else False |
|
upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=half) |
|
|
|
def upscaler(img, version, scale): |
|
try: |
|
img = cv2.imread(img, cv2.IMREAD_UNCHANGED) |
|
if len(img.shape) == 3 and img.shape[2] == 4: |
|
img_mode = 'RGBA' |
|
elif len(img.shape) == 2: |
|
img_mode = None |
|
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) |
|
else: |
|
img_mode = None |
|
|
|
h, w = img.shape[0:2] |
|
if h < 300: |
|
img = cv2.resize(img, (w * 2, h * 2), interpolation=cv2.INTER_LANCZOS4) |
|
|
|
face_enhancer = GFPGANer( |
|
model_path=f'{version}.pth', |
|
upscale=2, |
|
arch='RestoreFormer' if version=='RestoreFormer' else 'clean', |
|
channel_multiplier=2, |
|
bg_upsampler=upsampler |
|
) |
|
|
|
try: |
|
_, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) |
|
except RuntimeError as error: |
|
print('์ค๋ฅ ๋ฐ์:', error) |
|
|
|
try: |
|
if scale != 2: |
|
interpolation = cv2.INTER_AREA if scale < 2 else cv2.INTER_LANCZOS4 |
|
h, w = img.shape[0:2] |
|
output = cv2.resize(output, (int(w * scale / 2), int(h * scale / 2)), interpolation=interpolation) |
|
except Exception as error: |
|
print('์๋ชป๋ ์ค์ผ์ผ ์
๋ ฅ:', error) |
|
|
|
output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB) |
|
return output |
|
except Exception as error: |
|
print('์ ์ฒด ์์ธ ๋ฐ์:', error) |
|
return None |
|
|
|
def upscaler_korean(img): |
|
return upscaler(img, "GFPGANv1.4", 2) |
|
|
|
|
|
custom_css = """ |
|
:root { |
|
--primary-color: #5561e9; |
|
--secondary-color: #6c8aff; |
|
--accent-color: #ff6b6b; |
|
--background-color: #f0f5ff; |
|
--card-bg: #ffffff; |
|
--text-color: #334155; |
|
--border-radius: 18px; |
|
--shadow: 0 8px 30px rgba(0, 0, 0, 0.08); |
|
} |
|
|
|
body { |
|
font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; |
|
background-color: var(--background-color); |
|
color: var(--text-color); |
|
line-height: 1.6; |
|
} |
|
|
|
/* Gradio ์ปจํ
์ด๋ ์ค๋ฒ๋ผ์ด๋ */ |
|
.gradio-container { |
|
max-width: 100% !important; |
|
margin: 0 auto !important; |
|
padding: 0 !important; |
|
background-color: var(--background-color) !important; |
|
} |
|
|
|
/* ์๋จ ํค๋ */ |
|
.app-header { |
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); |
|
color: white; |
|
padding: 2rem; |
|
border-radius: var(--border-radius); |
|
margin-bottom: 1.5rem; |
|
box-shadow: var(--shadow); |
|
text-align: center; |
|
} |
|
|
|
.app-header h1 { |
|
margin: 0; |
|
font-size: 2.5rem; |
|
font-weight: 700; |
|
letter-spacing: -0.5px; |
|
} |
|
|
|
.app-header p { |
|
margin: 0.75rem 0 0; |
|
font-size: 1.1rem; |
|
opacity: 0.9; |
|
} |
|
|
|
/* ํจ๋ ์คํ์ผ๋ง */ |
|
.panel { |
|
background-color: var(--card-bg); |
|
border-radius: var(--border-radius); |
|
box-shadow: var(--shadow); |
|
padding: 1.5rem; |
|
margin-bottom: 1.5rem; |
|
border: 1px solid rgba(0, 0, 0, 0.04); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.panel:hover { |
|
transform: translateY(-5px); |
|
} |
|
|
|
/* ์น์
์ ๋ชฉ */ |
|
.section-title { |
|
font-size: 1.5rem; |
|
font-weight: 700; |
|
color: var(--primary-color); |
|
margin-bottom: 1rem; |
|
padding-bottom: 0.5rem; |
|
border-bottom: 2px solid var(--secondary-color); |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.section-title i { |
|
margin-right: 0.5rem; |
|
font-size: 1.4rem; |
|
} |
|
|
|
/* ๋ฒํผ ์คํ์ผ๋ง */ |
|
.custom-button { |
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); |
|
color: white !important; |
|
border: none !important; |
|
border-radius: calc(var(--border-radius) - 5px) !important; |
|
padding: 0.8rem 1.2rem !important; |
|
font-weight: 600 !important; |
|
cursor: pointer !important; |
|
transition: all 0.3s ease !important; |
|
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); |
|
text-transform: none !important; |
|
display: flex !important; |
|
align-items: center !important; |
|
justify-content: center !important; |
|
} |
|
|
|
.custom-button:hover { |
|
transform: translateY(-2px) !important; |
|
box-shadow: 0 7px 14px rgba(50, 50, 93, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08) !important; |
|
} |
|
|
|
.custom-button.primary { |
|
background: linear-gradient(135deg, var(--accent-color), #ff9a8b) !important; |
|
} |
|
|
|
.custom-button i { |
|
margin-right: 0.5rem; |
|
} |
|
|
|
/* ์ด๋ฏธ์ง ์ปจํ
์ด๋ */ |
|
.image-container { |
|
border-radius: var(--border-radius); |
|
overflow: hidden; |
|
border: 1px solid rgba(0, 0, 0, 0.08); |
|
transition: all 0.3s ease; |
|
background-color: white; |
|
} |
|
|
|
.image-container:hover { |
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
/* ํญ ์ปจํ
์ด๋ */ |
|
.custom-tabs { |
|
background-color: transparent !important; |
|
border: none !important; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.custom-tabs button { |
|
background-color: rgba(255, 255, 255, 0.7) !important; |
|
border: none !important; |
|
border-radius: var(--border-radius) var(--border-radius) 0 0 !important; |
|
padding: 0.8rem 1.5rem !important; |
|
font-weight: 600 !important; |
|
color: var(--text-color) !important; |
|
transition: all 0.3s ease !important; |
|
} |
|
|
|
.custom-tabs button[aria-selected="true"] { |
|
background-color: var(--primary-color) !important; |
|
color: white !important; |
|
} |
|
|
|
/* ์
๋ ฅ ํ๋ */ |
|
.custom-input { |
|
border-radius: calc(var(--border-radius) - 5px) !important; |
|
border: 1px solid rgba(0, 0, 0, 0.1) !important; |
|
padding: 0.8rem 1rem !important; |
|
transition: all 0.3s ease !important; |
|
} |
|
|
|
.custom-input:focus { |
|
border-color: var(--primary-color) !important; |
|
box-shadow: 0 0 0 2px rgba(85, 97, 233, 0.2) !important; |
|
} |
|
|
|
/* ์ฌ์ฉ์ ๋งค๋ด์ผ */ |
|
.user-manual { |
|
background-color: white; |
|
padding: 2rem; |
|
border-radius: var(--border-radius); |
|
box-shadow: var(--shadow); |
|
margin-top: 2rem; |
|
} |
|
|
|
.manual-title { |
|
font-size: 1.8rem; |
|
font-weight: 700; |
|
color: var(--primary-color); |
|
margin-bottom: 1.5rem; |
|
text-align: center; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.manual-title i { |
|
margin-right: 0.5rem; |
|
font-size: 1.8rem; |
|
} |
|
|
|
.manual-section { |
|
margin-bottom: 1.5rem; |
|
padding: 1.2rem; |
|
background-color: #f8faff; |
|
border-radius: calc(var(--border-radius) - 5px); |
|
} |
|
|
|
.manual-section-title { |
|
font-size: 1.3rem; |
|
font-weight: 700; |
|
margin-bottom: 1rem; |
|
color: var(--primary-color); |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.manual-section-title i { |
|
margin-right: 0.5rem; |
|
font-size: 1.2rem; |
|
} |
|
|
|
.manual-text { |
|
font-size: 1rem; |
|
line-height: 1.7; |
|
} |
|
|
|
.manual-text strong { |
|
color: var(--accent-color); |
|
} |
|
|
|
.tip-box { |
|
background-color: rgba(255, 107, 107, 0.1); |
|
border-left: 3px solid var(--accent-color); |
|
padding: 1rem 1.2rem; |
|
margin: 1rem 0; |
|
border-radius: 8px; |
|
} |
|
|
|
/* ๋ฒํผ ๊ทธ๋ฃน */ |
|
.button-grid { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); |
|
gap: 0.8rem; |
|
margin-bottom: 1.2rem; |
|
} |
|
|
|
/* ๋ก๋ฉ ์ ๋๋ฉ์ด์
*/ |
|
.progress-container { |
|
background-color: rgba(255, 255, 255, 0.9); |
|
border-radius: var(--border-radius); |
|
padding: 2rem; |
|
box-shadow: var(--shadow); |
|
text-align: center; |
|
} |
|
|
|
.progress-bar { |
|
height: 8px; |
|
border-radius: 4px; |
|
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color)); |
|
margin: 1rem 0; |
|
} |
|
|
|
/* ์์ ๊ทธ๋ฆฌ๋ */ |
|
.examples-grid { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); |
|
gap: 1rem; |
|
margin: 1.5rem 0; |
|
} |
|
|
|
.example-card { |
|
background: white; |
|
border-radius: var(--border-radius); |
|
overflow: hidden; |
|
box-shadow: var(--shadow); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.example-card:hover { |
|
transform: translateY(-5px); |
|
} |
|
|
|
/* ๋ฐ์ํ */ |
|
@media (max-width: 768px) { |
|
.button-grid { |
|
grid-template-columns: repeat(2, 1fr); |
|
} |
|
} |
|
|
|
/* ์ ์ฒด ์ธํฐํ์ด์ค ๋ฅ๊ทผ ๋ชจ์๋ฆฌ */ |
|
.block, .prose, .gr-prose, .gr-form, .gr-panel { |
|
border-radius: var(--border-radius) !important; |
|
} |
|
|
|
/* ๋ฉ์ธ ์ปจํ
์ธ ์คํฌ๋กค๋ฐ */ |
|
::-webkit-scrollbar { |
|
width: 8px; |
|
height: 8px; |
|
} |
|
|
|
::-webkit-scrollbar-track { |
|
background: rgba(0, 0, 0, 0.05); |
|
border-radius: 10px; |
|
} |
|
|
|
::-webkit-scrollbar-thumb { |
|
background: var(--secondary-color); |
|
border-radius: 10px; |
|
} |
|
""" |
|
|
|
|
|
fontawesome_link = """ |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" /> |
|
""" |
|
|
|
|
|
header_html = """ |
|
<div class="app-header"> |
|
<h1>โจ ์ด์ปค๋จธ์ค ์ ์ฉ ์ด๋ฏธ์ง ์์ฑ๊ธฐ(Ver1.1) โจ</h1> |
|
<p>์ฝ๊ณ ๋น ๋ฅด๊ฒ ์ํ ์ด๋ฏธ์ง๋ฅผ ํธ์งํ๊ณ ์์ฑํ์ธ์! ํ ๋ฒ์ ํด๋ฆญ์ผ๋ก ์ ๋ฌธ์ ์ธ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.</p> |
|
</div> |
|
""" |
|
|
|
|
|
user_manual_html = """ |
|
<div class="user-manual"> |
|
<div class="manual-title"><i class="fas fa-book"></i> ์ฌ์ฉ ์ค๋ช
์</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-magic"></i> ์ด์ปค๋จธ์ค ์ ์ฉ ์ด๋ฏธ์ง ์์ฑ๊ธฐ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">1๏ธโฃ ์ด๋ฏธ์ง ์
๋ก๋</span><br> |
|
์ต๋ 3๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ ํ์์
๋๋ค.<br><br> |
|
|
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">2๏ธโฃ ํ๋กฌํํธ ์
๋ ฅ ๋๋ ๋ฒํผ ์ ํ</span><br> |
|
๋ณํํ๊ณ ์ถ์ ๋ด์ฉ์ ์ง์ ์
๋ ฅํ๊ฑฐ๋, ๋ฏธ๋ฆฌ ์ ์๋ ๋ฒํผ ์ค ํ๋๋ฅผ ์ ํํ์ธ์.<br><br> |
|
|
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">3๏ธโฃ ์ด๋ฏธ์ง ์์ฑ</span><br> |
|
'์ด๋ฏธ์ง ์์ฑ' ๋ฒํผ์ ํด๋ฆญํ๋ฉด 4๊ฐ์ง ๋ฒ์ ์ ์ด๋ฏธ์ง๊ฐ ์์ฑ๋ฉ๋๋ค. |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-hashtag"></i> ์ด๋ฏธ์ง ์ฐธ์กฐ ๋ฐฉ๋ฒ</div> |
|
<p class="manual-text"> |
|
ํ๋กฌํํธ์์ ๋ค์ ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค: |
|
<ul> |
|
<li><strong style="font-size: 1.05rem;">#1</strong> - ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
<li><strong style="font-size: 1.05rem;">#2</strong> - ๋ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
<li><strong style="font-size: 1.05rem;">#3</strong> - ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ์๋ฅผ ๋ค์ด, "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2์ ์ ๊ธ๋ผ์ค)๋ฅผ ์ฐฉ์ฉํ ๋ชจ์ต"๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค. |
|
</div> |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-tools"></i> ์ฃผ์ ๊ธฐ๋ฅ</div> |
|
<div class="manual-text"> |
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;"> |
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-exchange-alt"></i> ์ด๋ฏธ์ง ๋ณ๊ฒฝ</p> |
|
ํฌ์ฆ๋ ์คํ์ผ์ ๋ณ๊ฒฝํ๋ฉด์ ์๋ณธ์ ์ฃผ์ ์์๋ ์ ์งํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-eraser"></i> ๊ธ์ ์ง์ฐ๊ธฐ/๋ณ๊ฒฝ</p> |
|
์ด๋ฏธ์ง์ ํ
์คํธ๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ์ ๊ฑฐํ๊ฑฐ๋ ๋ค๋ฅธ ํ
์คํธ๋ก ๋ณ๊ฒฝํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-tshirt"></i> ๊ฐ์ ์ํ์ฐฉ์ฉ</p> |
|
๋ชจ๋ธ์๊ฒ ๋ค๋ฅธ ์ด๋ฏธ์ง์ ์ํ์ ์์ฐ์ค๋ฝ๊ฒ ์ฐฉ์ฉ์ํต๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-image"></i> ๋ฐฐ๊ฒฝ ๋ฐ๊พธ๊ธฐ</p> |
|
์ฃผ์ ํผ์ฌ์ฒด๋ ์ ์งํ๋ฉฐ ๋ฐฐ๊ฒฝ๋ง ๊ต์ฒดํฉ๋๋ค. |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-search-plus"></i> ์ด๋ฏธ์ง ์
์ค์ผ์ผ๋ฌ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">์ด๋ฏธ์ง ๊ฐ์ ๊ธฐ๋ฅ</span><br> |
|
์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๊ณ ํด์๋๋ก ๋ณํํ๊ณ , ์ผ๊ตด์ ์์ฐ์ค๋ฝ๊ฒ ๋ณต์ํฉ๋๋ค.<br> |
|
ํนํ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ํจ๊ณผ์ ์
๋๋ค: |
|
<ul> |
|
<li>ํด์๋๊ฐ ๋ฎ์ ์ด๋ฏธ์ง ๊ฐ์ </li> |
|
<li>ํ๋ฆฟํ๊ฑฐ๋ ๋
ธ์ด์ฆ๊ฐ ์๋ ์ผ๊ตด ๋ณต์</li> |
|
<li>์ด๋ฏธ์ง ์ ๋ฐ์ ์ธ ์ ๋ช
๋ ํฅ์</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ ์์์๋ก ์ฒ๋ฆฌ ์๋๊ฐ ๋น ๋ฆ
๋๋ค. ์ผ๊ตด์ด ํฌํจ๋ ์ด๋ฏธ์ง์์ ๊ฐ์ฅ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. |
|
</div> |
|
</p> |
|
</div> |
|
</div> |
|
""" |
|
|
|
|
|
with gr.Blocks(css=custom_css) as demo: |
|
gr.HTML(fontawesome_link) |
|
gr.HTML(header_html) |
|
|
|
with gr.Tabs(elem_classes="custom-tabs") as tabs: |
|
|
|
with gr.TabItem("๐ ์ฌ์ฉ ์ค๋ช
์", elem_classes="tab-content"): |
|
gr.HTML(""" |
|
<div class="user-manual"> |
|
<div class="manual-title"><i class="fas fa-book"></i> ์ฌ์ฉ ์ค๋ช
์</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-magic"></i> ์ด์ปค๋จธ์ค์ ์ฉ ์ด๋ฏธ์ง ์์ฑ๊ธฐ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">1๏ธโฃ ์ด๋ฏธ์ง ์
๋ก๋</span><br> |
|
์ต๋ 3๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง๋ ํ์์
๋๋ค.<br><br> |
|
|
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">2๏ธโฃ ํ๋กฌํํธ ์
๋ ฅ ๋๋ ๋ฒํผ ์ ํ</span><br> |
|
๋ณํํ๊ณ ์ถ์ ๋ด์ฉ์ ์ง์ ์
๋ ฅํ๊ฑฐ๋, ๋ฏธ๋ฆฌ ์ ์๋ ๋ฒํผ ์ค ํ๋๋ฅผ ์ ํํ์ธ์.<br><br> |
|
|
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">3๏ธโฃ ์ด๋ฏธ์ง ์์ฑ</span><br> |
|
'์ด๋ฏธ์ง ์์ฑ (1์ฅ)' ๋ฒํผ์ ํด๋ฆญํ๋ฉด 1๊ฐ์ ์ด๋ฏธ์ง๊ฐ, '์ด๋ฏธ์ง ์์ฑ (4์ฅ)' ๋ฒํผ์ ํด๋ฆญํ๋ฉด 4๊ฐ์ง ๋ฒ์ ์ ์ด๋ฏธ์ง๊ฐ ์์ฑ๋ฉ๋๋ค. |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-hashtag"></i> ์ด๋ฏธ์ง ์ฐธ์กฐ ๋ฐฉ๋ฒ</div> |
|
<p class="manual-text"> |
|
ํ๋กฌํํธ์์ ๋ค์ ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค: |
|
<ul> |
|
<li><strong style="font-size: 1.05rem;">#1</strong> - ์ฒซ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
<li><strong style="font-size: 1.05rem;">#2</strong> - ๋ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
<li><strong style="font-size: 1.05rem;">#3</strong> - ์ธ ๋ฒ์งธ ์ด๋ฏธ์ง</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ์๋ฅผ ๋ค์ด, "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2์ ์ ๊ธ๋ผ์ค)๋ฅผ ์ฐฉ์ฉํ ๋ชจ์ต"๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค. |
|
</div> |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-tools"></i> ์ฃผ์ ๊ธฐ๋ฅ</div> |
|
<div class="manual-text"> |
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;"> |
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-exchange-alt"></i> ์ด๋ฏธ์ง ๋ณ๊ฒฝ</p> |
|
ํฌ์ฆ๋ ์คํ์ผ์ ๋ณ๊ฒฝํ๋ฉด์ ์๋ณธ์ ์ฃผ์ ์์๋ ์ ์งํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-eraser"></i> ๊ธ์ ์ง์ฐ๊ธฐ/๋ณ๊ฒฝ</p> |
|
์ด๋ฏธ์ง์ ํ
์คํธ๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ์ ๊ฑฐํ๊ฑฐ๋ ๋ค๋ฅธ ํ
์คํธ๋ก ๋ณ๊ฒฝํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-tshirt"></i> ๊ฐ์ ์ํ์ฐฉ์ฉ</p> |
|
๋ชจ๋ธ์๊ฒ ๋ค๋ฅธ ์ด๋ฏธ์ง์ ์ํ์ ์์ฐ์ค๋ฝ๊ฒ ์ฐฉ์ฉ์ํต๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-image"></i> ๋ฐฐ๊ฒฝ ๋ฐ๊พธ๊ธฐ</p> |
|
์ฃผ์ ํผ์ฌ์ฒด๋ ์ ์งํ๋ฉฐ ๋ฐฐ๊ฒฝ๋ง ๊ต์ฒดํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-cut"></i> ๋ถ๋ถ ์ง์ฐ๊ธฐ</p> |
|
์ด๋ฏธ์ง์ ํน์ ๋ถ๋ถ์ ์ง์ฐ๊ณ ๋ฐฐ๊ฒฝ๊ณผ ์์ฐ์ค๋ฝ๊ฒ ์กฐํ๋๋๋ก ์ฑ์๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-wine-glass"></i> ์ํ๋ค๊ณ ์๊ธฐ</p> |
|
๋ชจ๋ธ์ด ์ํ์ ๋ค๊ณ ์๋ ์์ฐ์ค๋ฌ์ด ํฌ์ฆ์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํฉ๋๋ค. |
|
</div> |
|
|
|
<div> |
|
<p style="font-size: 1.1rem; font-weight: 600; color: #ff6b6b;"><i class="fas fa-expand-alt"></i> ์ด๋ฏธ์ง ํ์ฅ</p> |
|
์๋ณธ ์ด๋ฏธ์ง ์ฃผ๋ณ์ ์์ฐ์ค๋ฝ๊ฒ ์ถ๊ฐ ์์ญ์ ์์ฑํ์ฌ ์ด๋ฏธ์ง๋ฅผ ํ์ฅํฉ๋๋ค. |
|
</div> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-search-plus"></i> ์ด๋ฏธ์ง ์
์ค์ผ์ผ๋ฌ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">์ด๋ฏธ์ง ๊ฐ์ ๊ธฐ๋ฅ</span><br> |
|
์ ํด์๋ ์ด๋ฏธ์ง๋ฅผ ๊ณ ํด์๋๋ก ๋ณํํ๊ณ , ์ผ๊ตด์ ์์ฐ์ค๋ฝ๊ฒ ๋ณต์ํฉ๋๋ค.<br> |
|
ํนํ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ํจ๊ณผ์ ์
๋๋ค: |
|
<ul> |
|
<li>ํด์๋๊ฐ ๋ฎ์ ์ด๋ฏธ์ง ๊ฐ์ </li> |
|
<li>ํ๋ฆฟํ๊ฑฐ๋ ๋
ธ์ด์ฆ๊ฐ ์๋ ์ผ๊ตด ๋ณต์</li> |
|
<li>์ด๋ฏธ์ง ์ ๋ฐ์ ์ธ ์ ๋ช
๋ ํฅ์</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ ์์์๋ก ์ฒ๋ฆฌ ์๋๊ฐ ๋น ๋ฆ
๋๋ค. ์ผ๊ตด์ด ํฌํจ๋ ์ด๋ฏธ์ง์์ ๊ฐ์ฅ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. |
|
</div> |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-cut"></i> ๋ฐฐ๊ฒฝ ์ง์ฐ๊ธฐ ๊ธฐ๋ฅ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">์๋ ๋ฐฐ๊ฒฝ ์ ๊ฑฐ</span><br> |
|
์ด๋ฏธ์ง์์ ๋ฐฐ๊ฒฝ์ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์ ๊ฑฐํ์ฌ ํฌ๋ช
ํ PNG ์ด๋ฏธ์ง๋ก ๋ณํํฉ๋๋ค.<br> |
|
์ฃผ์ ์ฌ์ฉ ์ฌ๋ก: |
|
<ul> |
|
<li>์ ํ ์ด๋ฏธ์ง์ ๋ฐฐ๊ฒฝ ์ ๊ฑฐ</li> |
|
<li>์ธ๋ฌผ ์ฌ์ง์์ ๋ฐฐ๊ฒฝ ๋ถ๋ฆฌ</li> |
|
<li>์ฌ๋ฌ ์ด๋ฏธ์ง ํฉ์ฑ์ ์ํ ์ค๋น</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ๋ฐฐ๊ฒฝ๊ณผ ์ฃผ์ ํผ์ฌ์ฒด ๊ฐ์ ๋๋น๊ฐ ๋๋ ทํ ์๋ก ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋ณต์กํ ๋ฐฐ๊ฒฝ์ ๊ฒฝ์ฐ ๋ฏธ์ธ ์กฐ์ ์ด ํ์ํ ์ ์์ต๋๋ค. |
|
</div> |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-sliders-h"></i> ์ด๋ฏธ์ง ํํฐ ๊ธฐ๋ฅ</div> |
|
<p class="manual-text"> |
|
<span style="font-size: 1.1rem; font-weight: 600; color: #5561e9;">์ด๋ฏธ์ง ํธ์ง ๋๊ตฌ</span><br> |
|
์ด๋ฏธ์ง ํํฐ ํญ์์๋ ๋ค์ํ ์ฌ๋ผ์ด๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์ฝ๊ฒ ํธ์งํ ์ ์์ต๋๋ค.<br> |
|
์ฃผ์ ๊ธฐ๋ฅ: |
|
<ul> |
|
<li>๋ฐ๊ธฐ, ๋๋น, ์ฑ๋, ์์จ๋ ๋ฑ ๋ค์ํ ์กฐ์ ์ต์
</li> |
|
<li>๋ชจ๋ ๋ณ๊ฒฝ์ฌํญ ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ</li> |
|
<li>ํธ์ง ์๋ฃ ํ JPG ํ์์ผ๋ก ์ ์ฅ ๊ฐ๋ฅ</li> |
|
</ul> |
|
|
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ๊ฐ ์ฌ๋ผ์ด๋๋ฅผ ์กฐ๊ธ์ฉ ์กฐ์ ํ๋ฉฐ ์ํ๋ ํจ๊ณผ๋ฅผ ์ฐพ์๋ณด์ธ์. |
|
</div> |
|
</p> |
|
</div> |
|
|
|
<div class="manual-section"> |
|
<div class="manual-section-title"><i class="fas fa-question-circle"></i> ์์ฃผ ๋ฌป๋ ์ง๋ฌธ</div> |
|
<p class="manual-text"> |
|
<strong style="font-size: 1.1rem; color: #5561e9;">Q: ์ด๋ค ํ์์ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ ์ ์๋์?</strong><br> |
|
A: JPG, PNG, WEBP ๋ฑ ๋๋ถ๋ถ์ ์ผ๋ฐ์ ์ธ ์ด๋ฏธ์ง ํ์์ ์ง์ํฉ๋๋ค.<br><br> |
|
|
|
<strong style="font-size: 1.1rem; color: #5561e9;">Q: ์ด๋ฏธ์ง ์์ฑ ๋ฐ ์ฒ๋ฆฌ์ ์ผ๋ง๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋์?</strong><br> |
|
A: ์ผ๋ฐ์ ์ผ๋ก 10-30์ด ์ ๋ ์์๋๋ฉฐ, ์ด๋ฏธ์ง ํฌ๊ธฐ์ ๋ณต์ก๋์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.<br><br> |
|
|
|
<strong style="font-size: 1.1rem; color: #5561e9;">Q: ์์ฑ๋ ์ด๋ฏธ์ง๋ฅผ ์ด๋ป๊ฒ ์ ์ฅํ ์ ์๋์?</strong><br> |
|
A: ์์ฑ๋ ์ด๋ฏธ์ง์ ๋ง์ฐ์ค ์ค๋ฅธ์ชฝ ๋ฒํผ์ ํด๋ฆญํ์ฌ '์ด๋ฏธ์ง ์ ์ฅ' ์ต์
์ ์ ํํ๋ฉด ๋ฉ๋๋ค. |
|
</p> |
|
</div> |
|
</div> |
|
""") |
|
|
|
with gr.TabItem("โจ ์ด์ปค๋จธ์ค ์ด๋ฏธ์ง ์์ฑ๊ธฐ", elem_classes="tab-content"): |
|
with gr.Row(equal_height=True): |
|
with gr.Column(scale=1): |
|
with gr.Group(elem_classes="panel"): |
|
gr.HTML('<div class="section-title"><i class="fas fa-upload"></i> ์ด๋ฏธ์ง ์
๋ก๋</div>') |
|
with gr.Row(): |
|
image1_input = gr.Image(type="pil", label="#1", image_mode="RGB", elem_classes="image-container", height=400) |
|
image2_input = gr.Image(type="pil", label="#2", image_mode="RGB", elem_classes="image-container", height=400) |
|
image3_input = gr.Image(type="pil", label="#3", image_mode="RGB", elem_classes="image-container", height=400) |
|
|
|
gr.HTML('<div class="section-title"><i class="fas fa-keyboard"></i> ํ๋กฌํํธ ์
๋ ฅ</div>') |
|
prompt_input = gr.Textbox( |
|
lines=3, |
|
placeholder="ํ๋กฌํํธ๋ฅผ ์
๋ ฅํ๊ฑฐ๋ ๋น์๋๋ฉด ์๋ ํฉ์ฑ๋ฉ๋๋ค. '#1', '#2', '#3'์ผ๋ก ๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค.", |
|
label="ํ๋กฌํํธ (์ ํ ์ฌํญ)", |
|
elem_classes="custom-input" |
|
) |
|
|
|
gr.HTML('<div class="section-title"><i class="fas fa-sliders-h"></i> ๋ณํ ์ต์
</div>') |
|
with gr.Column(elem_classes="button-grid"): |
|
image_change_btn1 = gr.Button('๐ ์ด๋ฏธ์ง ๋ณ๊ฒฝ-1', elem_classes="custom-button") |
|
image_change_btn2 = gr.Button('๐ ์ด๋ฏธ์ง ๋ณ๊ฒฝ-2', elem_classes="custom-button") |
|
text_remove_btn = gr.Button('๐งน ๊ธ์ ์ง์ฐ๊ธฐ', elem_classes="custom-button") |
|
text_change_btn = gr.Button('๐ค ๊ธ์ ๋ณ๊ฒฝ', elem_classes="custom-button") |
|
clothes_change_btn1 = gr.Button('๐ ์ํ์ฐฉ์ฉ-1', elem_classes="custom-button") |
|
clothes_change_btn2 = gr.Button('๐ ์ํ์ฐฉ์ฉ-2', elem_classes="custom-button") |
|
holding_product_btn = gr.Button('๐ท ์ํ๋ค๊ณ ์๊ธฐ', elem_classes="custom-button") |
|
background_change_btn = gr.Button('๐ผ๏ธ ๋ฐฐ๊ฒฝ ๋ฐ๊พธ๊ธฐ', elem_classes="custom-button") |
|
composite_product_btn = gr.Button('โ๏ธ ๋ถ๋ถ ์ง์ฐ๊ธฐ', elem_classes="custom-button") |
|
outpainting_btn = gr.Button('๐ ์ด๋ฏธ์ง ํ์ฅ', elem_classes="custom-button") |
|
|
|
submit_single_btn = gr.Button('โจ ์ด๋ฏธ์ง ์์ฑ (1์ฅ)', elem_classes="custom-button primary") |
|
submit_btn = gr.Button('โจ ์ด๋ฏธ์ง ์์ฑ (4์ฅ)', elem_classes="custom-button primary") |
|
|
|
with gr.Column(scale=1): |
|
with gr.Group(elem_classes="panel"): |
|
gr.HTML('<div class="section-title"><i class="fas fa-images"></i> ์์ฑ๋ ์ด๋ฏธ์ง</div>') |
|
with gr.Row(): |
|
with gr.Column(): |
|
output_image1 = gr.Image(label="์ด๋ฏธ์ง #1", elem_classes="image-container", height=400, type="filepath") |
|
output_image3 = gr.Image(label="์ด๋ฏธ์ง #3", elem_classes="image-container", height=400, type="filepath") |
|
with gr.Column(): |
|
output_image2 = gr.Image(label="์ด๋ฏธ์ง #2", elem_classes="image-container", height=400, type="filepath") |
|
output_image4 = gr.Image(label="์ด๋ฏธ์ง #4", elem_classes="image-container", height=400, type="filepath") |
|
|
|
gr.HTML('<div class="section-title"><i class="fas fa-info-circle"></i> ๊ฒฐ๊ณผ ์ ๋ณด</div>') |
|
output_text = gr.Textbox(label="์ํ ๋ฉ์์ง", lines=2, elem_classes="custom-input") |
|
prompt_display = gr.Textbox(label="์ฌ์ฉ๋ ํ๋กฌํํธ (์์ด)", visible=True, lines=2, elem_classes="custom-input") |
|
|
|
gr.HTML('<div class="section-title"><i class="fas fa-lightbulb"></i> ์์ ์ด๋ฏธ์ง</div>') |
|
with gr.Group(elem_classes="panel"): |
|
examples = [ |
|
["down/๋ชจ๋ธ.jpg", None, None, "(#1์ ์ฌ์ฑ)์ด ์ด์ง ๋ค๋ก ๋์๋ณด๋ ๋ชจ์ต์ผ๋ก ์ต๋ํ ์ด์ seed๋ฅผ ์ ์งํ์ฒด ์์ฐ์ค๋ฝ๊ฒ ๋ณ๊ฒฝํ๋ผ."], |
|
["down/์์ด๋ ๊ณ ๋ชจํ.png", None, None, "(#1 ๋ ๋ชจ๋ชจํ)์์ ์ฒญ์์์ด๋ ๊ณ ๋ง ๊ฒ์์ ๊ณ ๋๋ ๊ณ ๋ก ๋ณ๊ฒฝํ๊ณ ๋๋จธ์ง ๋ถ๋ถ์ seed๋ฅผ ๋ณ๊ฒฝ์ ํ์ง๋ง๋ผ."], |
|
["down/์ค๊ตญ์ด.png", None, None, "(#1 ์ด๋ฏธ์ง)์ ์๋ ์ค๊ตญ์ด๋ฅผ ๋ชจ๋ ์ ๊ฑฐํ๋ผ."], |
|
["down/ํ
์คํธ.webp", None, None, '(#1์ ํ
์คํธ)๋ฅผ ์คํ์ผ์ ์ ์งํ์ฒด ํ
์คํธ๋ง "Hello"๋ก ๋ฐ๊ฟ๋ผ'], |
|
["down/๋ชจ๋ธ.jpg", "down/์ ๊ธ๋ผ์ค.png", "down/์ฒญ๋ฐ์ง.png", "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด ์ ์ฒด ๋น์จ๊ณผ ํฌ์ฆ๋ ์ ์นํ ์ฒด (#2์ ์ ๊ธ๋ผ์ค)์ (#3์ ์ฒญ๋ฐ์ง)๋ฅผ ์ง์ ๋ชจ๋ธ์ด ์ฐฉ์ฉํ๊ฒ์ฒ๋ผ ์์ฐ์ค๋ฌ์ด ๋ชจ์ต"], |
|
["down/๋ชจ๋ธ.jpg", "down/์ ๊ธ๋ผ์ค.png", "down/์นดํ์ ๊ฒฝ.png", "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2์ ์ ๊ธ๋ผ์ค)์ ์ฐฉ์ฉํ๊ณ (#3์ ๋ท๋ฐฐ๊ฒฝ์ ์นดํ์ ์ฒด๊ฐ ๋ณด์ด๋ฉฐ) ์์์ ์์ ์๋ ๋ชจ์ต."], |
|
["down/๋ชจ๋ธ.jpg", "down/์์ธ์.png", None, "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด(#2์ ์์ธ์)์ ๋ค๊ณ ์๋ ์์ฐ์ค๋ฌ์ด ๋ชจ์ต"], |
|
["down/๋ชจ๋ธ.jpg", "down/์นดํ์ ๊ฒฝ.png", None, "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2 ์นดํ)์์ ์์ฐ์ค๋ฝ๊ฒ ์๋ ๋ชจ์ต"], |
|
["down/์์ด๋ ๊ณ ๋ชจํ.png", None, None, "(#1์ ๋ ๊ณ ๋ชจํ)์์ ์ฒญ์์์ด๋ ๊ณ ๋ฅผ ์ ๊ฑฐํ ํ, ๊ทธ ์๋ฆฌ๋ฅผ ์ฃผ๋ณ ๋ฐฐ๊ฒฝ๊ณผ ์์ฐ์ค๋ฝ๊ฒ ์ด์ฐ๋ฌ์ง๋๋ก ์ฑ์์ฃผ์ธ์. ๋จ, ์ด๋ฏธ์ง์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ฃผ์ ์์๋ ๋์ผํ๊ฒ ์ ์งํด ํด์ผํ๋ค."], |
|
["down/์นดํ์ ๊ฒฝ.png", None, None, "(#1 ์ด๋ฏธ์ง)๋ฅผ ์๋ณธ๊ทธ๋๋ก ์ค์์ ๋๊ณ ๋น์จ๋ก ์ ์งํ ์ฒด ์์๋ ๋ฐ ์ข์ฐ๋ก ํฌ๊ฒ ํ์ฅํ๋ผ."] |
|
] |
|
|
|
gr.Examples( |
|
examples=examples, |
|
inputs=[image1_input, image2_input, image3_input, prompt_input] |
|
) |
|
|
|
with gr.TabItem("๐ ์ด๋ฏธ์ง ์
์ค์ผ์ผ๋ฌ", elem_classes="tab-content"): |
|
with gr.Row(): |
|
with gr.Column(elem_classes="panel"): |
|
gr.HTML('<div class="section-title"><i class="fas fa-search-plus"></i> ์ด๋ฏธ์ง ์
์ค์ผ์ผ & ๋ณต์</div>') |
|
gr.HTML(""" |
|
<p style="margin-bottom: 1rem; font-size: 1.05rem;"> |
|
์ด๋ฏธ์ง๋ฅผ ์
์ค์ผ์ผ๋ฌํฉ๋๋ค. |
|
</p> |
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ํด์๋๊ฐ ๋ฎ๊ฑฐ๋ ํ์ง์ด ๋จ์ด์ง๋ ์ด๋ฏธ์ง, ํนํ ์ผ๊ตด ์ด๋ฏธ์ง์ ํจ๊ณผ์ ์
๋๋ค. |
|
</div> |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-upload"></i> ์
๋ ฅ ์ด๋ฏธ์ง</div>') |
|
gfpgan_input = gr.Image(type="filepath", label="์
๋ก๋", elem_classes="image-container") |
|
|
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-download"></i> ๊ฒฐ๊ณผ ์ด๋ฏธ์ง</div>') |
|
gfpgan_output = gr.Image(type="numpy", label="์
์ค์ผ์ผ ๊ฒฐ๊ณผ", elem_classes="image-container") |
|
|
|
gfpgan_btn = gr.Button('โจ ์
์ค์ผ์ผ ๋ฐ ๋ณต์', elem_classes="custom-button primary") |
|
|
|
|
|
with gr.TabItem("โ๏ธ ๋ฐฐ๊ฒฝ ์ง์ฐ๊ธฐ", elem_classes="tab-content"): |
|
with gr.Row(): |
|
with gr.Column(elem_classes="panel"): |
|
gr.HTML('<div class="section-title"><i class="fas fa-cut"></i> ์ด๋ฏธ์ง ๋ฐฐ๊ฒฝ ์ ๊ฑฐ</div>') |
|
gr.HTML(""" |
|
<p style="margin-bottom: 1rem; font-size: 1.05rem;"> |
|
์ด๋ฏธ์ง์์ ๋ฐฐ๊ฒฝ์ ์๋์ผ๋ก ์ ๊ฑฐํ์ฌ ํฌ๋ช
ํ PNG ์ด๋ฏธ์ง๋ก ๋ณํํฉ๋๋ค. |
|
</p> |
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ๋ฐฐ๊ฒฝ๊ณผ ์ฃผ์ ํผ์ฌ์ฒด ๊ฐ์ ๋๋น๊ฐ ๋๋ ทํ ์๋ก ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. |
|
</div> |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-upload"></i> ์
๋ ฅ ์ด๋ฏธ์ง</div>') |
|
bg_remove_input = gr.Image(type="pil", label="์
๋ก๋", elem_classes="image-container") |
|
|
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-download"></i> ๊ฒฐ๊ณผ ์ด๋ฏธ์ง</div>') |
|
bg_remove_output = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ ๊ฑฐ ๊ฒฐ๊ณผ", elem_classes="image-container", format="png") |
|
|
|
with gr.Row(): |
|
bg_remove_status = gr.Textbox(label="์ํ", lines=2, elem_classes="custom-input") |
|
bg_remove_btn = gr.Button('โ๏ธ ๋ฐฐ๊ฒฝ ์ ๊ฑฐํ๊ธฐ', elem_classes="custom-button primary") |
|
|
|
|
|
with gr.TabItem("๐๏ธ ์ด๋ฏธ์ง ํํฐ", elem_classes="tab-content"): |
|
with gr.Row(): |
|
with gr.Column(elem_classes="panel"): |
|
gr.HTML('<div class="section-title"><i class="fas fa-sliders-h"></i> ์ด๋ฏธ์ง ํํฐ</div>') |
|
gr.HTML(""" |
|
<p style="margin-bottom: 1rem; font-size: 1.05rem;"> |
|
์ด๋ฏธ์ง ํํฐ๋ฅผ ์ ์ฉํ์ฌ ์์๊ณผ ํค์ ์กฐ์ ํฉ๋๋ค. |
|
</p> |
|
<div class="tip-box"> |
|
<i class="fas fa-lightbulb"></i> <strong>ํ:</strong> ์ฌ๋ผ์ด๋๋ฅผ ์กฐ์ ํ์ฌ ์ด๋ฏธ์ง์ ๋ฐ๊ธฐ, ๋๋น, ์ฑ๋ ๋ฑ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. |
|
</div> |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-upload"></i> ์
๋ ฅ ์ด๋ฏธ์ง</div>') |
|
filter_input_image = gr.Image(type="pil", label="์
๋ก๋", elem_classes="image-container") |
|
|
|
with gr.Column(): |
|
gr.HTML('<div class="section-title"><i class="fas fa-image"></i> ๊ฒฐ๊ณผ ์ด๋ฏธ์ง</div>') |
|
filter_output_image = gr.Image(type="pil", label="ํํฐ ์ ์ฉ ๊ฒฐ๊ณผ", elem_classes="image-container") |
|
|
|
gr.HTML('<div class="section-title"><i class="fas fa-sliders-h"></i> ํํฐ ์กฐ์ </div>') |
|
with gr.Group(): |
|
brightness_slider = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="๋ฐ๊ธฐ ์กฐ์ ") |
|
contrast_slider = gr.Slider(0.5, 1.5, value=1.0, step=0.1, label="๋๋น ์กฐ์ ") |
|
saturation_slider = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="์ฑ๋ ์กฐ์ ") |
|
temperature_slider = gr.Slider(-1.0, 1.0, value=0.0, step=0.1, label="์์จ๋ ์กฐ์ ") |
|
tint_slider = gr.Slider(-100, 100, value=0, step=1, label="์์กฐ ์กฐ์ ") |
|
exposure_slider = gr.Slider(-5.0, 5.0, value=0.0, step=0.1, label="๋
ธ์ถ ์กฐ์ ") |
|
vibrance_slider = gr.Slider(-100.0, 100.0, value=0.0, step=1.0, label="ํ๊ธฐ ์กฐ์ ") |
|
color_mixer_blues_slider = gr.Slider(-100.0, 100.0, value=0.0, step=1.0, label="์ปฌ๋ฌ ๋ฏน์ (๋ธ๋ฃจ)") |
|
shadows_slider = gr.Slider(-100.0, 100.0, value=0.0, step=1.0, label="๊ทธ๋ฆผ์ ์กฐ์ ") |
|
|
|
|
|
inputs = [ |
|
filter_input_image, |
|
brightness_slider, |
|
contrast_slider, |
|
saturation_slider, |
|
temperature_slider, |
|
tint_slider, |
|
exposure_slider, |
|
vibrance_slider, |
|
color_mixer_blues_slider, |
|
shadows_slider |
|
] |
|
|
|
input_components = [ |
|
brightness_slider, |
|
contrast_slider, |
|
saturation_slider, |
|
temperature_slider, |
|
tint_slider, |
|
exposure_slider, |
|
vibrance_slider, |
|
color_mixer_blues_slider, |
|
shadows_slider |
|
] |
|
|
|
for input_component in input_components: |
|
input_component.change( |
|
fn=process_image, |
|
inputs=inputs, |
|
outputs=filter_output_image |
|
) |
|
|
|
filter_input_image.change( |
|
fn=lambda x, *args: process_image(x, *args) if x is not None else None, |
|
inputs=inputs, |
|
outputs=filter_output_image |
|
) |
|
|
|
|
|
|
|
image_change_btn1.click( |
|
fn=lambda: "(#1์ ์ฌ์ฑ)์ด ์ด์ง ๋ค๋ก ๋์๋ณด๋ ๋ชจ์ต์ผ๋ก ์ต๋ํ ์ด์ seed๋ฅผ ์ ์งํํ
์์ฐ์ค๋ฝ๊ฒ ๋ณ๊ฒฝ.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
image_change_btn2.click( |
|
fn=lambda: "(#1 ๋ ๋ชจ๋ชจํ)์์ ์ฒญ์์์ด๋ ๊ณ ๋ง ๊ฒ์์ ๊ณ ๋๋ ๊ณ ๋ก ๋ณ๊ฒฝํ๊ณ ๋๋จธ์ง ๋ถ๋ถ์ seed๋ฅผ ๋ณ๊ฒฝ์ ํ์ง๋ง๋ผ.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
text_remove_btn.click( |
|
fn=lambda: "(#1 ์ด๋ฏธ์ง)์ ์๋ ์ค๊ตญ์ด๋ฅผ ๋ชจ๋ ์ ๊ฑฐํ๋ผ.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
text_change_btn.click( |
|
fn=lambda: '(#1์ ํ
์คํธ)๋ฅผ ์คํ์ผ์ ์ ์งํ์ฒด ํ
์คํธ๋ง "Hello"๋ก ๋ฐ๊ฟ๋ผ', |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
clothes_change_btn1.click( |
|
fn=lambda: "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด ์ ์ฒด ๋น์จ๊ณผ ํฌ์ฆ๋ ์ ์งํ ์ฒด (#2์ ์ ๊ธ๋ผ์ค)์ (#3์ ์ฒญ๋ฐ์ง)๋ฅผ ์ง์ ๋ชจ๋ธ์ด ์ฐฉ์ฉํ๊ฒ ์ฒ๋ผ ์์ฐ์ค๋ฝ๊ฒ ๋ชจ์ต.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
clothes_change_btn2.click( |
|
fn=lambda: "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2์ ์ ๊ธ๋ผ์ค)์ ์ฐฉ์ฉํ๊ณ (#3์ ๋ท๋ฐฐ๊ฒฝ์ ์นดํ์ ์ฒด๊ฐ ๋ณด์ด๋ฉฐ) ์์์ ์์ ์๋ ๋ชจ์ต", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
holding_product_btn.click( |
|
fn=lambda: "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด(#2์ ์์ธ์)์ ๋ค๊ณ ์๋ ์์ฐ์ค๋ฌ์ด ๋ชจ์ต", |
|
|
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
background_change_btn.click( |
|
fn=lambda: "(#1์ ์ฌ์ฑ๋ชจ๋ธ)์ด (#2 ์นดํ)์์ ์์ฐ์ค๋ฝ๊ฒ ์๋ ๋ชจ์ต", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
composite_product_btn.click( |
|
fn=lambda: "(#1์ ๋ ๊ณ ๋ชจํ)์์ ์ฒญ์์์ด๋ ๊ณ ๋ฅผ ์ ๊ฑฐํ ํ, ๊ทธ ์๋ฆฌ๋ฅผ ์ฃผ๋ณ ๋ฐฐ๊ฒฝ๊ณผ ์์ฐ์ค๋ฝ๊ฒ ์ด์ฐ๋ฌ์ง๋๋ก ์ฑ์์ฃผ์ธ์. ๋จ, ์ด๋ฏธ์ง์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ฃผ์ ์์๋ ๋์ผํ๊ฒ ์ ์งํด ํด์ผํ๋ค.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
outpainting_btn.click( |
|
fn=lambda: "(#1 ์ด๋ฏธ์ง)๋ฅผ ์๋ณธ๊ทธ๋๋ก ์ค์์ ๋๊ณ ๋น์จ๋ก ์ ์งํ์ฒด ์์๋ ๋ฐ ์ข์ฐ๋ก ํฌ๊ฒ ํ์ฅํ๋ผ.", |
|
inputs=[], |
|
outputs=prompt_input |
|
) |
|
|
|
|
|
submit_single_btn.click( |
|
fn=lambda image1, image2, image3, prompt: process_images_with_prompt(image1, image2, image3, prompt, 0), |
|
inputs=[image1_input, image2_input, image3_input, prompt_input], |
|
outputs=[output_image1, output_text, prompt_display], |
|
) |
|
|
|
|
|
submit_btn.click( |
|
fn=generate_multiple_images, |
|
inputs=[image1_input, image2_input, image3_input, prompt_input], |
|
outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display], |
|
) |
|
|
|
gfpgan_btn.click( |
|
fn=upscaler_korean, |
|
inputs=gfpgan_input, |
|
outputs=gfpgan_output |
|
) |
|
|
|
|
|
bg_remove_btn.click( |
|
fn=remove_background, |
|
inputs=bg_remove_input, |
|
outputs=[bg_remove_output, bg_remove_status] |
|
) |
|
|
|
demo.queue() |
|
demo.launch() |