93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
# usb_camera_app.py
|
||
# 菜品识别:仅 USB 相机(UI 复用 ui.classifier_ui)
|
||
|
||
import os
|
||
import sys
|
||
import threading
|
||
import time
|
||
|
||
import cv2
|
||
|
||
if hasattr(sys, 'frozen'):
|
||
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
||
|
||
from ui.classifier_ui import BaseDishApp, run_app
|
||
|
||
|
||
class ImageClassifierDemo(BaseDishApp):
|
||
window_title = "菜品识别系统"
|
||
app_title = "菜品识别系统"
|
||
edition_label = "USB 相机版"
|
||
camera_display_name = "USB相机"
|
||
|
||
def __init__(self, root):
|
||
self.cap = None
|
||
self._frame_lock = threading.Lock()
|
||
super().__init__(root)
|
||
|
||
def auto_connect_camera(self):
|
||
def connect_thread():
|
||
try:
|
||
self.cap = cv2.VideoCapture(0)
|
||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
|
||
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
|
||
if self.cap.isOpened():
|
||
self.camera_connected = True
|
||
self.root.after(0, self._update_camera_ui_success)
|
||
return
|
||
self.cap = None
|
||
except Exception as e:
|
||
self.cap = None
|
||
print(f"USB相机连接失败:{e}")
|
||
self.root.after(0, self._update_camera_ui_fail)
|
||
|
||
threading.Thread(target=connect_thread, daemon=True).start()
|
||
|
||
def grab_preview_frame(self):
|
||
if not self.camera_connected or self.cap is None:
|
||
return None
|
||
with self._frame_lock:
|
||
try:
|
||
# 丢掉缓冲旧帧,取最新
|
||
for _ in range(2):
|
||
self.cap.grab()
|
||
ret, frame = self.cap.read()
|
||
if ret and frame is not None and frame.size > 0:
|
||
return frame
|
||
except Exception as e:
|
||
print(f"USB取帧失败: {e}")
|
||
return None
|
||
|
||
def take_photo(self):
|
||
if not self.camera_connected or self.cap is None:
|
||
return -1, None
|
||
os.makedirs("images", exist_ok=True)
|
||
capture_time = time.strftime("%Y%m%d_%H%M%S")
|
||
save_path = os.path.abspath(f'images/capture_{capture_time}.jpg')
|
||
try:
|
||
frame = self.grab_preview_frame()
|
||
if frame is None:
|
||
return -1, None
|
||
if cv2.imwrite(save_path, frame):
|
||
return 0, save_path
|
||
except Exception as e:
|
||
print(f"USB拍照失败: {e}")
|
||
return -1, None
|
||
|
||
def close_camera(self):
|
||
if self.cap is not None:
|
||
self.cap.release()
|
||
self.cap = None
|
||
self.camera_connected = False
|
||
|
||
|
||
if __name__ == "__main__":
|
||
# 与界面一同启动本机客户端服务(媒体 HTTP :9100;排餐/设备状态在 BaseDishApp 内拉起)
|
||
try:
|
||
from service.media_server import ensure_media_server
|
||
ensure_media_server()
|
||
except Exception as exc:
|
||
print(f'[WARN] media server start failed: {exc}')
|
||
run_app(ImageClassifierDemo)
|