Files
PartsInquiry/backend/txm/app/ui/tk_app.py
2025-09-27 22:57:59 +08:00

163 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import tkinter as tk
from tkinter import filedialog, messagebox
from typing import Optional
import cv2
from PIL import Image, ImageTk
from ..config_loader import load_config
from ..io_utils import read_image_bgr
from ..pipeline import EAN13Recognizer
class TkEAN13App:
def __init__(self) -> None:
self.config = load_config()
self.root = tk.Tk()
self.root.title(self.config["app"]["ui"]["window_title"])
self.image_panel = tk.Label(self.root)
self.image_panel.pack(side=tk.TOP, padx=10, pady=10)
btn_frame = tk.Frame(self.root)
btn_frame.pack(side=tk.TOP, pady=5)
self.btn_open = tk.Button(btn_frame, text="选择图片", command=self.on_open)
self.btn_open.pack(side=tk.LEFT, padx=5)
self.btn_recognize = tk.Button(btn_frame, text="识别条码", command=self.on_recognize)
self.btn_recognize.pack(side=tk.LEFT, padx=5)
self.btn_camera = tk.Button(btn_frame, text="摄像头识别", command=self.on_camera)
self.btn_camera.pack(side=tk.LEFT, padx=5)
self.result_var = tk.StringVar(value="结果:-")
self.result_label = tk.Label(self.root, textvariable=self.result_var)
self.result_label.pack(side=tk.TOP, pady=5)
self.current_image_path: Optional[str] = None
self.recognizer = EAN13Recognizer()
self.cap = None
self.cam_running = False
def on_open(self) -> None:
path = filedialog.askopenfilename(
title="选择条码图片",
filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.bmp;*.tif;*.tiff")],
)
if not path:
return
self.current_image_path = path
img_bgr = read_image_bgr(path)
if img_bgr is None:
messagebox.showerror("错误", "无法读取图片")
return
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# 限制显示尺寸
max_w = 800
h, w = img_rgb.shape[:2]
if w > max_w:
scale = max_w / float(w)
img_rgb = cv2.resize(img_rgb, (max_w, int(h * scale)), interpolation=cv2.INTER_AREA)
im = Image.fromarray(img_rgb)
self.tk_img = ImageTk.PhotoImage(im)
self.image_panel.configure(image=self.tk_img)
self.result_var.set("结果:-")
def on_recognize(self) -> None:
if not self.current_image_path:
messagebox.showinfo("提示", "请先选择图片")
return
result = self.recognizer.recognize_any_from_path(self.current_image_path)
ean13 = result.get("ean13", "")
if ean13:
self.result_var.set(f"结果EAN-13 {ean13}")
return
others = result.get("others", [])
if others:
first = others[0]
self.result_var.set(f"结果:{first.get('type')} {first.get('code')}")
return
self.result_var.set("结果:未识别")
def on_camera(self) -> None:
if self.cam_running:
# 若已在运行,视为停止
self.stop_camera()
return
cam_cfg = self.config.get("camera", {})
index = int(cam_cfg.get("index", 0))
self.cap = cv2.VideoCapture(index, cv2.CAP_DSHOW)
if not self.cap.isOpened():
messagebox.showerror("错误", f"无法打开摄像头 index={index}")
self.cap.release()
self.cap = None
return
# 设置分辨率(尽力设置)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, float(cam_cfg.get("width", 1280)))
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, float(cam_cfg.get("height", 720)))
self.cam_running = True
self.result_var.set("结果:摄像头开启,正在识别...")
self.btn_camera.configure(text="停止摄像头")
self._camera_loop()
def stop_camera(self) -> None:
self.cam_running = False
try:
if self.cap is not None:
self.cap.release()
finally:
self.cap = None
self.btn_camera.configure(text="摄像头识别")
def _camera_loop(self) -> None:
if not self.cam_running or self.cap is None:
return
ret, frame = self.cap.read()
if not ret:
# 读取失败,稍后重试
self.root.after(int(self.config.get("camera", {}).get("interval_ms", 80)), self._camera_loop)
return
# 显示到面板
show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
max_w = 800
h, w = show.shape[:2]
if w > max_w:
scale = max_w / float(w)
show = cv2.resize(show, (max_w, int(h * scale)), interpolation=cv2.INTER_AREA)
im = Image.fromarray(show)
self.tk_img = ImageTk.PhotoImage(im)
self.image_panel.configure(image=self.tk_img)
# 识别
result = self.recognizer.recognize_any_from_image(frame)
ean13 = result.get("ean13", "")
if ean13:
self.result_var.set(f"结果EAN-13 {ean13}")
self.stop_camera()
return
others = result.get("others", [])
if others:
first = others[0]
self.result_var.set(f"结果:{first.get('type')} {first.get('code')}")
self.stop_camera()
return
# 未识别,继续下一帧
self.root.after(int(self.config.get("camera", {}).get("interval_ms", 80)), self._camera_loop)
def run(self) -> None:
self.root.mainloop()
def main() -> None:
app = TkEAN13App()
app.run()
if __name__ == "__main__":
main()