import tkinter as tk
from tkinter import filedialog, scrolledtext
import os
import cv2
import numpy as np
import threading
import queue
import time
def center_window(root, width=800, height=500):
# Lấy kích thước màn hình
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Tính vị trí bắt đầu trục ngang và trục đứng
aaaxxx = (screen_width // 2) - (width // 2)
bbbyyy = (screen_height // 2) - (height // 2) - (40)
# Đặt geometry
root.geometry(f"{width}x{height}+{aaaxxx}+{bbbyyy}")
class DarkCornersRemover:
def __init__(self, root):
self.root = root
self.root.title("Remove Black Background In Images - DarkCorners")
self.root.resizable(False, False)
center_window(self.root, 800, 500)
self.input_dir = tk.StringVar()
self.output_dir = tk.StringVar()
self.processing = False
self.thread = None
self.log_queue = queue.Queue()
self.build_gui()
self.root.after(100, self.update_log)
def build_gui(self):
# Hàng 1: Tiêu đề
tk.Label(self.root, text="Remove Black Background In Images - DarkCorners", font=("Arial", 18, "bold")).pack(pady=10)
# Hàng 2: Chọn thư mục input/output
frame_paths = tk.Frame(self.root)
frame_paths.pack(pady=10, fill='x', padx=20)
# Input
frame_input = tk.Frame(frame_paths)
frame_input.pack(side='left', expand=True, fill='x', padx=(0, 10))
tk.Entry(frame_input, textvariable=self.input_dir, width=40).pack(side='left', expand=True, fill='x')
tk.Button(frame_input, text="Chọn Input", command=self.select_input_dir).pack(side='left', padx=5)
# Output
frame_output = tk.Frame(frame_paths)
frame_output.pack(side='left', expand=True, fill='x')
tk.Entry(frame_output, textvariable=self.output_dir, width=40).pack(side='left', expand=True, fill='x')
tk.Button(frame_output, text="Chọn Output", command=self.select_output_dir).pack(side='left', padx=5)
# Hàng 3: Các nút
frame_buttons = tk.Frame(self.root)
frame_buttons.pack(pady=10)
tk.Button(frame_buttons, text="Bắt Đầu", command=self.start_processing, width=15).pack(side='left', padx=10)
tk.Button(frame_buttons, text="Tạm Dừng", command=self.stop_processing, width=15).pack(side='left', padx=10)
tk.Button(frame_buttons, text="Thoát", command=self.root.quit, width=15).pack(side='left', padx=10)
# Hàng 4: Logs
tk.Label(self.root, text="Logs:", font=("Arial", 12, "bold")).pack(anchor='w', padx=20)
self.log_area = scrolledtext.ScrolledText(self.root, width=95, height=25, state='disabled', bg="#f4f4f4")
self.log_area.pack(padx=20, pady=10)
def log(self, message):
self.log_queue.put(message)
def update_log(self):
while not self.log_queue.empty():
message = self.log_queue.get()
self.log_area.config(state='normal')
self.log_area.insert(tk.END, message + "\n")
self.log_area.see(tk.END)
self.log_area.config(state='disabled')
self.root.after(100, self.update_log)
def select_input_dir(self):
path = filedialog.askdirectory()
if path:
self.input_dir.set(path)
def select_output_dir(self):
path = filedialog.askdirectory()
if path:
self.output_dir.set(path)
def start_processing(self):
if self.processing:
self.log("Đang xử lý rồi...")
return
if not self.input_dir.get() or not self.output_dir.get():
self.log("Vui lòng chọn thư mục Input và Output.")
return
self.processing = True
self.thread = threading.Thread(target=self.process_images)
self.thread.start()
def stop_processing(self):
if self.processing:
self.processing = False
self.log("Đã yêu cầu dừng xử lý...")
def process_images(self):
input_folder = self.input_dir.get()
output_folder = self.output_dir.get()
os.makedirs(output_folder, exist_ok=True)
files = [f for f in os.listdir(input_folder) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
if not files:
self.log("Không tìm thấy ảnh trong thư mục input.")
self.processing = False
return
for filename in files:
if not self.processing:
self.log("Quá trình đã dừng.")
break
input_path = os.path.join(input_folder, filename)
output_path = os.path.join(output_folder, filename)
self.log(f"Đang xử lý: {filename}")
success = self.crop_black_border(input_path, output_path)
if success:
self.log(f"✔ Đã lưu: {output_path}")
else:
self.log(f"✖ Lỗi khi xử lý: {filename}")
time.sleep(0.1) # Delay nhỏ để log hiển thị từ từ
self.processing = False
self.log("✅ Hoàn tất xử lý.")
def crop_black_border(self, image_path, output_path):
try:
image = cv2.imread(image_path)
if image is None:
return False
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return False
x, y, w, h = cv2.boundingRect(np.vstack(contours))
cropped = image[y:y+h, x:x+w]
cv2.imwrite(output_path, cropped)
return True
except Exception as e:
self.log(f"❗ Lỗi: {e}")
return False
# Khởi chạy ứng dụng
if __name__ == "__main__":
root = tk.Tk()
app = DarkCornersRemover(root)
root.mainloop()