gif-1 / app.py
ssboost's picture
Create app.py
1ed87be verified
raw
history blame
9.52 kB
import cv2
import numpy as np
from PIL import Image, ImageEnhance, ImageFilter
import gradio as gr
from io import BytesIO
import tempfile
import logging
# ๋กœ๊น… ์„ค์ • - INFO ๋ ˆ๋ฒจ๋กœ ๋ณ€๊ฒฝ
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def adjust_brightness(image, value):
"""์ด๋ฏธ์ง€ ๋ฐ๊ธฐ ์กฐ์ ˆ"""
value = float(value - 1) * 100 # 0-2 ๋ฒ”์œ„๋ฅผ -100์—์„œ +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 # 0-2 ๋ฒ”์œ„๋ฅผ -100์—์„œ +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) # Hue ๊ฐ’์€ 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
# PIL ์ด๋ฏธ์ง€๋ฅผ OpenCV ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
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)
# PIL ์ด๋ฏธ์ง€๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜
return Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
def download_image(image, input_image_name):
"""์ด๋ฏธ์ง€๋ฅผ JPG ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ฒฝ๋กœ ๋ฐ˜ํ™˜"""
if image is None:
return None
# ํ•œ๊ตญ ์‹œ๊ฐ„ ํƒ€์ž„์Šคํƒฌํ”„ ์ƒ์„ฑ ํ•จ์ˆ˜
from datetime import datetime, timedelta
def get_korean_timestamp():
korea_time = datetime.utcnow() + timedelta(hours=9)
return korea_time.strftime('%Y%m%d_%H%M%S')
timestamp = get_korean_timestamp()
if input_image_name and hasattr(input_image_name, 'name'):
base_name = input_image_name.name.split('.')[0] # ํŒŒ์ผ ๊ฐ์ฒด์—์„œ ์ด๋ฆ„ ์ถ”์ถœ
else:
base_name = "์ด๋ฏธ์ง€"
file_name = f"[๋์žฅAI]๋์žฅํ•„ํ„ฐ_{base_name}_{timestamp}.jpg"
# ํŒŒ์ผ ์ €์žฅ
temp_file_path = tempfile.gettempdir() + "/" + file_name
image.save(temp_file_path, format="JPEG")
return temp_file_path
def create_interface():
css = """
footer {
visibility: hidden;
}
.download-button, .download-output {
width: 100%;
}
.download-container {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
#gradio-app {
margin: 0 !important; /* ๋ชจ๋“  ๋ฐฉํ–ฅ ์—ฌ๋ฐฑ ์ œ๊ฑฐ */
text-align: left !important; /* ์™ผ์ชฝ ์ •๋ ฌ ๊ฐ•์ œ */
padding: 20px !important; /* ํŒจ๋”ฉ ์ถ”๊ฐ€ */
}
.gradio-container {
max-width: 100% !important; /* ๊ฐ€๋กœ ํญ ์ „์ฒด ์‚ฌ์šฉ */
margin-left: 0 !important; /* ์™ผ์ชฝ ์ •๋ ฌ */
padding: 20px !important; /* ํŒจ๋”ฉ ์ถ”๊ฐ€ */
}
.download-button {
background-color: black !important;
color: white !important;
border: none !important;
padding: 10px !important;
font-size: 16px !important;
}
"""
with gr.Blocks(theme=gr.themes.Soft(
primary_hue=gr.themes.Color(
c50="#FFF7ED", # ๊ฐ€์žฅ ๋ฐ์€ ์ฃผํ™ฉ
c100="#FFEDD5",
c200="#FED7AA",
c300="#FDBA74",
c400="#FB923C",
c500="#F97316", # ๊ธฐ๋ณธ ์ฃผํ™ฉ
c600="#EA580C",
c700="#C2410C",
c800="#9A3412",
c900="#7C2D12", # ๊ฐ€์žฅ ์–ด๋‘์šด ์ฃผํ™ฉ
c950="#431407",
),
secondary_hue="zinc", # ๋ชจ๋˜ํ•œ ๋А๋‚Œ์˜ ํšŒ์ƒ‰ ๊ณ„์—ด
neutral_hue="zinc",
font=("Pretendard", "sans-serif")
), css=css) as interface:
with gr.Row():
# ์™ผ์ชฝ ์—ด: ๋น„์œจ 3
with gr.Column(scale=3):
# ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
input_image = gr.Image(type="pil", label="์ด๋ฏธ์ง€ ์—…๋กœ๋“œ")
# ์กฐ์ • ์Šฌ๋ผ์ด๋”
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="๊ทธ๋ฆผ์ž ์กฐ์ ˆ")
# ์˜ค๋ฅธ์ชฝ ์—ด: ๋น„์œจ 7
with gr.Column(scale=7):
# ์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€ ์ถœ๋ ฅ
output_image = gr.Image(type="pil", label="์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€")
# ๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ
with gr.Row(elem_classes="download-container"):
download_button = gr.Button("JPG๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ", elem_classes="download-button")
with gr.Row(elem_classes="download-container"):
download_output = gr.File(label="JPG ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ", elem_classes="download-output")
# ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์—ฐ๊ฒฐ
inputs = [
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=output_image
)
# ๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ ๊ธฐ๋Šฅ
download_button.click(
fn=download_image,
inputs=[output_image, input_image],
outputs=download_output
)
return interface
# ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ๋ฐ ์‹คํ–‰
if __name__ == "__main__":
logger.info("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘")
interface = create_interface()
interface.queue()
interface.launch()