import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog, messagebox, HORIZONTAL
from PIL import Image, ImageTk

# 調整清晰度
def adjust_sharpness(image, alpha=1.9):
    blurred = cv2.GaussianBlur(image, (0, 0), 3)
    sharpened = cv2.addWeighted(image, alpha, blurred, 1 - alpha, 0)
    return sharpened

# 調整對比度
def adjust_contrast(image, beta=90):
    image = image.astype(np.float32)
    image = image * (1 + beta / 100.0)
    image = np.clip(image, 0, 255).astype(np.uint8)
    return image

# 調整亮度
def adjust_brightness(image, gamma=1.0):
    if gamma == 0:
        gamma = 0.01  # 防止除以零
    inv_gamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype("uint8")
    return cv2.LUT(image, table)

# 應用模糊
def apply_blur(image, ksize=5):
    if ksize % 2 == 0:
        ksize += 1  # 確保 ksize 是奇數
    return cv2.GaussianBlur(image, (ksize, ksize), 0)

# 黑白二值化處理
def convert_to_binary(image, threshold=128):
    img_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))  # 轉換為 PIL 格式
    grayscale_image = img_pil.convert('L')  # 轉換為灰度圖
    binary_image = grayscale_image.point(lambda p: 255 if p > threshold else 0, mode='1')  # 二值化
    return binary_image

# 更新並處理圖像
def process_image():
    global processed_image, display_image

    alpha = sharpness_scale.get()
    beta = contrast_scale.get()
    gamma = brightness_scale.get()
    ksize = blur_scale.get()

    # 應用圖像處理
    processed_image = adjust_sharpness(original_image, alpha=alpha)
    processed_image = adjust_contrast(processed_image, beta=beta)
    processed_image = adjust_brightness(processed_image, gamma=gamma)
    processed_image = apply_blur(processed_image, ksize=ksize)

    # 將處理後的圖像顯示
    display_image_func(processed_image)

# 顯示圖像
def display_image_func(img):
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    im_pil = Image.fromarray(img_rgb)
    imgtk = ImageTk.PhotoImage(image=im_pil)
    display_image.configure(image=imgtk)
    display_image.image = imgtk

# 加載圖像
def load_image():
    global original_image

    file_path = filedialog.askopenfilename()
    if file_path:
        image = cv2.imread(file_path)
        if image is None:
            messagebox.showerror("錯誤", "無法加載圖像")
            return
        original_image = image
        process_image()

# 保存圖像
def save_image():
    if processed_image is None:
        messagebox.showerror("錯誤", "沒有可保存的圖像")
        return
    file_path = filedialog.asksaveasfilename(defaultextension=".png")
    if file_path:
        cv2.imwrite(file_path, processed_image)
        messagebox.showinfo("保存成功", f"圖像已保存到 {file_path}")

# 將圖像轉換為黑白二值圖並保存
def save_binary_image():
    if processed_image is None:
        messagebox.showerror("錯誤", "沒有可轉換的圖像")
        return
    binary_image = convert_to_binary(processed_image, threshold=binary_threshold_scale.get())
    file_path = filedialog.asksaveasfilename(defaultextension=".png")
    if file_path:
        binary_image.save(file_path)
        messagebox.showinfo("保存成功", f"黑白圖像已保存到 {file_path}")

# 初始化Tkinter窗口
root = tk.Tk()
root.title("圖像調整工具")
root.geometry("450x700")

# 初始化全局變數
original_image = None
processed_image = None

# 加載圖像按鈕
load_button = tk.Button(root, text="加載圖像", command=load_image)
load_button.pack(pady=10)

# 清晰度調節
sharpness_label = tk.Label(root, text="清晰度 (alpha)")
sharpness_label.pack()
sharpness_scale = tk.Scale(root, from_=0.0, to=5.0, resolution=0.1, orient=HORIZONTAL, command=lambda x: process_image() if original_image is not None else None)
sharpness_scale.set(1.9)
sharpness_scale.pack()

# 對比度調節
contrast_label = tk.Label(root, text="對比度 (beta)")
contrast_label.pack()
contrast_scale = tk.Scale(root, from_=-100, to=100, resolution=1, orient=HORIZONTAL, command=lambda x: process_image() if original_image is not None else None)
contrast_scale.set(0)
contrast_scale.pack()

# 亮度調節
brightness_label = tk.Label(root, text="亮度 (gamma)")
brightness_label.pack()
brightness_scale = tk.Scale(root, from_=0.1, to=5.0, resolution=0.1, orient=HORIZONTAL, command=lambda x: process_image() if original_image is not None else None)
brightness_scale.set(1.0)
brightness_scale.pack()

# 模糊程度調節
blur_label = tk.Label(root, text="模糊程度 (ksize)")
blur_label.pack()
blur_scale = tk.Scale(root, from_=1, to=31, resolution=2, orient=HORIZONTAL, command=lambda x: process_image() if original_image is not None else None)
blur_scale.set(1)
blur_scale.pack()

# 黑白二值化的閾值調節
binary_threshold_label = tk.Label(root, text="黑白二值化閾值")
binary_threshold_label.pack()
binary_threshold_scale = tk.Scale(root, from_=0, to=255, resolution=1, orient=HORIZONTAL)
binary_threshold_scale.set(128)
binary_threshold_scale.pack()

# 保存圖像按鈕
save_button = tk.Button(root, text="保存處理後的圖像", command=save_image)
save_button.pack(pady=10)

# 保存黑白二值圖按鈕
save_binary_button = tk.Button(root, text="保存黑白二值圖", command=save_binary_image)
save_binary_button.pack(pady=10)

# 圖像顯示區域
display_image = tk.Label(root)
display_image.pack()

# 運行主循環
root.mainloop()


###不管調整清晰還是黑白化，我都要影像能夠即時在下方顯示，而不是儲存後才顯示。