import gradio as gr from PIL import Image from skimage import color, feature from skimage.segmentation import slic, mark_boundaries from skimage.filters import threshold_otsu import numpy as np import cv2 import os # 驗證輸入的圖片是否為有效的 NumPy 陣列格式 def validate_image(image): if not isinstance(image, np.ndarray): raise ValueError("Input is not a valid NumPy array.") if image.ndim == 3 and image.shape[2] == 4: # RGBA to RGB image = image[:, :, :3] if image.ndim == 2: # Grayscale to RGB image = np.stack([image] * 3, axis=-1) elif image.ndim == 3 and image.shape[2] != 3: raise ValueError("Image must have 3 channels (RGB).") return image.astype(np.uint8) # 邊緣檢測函數 def edge_detection(image, low_threshold, high_threshold): gray = color.rgb2gray(image) edges = feature.canny(gray, sigma=low_threshold) return (edges * 255).astype(np.uint8) # 影像分割函數 def image_segmentation(image, num_segments): segments = slic(image, n_segments=num_segments, start_label=1) segmented_image = mark_boundaries(image, segments) return (segmented_image * 255).astype(np.uint8) # 修復影像函數(圖像修補) def image_inpainting(image, mask=None): if mask is None: gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) _, mask = cv2.threshold(gray, threshold_otsu(gray), 255, cv2.THRESH_BINARY_INV) mask = cv2.dilate(mask, None, iterations=3) if mask.ndim == 3: mask = cv2.cvtColor(mask, cv2.COLOR_RGB2GRAY) inpainted = cv2.inpaint(image, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA) return inpainted # 主處理函數,用來根據選擇的任務進行處理 def process_image(task, image, mask, param1, param2): try: # 驗證輸入的圖像 image = validate_image(image) if task == "Edge Detection": result = edge_detection(image, param1, param2) elif task == "Image Segmentation": result = image_segmentation(image, int(param1)) elif task == "Image Inpainting": result = image_inpainting(image, mask) else: raise ValueError(f"Unknown task: {task}") result = np.clip(result, 0, 255).astype(np.uint8) # 確保返回 PIL Image 格式 return Image.fromarray(result) # 返回 PIL Image 格式的圖像 except Exception as e: print(f"錯誤: {e}") return np.zeros((100, 100, 3), dtype=np.uint8) # 生成範例資料,強化對圖像的檢查和處理 def generate_grouped_examples(task_names, examples_dir): examples = [] images = sorted([f for f in os.listdir(examples_dir) if f.endswith((".png", ".jpg", ".jpeg"))]) # 生成一個全黑的 mask 當作 placeholder black_mask = Image.fromarray(np.zeros((100, 100, 3), dtype=np.uint8)) # for file_name in images: # file_path = os.path.join(examples_dir, file_name) # try: # image = Image.open(file_path).convert("RGB") # image_array = np.array(image) # # 確保範例圖像轉為 PIL.Image 格式 # image_pil = Image.fromarray(image_array) # # for task in task_names: # # # 確保範例圖像正確 # # examples.append([task, image_pil, None, 2, 5]) # 傳入 PIL 圖像 # for task in task_names: # if task == "Image Inpainting": # # 給一個 dummy mask # examples.append([task, image_pil, black_mask, 2, 5]) # else: # # 對非 Inpainting 任務,可直接給 mask=None 或改給 black_mask,看哪種運行正常 # # 但通常給 None 就會引發現在的問題,所以建議也用黑 mask # examples.append([task, image_pil, black_mask, 2, 5]) # except Exception as e: # print(f"Error loading example {file_name}: {e}") # return examples for i, file_name in enumerate(images): file_path = os.path.join(examples_dir, file_name) try: image = Image.open(file_path).convert("RGB") image_array = np.array(image) image_pil = Image.fromarray(image_array) # 根據 i 決定前三張或其他張如何設定 mask for task in task_names: if i < 2: # 前三張圖片:第三個參數 (mask) = None examples.append([task, image_pil, None, 2, 5]) else: # 之後的圖片:如果是 Inpainting,就給 black_mask;否則也可給黑 mask if task == "Image Inpainting": examples.append([task, image_pil, black_mask, 2, 5]) else: examples.append([task, image_pil, black_mask, 2, 5]) except Exception as e: print(f"Error loading example {file_name}: {e}") return examples tasks = ["Edge Detection", "Image Segmentation", "Image Inpainting"] examples_dir = "examples" # 假設範例圖像在此目錄下 examples = generate_grouped_examples(tasks, examples_dir) # Gradio 介面設定 interface = gr.Interface( fn=process_image, inputs=[ gr.Dropdown(choices=tasks, label="Task"), gr.Image(type="numpy", label="Input Image"), gr.Image(type="numpy", label="Mask (Optional), Note: This is for Image Inpainting function"), gr.Slider(1, 10, value=1, label="Parameter 1 (e.g., Edge Sigma, Num Segments)"), gr.Slider(0, 10, value=1, label="Parameter 2 (e.g., High Threshold)") ], outputs=gr.Image(type="pil"), # 返回 PIL 格式的圖像 examples=examples, title="Computer Vision Web App", description="Perform Edge Detection, Image Segmentation, or Inpainting on uploaded images." ) if __name__ == "__main__": interface.launch()