edge-api / app.py
dahyedahye's picture
.
a7b1429
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import FileResponse
import cv2
from PIL import Image
import re
import gdown
import os
import uuid
URL = "https://leekwoon-edge-api.hf.space"
# URL = "http://localhost:7860"
app = FastAPI(
version="0.0.1",
servers=[
{
"url": URL,
"description": "image edge detection API",
}
],
)
def extract_file_id(drive_url: str) -> str:
"""
Google Drive URL์—์„œ ํŒŒ์ผ ID๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
Parameters:
drive_url (str): Google Drive ํŒŒ์ผ URL.
Returns:
str: ์ถ”์ถœ๋œ ํŒŒ์ผ ID.
"""
# ์ •๊ทœ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ URL์—์„œ ํŒŒ์ผ ID ์ถ”์ถœ
match = re.search(r'/d/([a-zA-Z0-9_-]+)', drive_url)
if match:
return match.group(1)
# ๋‹ค๋ฅธ URL ํ˜•์‹์—์„œ ํŒŒ์ผ ID ์ถ”์ถœ
match = re.search(r'file/d/([a-zA-Z0-9_-]+)', drive_url)
if match:
return match.group(1)
# ๊ณต์œ  ๋งํฌ์—์„œ ํŒŒ์ผ ID ์ถ”์ถœ
match = re.search(r'([a-zA-Z0-9_-]{33,})', drive_url)
if match:
return match.group(1)
raise ValueError("Invalid Google Drive URL")
@app.post("/detect-edges/")
def detect_edges(url: str, request: Request):
try:
# Google Drive ํŒŒ์ผ ID ์ถ”์ถœ
file_id = extract_file_id(url)
download_url = f"https://drive.google.com/uc?id={file_id}"
# ์ด๋ฏธ์ง€๋ฅผ Google Drive์—์„œ ๋‹ค์šด๋กœ๋“œ
temp_input_image = f'/tmp/{uuid.uuid4()}.png'
gdown.download(download_url, temp_input_image, quiet=False)
# ์ด๋ฏธ์ง€๋ฅผ ์ฝ์–ด๋“ค์ž„
image = cv2.imread(temp_input_image)
# ์ด๋ฏธ์ง€๊ฐ€ ์ œ๋Œ€๋กœ ์ฝํ˜”๋Š”์ง€ ํ™•์ธ
if image is None:
raise HTTPException(status_code=400, detail="Invalid image URL or file not found.")
# ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ๋กœ ๋ณ€ํ™˜
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Canny ์—์ง€ ๊ฒ€์ถœ ์ ์šฉ
edges = cv2.Canny(gray_image, threshold1=100, threshold2=200)
edges_image = Image.fromarray(edges)
# ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ ์ƒ์„ฑ
white_background = Image.new("RGB", edges_image.size, (255, 255, 255))
# Canny ์—์ง€๋ฅผ ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ ์œ„์— ํ•ฉ์„ฑ
edges_on_white = Image.composite(Image.new("RGB", edges_image.size, (0, 0, 0)), white_background, edges_image)
# Sobel ์—ฐ์‚ฐ์ž ์ ์šฉ
sobelx = cv2.Sobel(gray_image, cv2.CV_64F, 1, 0, ksize=5) # X ์ถ•์— ๋Œ€ํ•œ Sobel ์—ฐ์‚ฐ์ž
sobely = cv2.Sobel(gray_image, cv2.CV_64F, 0, 1, ksize=5) # Y ์ถ•์— ๋Œ€ํ•œ Sobel ์—ฐ์‚ฐ์ž
# ๋‘ ๊ธฐ์šธ๊ธฐ ๊ฒฐํ•ฉ
sobel_combined = cv2.magnitude(sobelx, sobely)
# ๊ฒฐ๊ณผ๋ฅผ [0, 255] ๋ฒ”์œ„๋กœ ์ •๊ทœํ™”
sobel_combined = cv2.normalize(sobel_combined, None, 0, 255, cv2.NORM_MINMAX)
sobel_combined = sobel_combined.astype('uint8')
# ๊ฒฐ๊ณผ๋ฅผ PIL ์ด๋ฏธ์ง€๋กœ ๋ณ€ํ™˜
sobel_image = Image.fromarray(sobel_combined)
# Sobel ์—์ง€๋ฅผ ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ ์œ„์— ํ•ฉ์„ฑ
edges_on_white_sobel = Image.composite(Image.new("RGB", sobel_image.size, (0, 0, 0)), white_background, sobel_image)
# ์ตœ์ข… Sobel ์ด๋ฏธ์ง€๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ (PNG ํ˜•์‹)
output_file_path = f'/tmp/{uuid.uuid4()}.png'
edges_on_white_sobel.save(output_file_path, format='PNG')
# ์ž…๋ ฅ ์ด๋ฏธ์ง€ ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ
os.remove(temp_input_image)
# ์„œ๋ฒ„์˜ URL์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ค์šด๋กœ๋“œ URL ์ƒ์„ฑ
download_url = os.path.join(URL, "tmp", os.path.basename(output_file_path))
# ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜
return {"download_url": download_url}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/tmp/{filename}")
def download_file(filename: str):
file_path = f"/tmp/{filename}"
if os.path.exists(file_path):
return FileResponse(file_path, media_type='image/png', filename=filename)
else:
raise HTTPException(status_code=404, detail="File not found")