|
import cv2 |
|
import numpy as np |
|
from PIL import Image, ImageEnhance, ImageFilter |
|
import gradio as gr |
|
from io import BytesIO |
|
import tempfile |
|
import logging |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
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 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(): |
|
|
|
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="๊ทธ๋ฆผ์ ์กฐ์ ") |
|
|
|
|
|
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() |
|
|