feat: 添加科技感UI界面和中文标题支持
- 新增TechUI类,提供现代化科技感用户界面 - 支持中文标题显示:"烟台蓬莱国际机场低能见度识别软件" - 集成多面板布局:视频显示、状态监控、LED矩阵、统计信息 - 添加PIL库支持中文字体渲染,解决乱码问题 - 更新main.py集成新UI界面,替换原简单显示 - 添加UI测试脚本test_ui.py用于界面效果预览 - 更新依赖项:添加Pillow和PyYAML支持 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2ff9c2b0bb
commit
a8e0bdcfe2
39
main.py
39
main.py
@ -23,6 +23,7 @@ from src.preprocessing.image_enhancer import ImageEnhancer
|
||||
from src.roi_detection.led_detector import LEDDetector
|
||||
from src.output.result_formatter import ResultFormatter
|
||||
from src.output.logger import LEDLogger
|
||||
from src.ui.tech_ui import TechUI
|
||||
|
||||
|
||||
class YantaiVisionXSystem:
|
||||
@ -46,7 +47,8 @@ class YantaiVisionXSystem:
|
||||
self.led_detector = None
|
||||
self.formatter = ResultFormatter()
|
||||
self.logger = LEDLogger()
|
||||
|
||||
self.tech_ui = TechUI()
|
||||
|
||||
# 状态变量
|
||||
self.is_running = False
|
||||
self.display_enabled = False
|
||||
@ -255,38 +257,27 @@ class YantaiVisionXSystem:
|
||||
def _display_results(self, original_frame, detection_result) -> None:
|
||||
"""
|
||||
显示检测结果
|
||||
|
||||
|
||||
Args:
|
||||
original_frame: 原始帧
|
||||
detection_result: 检测结果
|
||||
"""
|
||||
# 可视化检测结果
|
||||
# 可视化检测结果(在原始帧上绘制ROI等信息)
|
||||
vis_frame = self.led_detector.visualize_detection_result(
|
||||
original_frame, detection_result
|
||||
)
|
||||
|
||||
# 添加状态信息
|
||||
info_text = f"Frame: {detection_result.frame_count} | "
|
||||
info_text += f"Time: {detection_result.processing_time*1000:.1f}ms | "
|
||||
|
||||
summary = detection_result.detection_summary
|
||||
if 'threshold_detection' in summary:
|
||||
states = summary['threshold_detection']['states']
|
||||
info_text += f"ON: {states.get('on', 0)} | OFF: {states.get('off', 0)}"
|
||||
|
||||
cv2.putText(vis_frame, info_text, (10, 30),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
|
||||
|
||||
# 显示状态矩阵
|
||||
matrix_text = self.formatter.format_matrix_visual(
|
||||
self.formatter.format_to_matrix(detection_result)
|
||||
)
|
||||
|
||||
# 显示图像和状态
|
||||
cv2.imshow('YantaiVisionX - LED Detection', vis_frame)
|
||||
|
||||
|
||||
# 使用科技感UI创建完整显示帧
|
||||
display_frame = self.tech_ui.create_display_frame(vis_frame, detection_result)
|
||||
|
||||
# 显示图像
|
||||
cv2.imshow('YantaiVisionX LED Detection System', display_frame)
|
||||
|
||||
# 在控制台显示矩阵状态(每10帧显示一次)
|
||||
if detection_result.frame_count % 10 == 0:
|
||||
matrix_text = self.formatter.format_matrix_visual(
|
||||
self.formatter.format_to_matrix(detection_result)
|
||||
)
|
||||
print(f"\n{matrix_text}")
|
||||
|
||||
def _cleanup(self) -> None:
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
opencv-python>=4.8.0
|
||||
numpy>=1.24.0
|
||||
scikit-image>=0.20.0
|
||||
matplotlib>=3.7.0
|
||||
matplotlib>=3.7.0
|
||||
Pillow>=9.5.0
|
||||
PyYAML>=6.0
|
||||
8
src/ui/__init__.py
Normal file
8
src/ui/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
"""
|
||||
UI模块
|
||||
为YantaiVisionX系统提供用户界面组件
|
||||
"""
|
||||
|
||||
from .tech_ui import TechUI
|
||||
|
||||
__all__ = ['TechUI']
|
||||
480
src/ui/tech_ui.py
Normal file
480
src/ui/tech_ui.py
Normal file
@ -0,0 +1,480 @@
|
||||
"""
|
||||
科技感UI界面模块
|
||||
为YantaiVisionX系统提供现代化的用户界面
|
||||
"""
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Tuple, Optional, Any
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import os
|
||||
|
||||
|
||||
class TechUI:
|
||||
"""
|
||||
科技感用户界面类
|
||||
"""
|
||||
|
||||
def __init__(self, window_width: int = 1280, window_height: int = 720):
|
||||
"""
|
||||
初始化UI界面
|
||||
|
||||
Args:
|
||||
window_width: 窗口宽度
|
||||
window_height: 窗口高度
|
||||
"""
|
||||
self.window_width = window_width
|
||||
self.window_height = window_height
|
||||
|
||||
# 颜色定义
|
||||
self.colors = {
|
||||
'bg_dark': (30, 30, 30), # 深色背景
|
||||
'bg_panel': (45, 45, 45), # 面板背景
|
||||
'accent_blue': (255, 165, 0), # 蓝色强调色
|
||||
'accent_cyan': (255, 255, 0), # 青色强调色
|
||||
'text_primary': (255, 255, 255), # 主要文字
|
||||
'text_secondary': (200, 200, 200), # 次要文字
|
||||
'led_on': (0, 255, 0), # LED开启
|
||||
'led_off': (100, 100, 100), # LED关闭
|
||||
'border': (100, 150, 200), # 边框
|
||||
'warning': (0, 165, 255), # 警告色
|
||||
'success': (0, 255, 0), # 成功色
|
||||
}
|
||||
|
||||
# 面板区域定义
|
||||
self.panels = {
|
||||
'header': (0, 0, window_width, 80), # 标题区域
|
||||
'video': (20, 100, 800, 480), # 视频显示区域
|
||||
'status': (840, 100, 420, 200), # 状态面板
|
||||
'led_matrix': (840, 320, 420, 200), # LED矩阵显示
|
||||
'stats': (840, 540, 420, 160), # 统计信息
|
||||
}
|
||||
|
||||
# 字体配置
|
||||
self.fonts = {
|
||||
'title': cv2.FONT_HERSHEY_SIMPLEX,
|
||||
'subtitle': cv2.FONT_HERSHEY_SIMPLEX,
|
||||
'normal': cv2.FONT_HERSHEY_SIMPLEX,
|
||||
'small': cv2.FONT_HERSHEY_SIMPLEX,
|
||||
'mono': cv2.FONT_HERSHEY_DUPLEX,
|
||||
}
|
||||
|
||||
self.font_scales = {
|
||||
'title': 1.0,
|
||||
'subtitle': 0.7,
|
||||
'normal': 0.6,
|
||||
'small': 0.5,
|
||||
'mono': 0.5,
|
||||
}
|
||||
|
||||
# 尝试加载中文字体
|
||||
self.chinese_font = self._load_chinese_font()
|
||||
|
||||
def _load_chinese_font(self):
|
||||
"""加载中文字体"""
|
||||
# 常见的中文字体路径
|
||||
font_paths = [
|
||||
"C:/Windows/Fonts/msyh.ttc", # 微软雅黑
|
||||
"C:/Windows/Fonts/simhei.ttf", # 黑体
|
||||
"C:/Windows/Fonts/simsun.ttc", # 宋体
|
||||
"/System/Library/Fonts/PingFang.ttc", # macOS
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", # Linux
|
||||
]
|
||||
|
||||
for font_path in font_paths:
|
||||
if os.path.exists(font_path):
|
||||
try:
|
||||
return ImageFont.truetype(font_path, 24)
|
||||
except:
|
||||
continue
|
||||
|
||||
# 如果没有找到字体,使用默认字体
|
||||
try:
|
||||
return ImageFont.load_default()
|
||||
except:
|
||||
return None
|
||||
|
||||
def _put_chinese_text(self, canvas, text, position, font_size=24, color=(255, 255, 255)):
|
||||
"""在画布上绘制中文文字"""
|
||||
if self.chinese_font is None:
|
||||
# 如果没有中文字体,使用OpenCV默认字体
|
||||
cv2.putText(canvas, text, position, cv2.FONT_HERSHEY_SIMPLEX,
|
||||
font_size/30, color, 2)
|
||||
return
|
||||
|
||||
# 转换为PIL图像
|
||||
pil_img = Image.fromarray(cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB))
|
||||
draw = ImageDraw.Draw(pil_img)
|
||||
|
||||
# 设置字体大小
|
||||
try:
|
||||
font = ImageFont.truetype(self.chinese_font.path, font_size) if hasattr(self.chinese_font, 'path') else self.chinese_font
|
||||
except:
|
||||
font = self.chinese_font
|
||||
|
||||
# 绘制文字
|
||||
draw.text(position, text, font=font, fill=color[::-1]) # RGB转BGR
|
||||
|
||||
# 转换回OpenCV格式
|
||||
cv2_img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
|
||||
canvas[:] = cv2_img
|
||||
|
||||
def create_main_canvas(self) -> np.ndarray:
|
||||
"""
|
||||
创建主画布
|
||||
|
||||
Returns:
|
||||
np.ndarray: 主画布图像
|
||||
"""
|
||||
canvas = np.full((self.window_height, self.window_width, 3),
|
||||
self.colors['bg_dark'], dtype=np.uint8)
|
||||
|
||||
# 绘制渐变背景效果
|
||||
self._draw_gradient_background(canvas)
|
||||
|
||||
return canvas
|
||||
|
||||
def _draw_gradient_background(self, canvas: np.ndarray):
|
||||
"""绘制渐变背景"""
|
||||
h, w = canvas.shape[:2]
|
||||
|
||||
# 创建微妙的渐变效果
|
||||
for i in range(h):
|
||||
intensity = int(30 + (i / h) * 10) # 从30到40的渐变
|
||||
canvas[i:i+1, :] = (intensity, intensity, intensity)
|
||||
|
||||
# 添加网格线效果
|
||||
for i in range(0, w, 40):
|
||||
cv2.line(canvas, (i, 0), (i, h), (40, 40, 40), 1)
|
||||
for i in range(0, h, 40):
|
||||
cv2.line(canvas, (0, i), (w, i), (40, 40, 40), 1)
|
||||
|
||||
def draw_header(self, canvas: np.ndarray, system_time: str = None):
|
||||
"""
|
||||
绘制标题头部
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
system_time: 系统时间
|
||||
"""
|
||||
x, y, w, h = self.panels['header']
|
||||
|
||||
# 绘制标题背景
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + h), self.colors['bg_panel'], -1)
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + h), self.colors['border'], 2)
|
||||
|
||||
# 主标题
|
||||
title = "烟台蓬莱国际机场低能见度识别软件"
|
||||
|
||||
# 使用中文字体绘制标题
|
||||
title_x = x + 50 # 简化定位
|
||||
title_y = y + 20
|
||||
|
||||
# 标题阴影效果
|
||||
self._put_chinese_text(canvas, title, (title_x + 2, title_y + 2), 28, (0, 0, 0))
|
||||
self._put_chinese_text(canvas, title, (title_x, title_y), 28, self.colors['accent_cyan'])
|
||||
|
||||
# 副标题
|
||||
subtitle = "YantaiVisionX LED Array Monitoring System"
|
||||
subtitle_size = cv2.getTextSize(subtitle, self.fonts['subtitle'],
|
||||
self.font_scales['subtitle'], 1)[0]
|
||||
subtitle_x = x + (w - subtitle_size[0]) // 2
|
||||
subtitle_y = y + 60
|
||||
cv2.putText(canvas, subtitle, (subtitle_x, subtitle_y),
|
||||
self.fonts['subtitle'], self.font_scales['subtitle'],
|
||||
self.colors['text_secondary'], 1)
|
||||
|
||||
# 时间显示
|
||||
if system_time is None:
|
||||
system_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
time_x = x + w - 200
|
||||
time_y = y + 25
|
||||
cv2.putText(canvas, system_time, (time_x, time_y),
|
||||
self.fonts['small'], self.font_scales['small'],
|
||||
self.colors['text_secondary'], 1)
|
||||
|
||||
# 绘制装饰线
|
||||
cv2.line(canvas, (x + 20, y + h - 5), (x + w - 20, y + h - 5),
|
||||
self.colors['accent_blue'], 2)
|
||||
|
||||
def draw_video_panel(self, canvas: np.ndarray, video_frame: np.ndarray):
|
||||
"""
|
||||
绘制视频显示面板
|
||||
|
||||
Args:
|
||||
canvas: 主画布
|
||||
video_frame: 视频帧
|
||||
"""
|
||||
x, y, w, h = self.panels['video']
|
||||
|
||||
# 绘制面板背景和边框
|
||||
cv2.rectangle(canvas, (x - 2, y - 2), (x + w + 2, y + h + 2),
|
||||
self.colors['border'], 2)
|
||||
|
||||
# 调整视频帧大小并显示
|
||||
if video_frame is not None:
|
||||
resized_frame = cv2.resize(video_frame, (w, h))
|
||||
canvas[y:y+h, x:x+w] = resized_frame
|
||||
else:
|
||||
# 无视频时显示占位符
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + h),
|
||||
self.colors['bg_panel'], -1)
|
||||
placeholder_text = "NO VIDEO SIGNAL"
|
||||
text_size = cv2.getTextSize(placeholder_text, self.fonts['normal'],
|
||||
self.font_scales['normal'], 2)[0]
|
||||
text_x = x + (w - text_size[0]) // 2
|
||||
text_y = y + (h + text_size[1]) // 2
|
||||
cv2.putText(canvas, placeholder_text, (text_x, text_y),
|
||||
self.fonts['normal'], self.font_scales['normal'],
|
||||
self.colors['text_secondary'], 2)
|
||||
|
||||
# 绘制视频标签
|
||||
cv2.rectangle(canvas, (x, y - 25), (x + 120, y - 2),
|
||||
self.colors['bg_panel'], -1)
|
||||
cv2.putText(canvas, "LIVE VIDEO", (x + 10, y - 8),
|
||||
self.fonts['small'], self.font_scales['small'],
|
||||
self.colors['accent_cyan'], 1)
|
||||
|
||||
def draw_status_panel(self, canvas: np.ndarray, detection_result):
|
||||
"""
|
||||
绘制系统状态面板
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
detection_result: 检测结果
|
||||
"""
|
||||
x, y, w, h = self.panels['status']
|
||||
|
||||
# 绘制面板
|
||||
self._draw_panel(canvas, "SYSTEM STATUS", x, y, w, h)
|
||||
|
||||
# 状态信息
|
||||
status_y = y + 40
|
||||
line_height = 25
|
||||
|
||||
# 帧计数
|
||||
frame_text = f"Frame: {detection_result.frame_count}"
|
||||
cv2.putText(canvas, frame_text, (x + 15, status_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['text_primary'], 1)
|
||||
|
||||
# 处理时间
|
||||
status_y += line_height
|
||||
processing_time = detection_result.processing_time * 1000
|
||||
time_text = f"Processing: {processing_time:.1f}ms"
|
||||
cv2.putText(canvas, time_text, (x + 15, status_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['text_primary'], 1)
|
||||
|
||||
# FPS计算
|
||||
status_y += line_height
|
||||
fps = 1.0 / detection_result.processing_time if detection_result.processing_time > 0 else 0
|
||||
fps_text = f"FPS: {fps:.1f}"
|
||||
cv2.putText(canvas, fps_text, (x + 15, status_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['text_primary'], 1)
|
||||
|
||||
# 检测模式
|
||||
status_y += line_height
|
||||
detection_mode = getattr(detection_result, 'detection_mode', 'normal')
|
||||
mode_text = f"Mode: {detection_mode.upper()}"
|
||||
cv2.putText(canvas, mode_text, (x + 15, status_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['accent_cyan'], 1)
|
||||
|
||||
# 系统状态指示灯
|
||||
self._draw_status_indicator(canvas, x + w - 60, y + 30, "ONLINE", True)
|
||||
|
||||
def draw_led_matrix_panel(self, canvas: np.ndarray, led_states: List[List[bool]]):
|
||||
"""
|
||||
绘制LED状态矩阵面板
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
led_states: LED状态矩阵 (3x6)
|
||||
"""
|
||||
x, y, w, h = self.panels['led_matrix']
|
||||
|
||||
# 绘制面板
|
||||
self._draw_panel(canvas, "LED STATUS MATRIX", x, y, w, h)
|
||||
|
||||
# LED矩阵绘制
|
||||
matrix_start_x = x + 20
|
||||
matrix_start_y = y + 50
|
||||
led_size = 25
|
||||
led_spacing = 35
|
||||
|
||||
for row in range(3):
|
||||
for col in range(6):
|
||||
led_x = matrix_start_x + col * (led_size + led_spacing)
|
||||
led_y = matrix_start_y + row * (led_size + led_spacing)
|
||||
|
||||
# 确定LED状态
|
||||
is_on = False
|
||||
if row < len(led_states) and col < len(led_states[row]):
|
||||
is_on = led_states[row][col]
|
||||
|
||||
# 绘制LED
|
||||
led_color = self.colors['led_on'] if is_on else self.colors['led_off']
|
||||
cv2.circle(canvas, (led_x + led_size // 2, led_y + led_size // 2),
|
||||
led_size // 2, led_color, -1)
|
||||
|
||||
# LED边框
|
||||
border_color = self.colors['success'] if is_on else self.colors['border']
|
||||
cv2.circle(canvas, (led_x + led_size // 2, led_y + led_size // 2),
|
||||
led_size // 2, border_color, 2)
|
||||
|
||||
# LED标签
|
||||
label = f"R{row+1}C{col+1}"
|
||||
cv2.putText(canvas, label, (led_x - 5, led_y + led_size + 15),
|
||||
self.fonts['small'], 0.3,
|
||||
self.colors['text_secondary'], 1)
|
||||
|
||||
def draw_statistics_panel(self, canvas: np.ndarray, detection_result):
|
||||
"""
|
||||
绘制统计信息面板
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
detection_result: 检测结果
|
||||
"""
|
||||
x, y, w, h = self.panels['stats']
|
||||
|
||||
# 绘制面板
|
||||
self._draw_panel(canvas, "STATISTICS", x, y, w, h)
|
||||
|
||||
# 统计信息
|
||||
stats_y = y + 40
|
||||
line_height = 22
|
||||
|
||||
# 获取统计数据
|
||||
summary = detection_result.detection_summary
|
||||
if 'threshold_detection' in summary:
|
||||
states = summary['threshold_detection']['states']
|
||||
total_on = states.get('on', 0)
|
||||
total_off = states.get('off', 0)
|
||||
total_leds = total_on + total_off
|
||||
else:
|
||||
total_on = total_off = total_leds = 0
|
||||
|
||||
# LED统计
|
||||
cv2.putText(canvas, f"Total LEDs: {total_leds}", (x + 15, stats_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['text_primary'], 1)
|
||||
|
||||
stats_y += line_height
|
||||
cv2.putText(canvas, f"LEDs ON: {total_on}", (x + 15, stats_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['success'], 1)
|
||||
|
||||
stats_y += line_height
|
||||
cv2.putText(canvas, f"LEDs OFF: {total_off}", (x + 15, stats_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['led_off'], 1)
|
||||
|
||||
# 运行时间
|
||||
stats_y += line_height + 5
|
||||
runtime_text = f"Runtime: {datetime.now().strftime('%H:%M:%S')}"
|
||||
cv2.putText(canvas, runtime_text, (x + 15, stats_y),
|
||||
self.fonts['mono'], self.font_scales['mono'],
|
||||
self.colors['text_secondary'], 1)
|
||||
|
||||
def _draw_panel(self, canvas: np.ndarray, title: str, x: int, y: int, w: int, h: int):
|
||||
"""
|
||||
绘制通用面板
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
title: 面板标题
|
||||
x, y, w, h: 面板位置和大小
|
||||
"""
|
||||
# 面板背景
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + h), self.colors['bg_panel'], -1)
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + h), self.colors['border'], 2)
|
||||
|
||||
# 标题栏
|
||||
cv2.rectangle(canvas, (x, y), (x + w, y + 30), self.colors['accent_blue'], -1)
|
||||
cv2.putText(canvas, title, (x + 10, y + 20),
|
||||
self.fonts['subtitle'], self.font_scales['small'],
|
||||
self.colors['text_primary'], 1)
|
||||
|
||||
# 装饰线
|
||||
cv2.line(canvas, (x + 5, y + 32), (x + w - 5, y + 32),
|
||||
self.colors['accent_cyan'], 1)
|
||||
|
||||
def _draw_status_indicator(self, canvas: np.ndarray, x: int, y: int,
|
||||
text: str, is_active: bool):
|
||||
"""
|
||||
绘制状态指示器
|
||||
|
||||
Args:
|
||||
canvas: 画布
|
||||
x, y: 位置
|
||||
text: 状态文本
|
||||
is_active: 是否激活状态
|
||||
"""
|
||||
# 指示灯
|
||||
color = self.colors['success'] if is_active else self.colors['warning']
|
||||
cv2.circle(canvas, (x, y), 6, color, -1)
|
||||
cv2.circle(canvas, (x, y), 6, self.colors['border'], 1)
|
||||
|
||||
# 状态文本
|
||||
cv2.putText(canvas, text, (x + 15, y + 5),
|
||||
self.fonts['small'], self.font_scales['small'],
|
||||
color, 1)
|
||||
|
||||
def create_display_frame(self, video_frame: np.ndarray, detection_result) -> np.ndarray:
|
||||
"""
|
||||
创建完整的显示帧
|
||||
|
||||
Args:
|
||||
video_frame: 原始视频帧
|
||||
detection_result: 检测结果
|
||||
|
||||
Returns:
|
||||
np.ndarray: 完整的显示帧
|
||||
"""
|
||||
# 创建主画布
|
||||
canvas = self.create_main_canvas()
|
||||
|
||||
# 绘制各个组件
|
||||
self.draw_header(canvas)
|
||||
self.draw_video_panel(canvas, video_frame)
|
||||
self.draw_status_panel(canvas, detection_result)
|
||||
|
||||
# 转换LED状态为矩阵格式
|
||||
led_states = self._convert_to_matrix(detection_result)
|
||||
self.draw_led_matrix_panel(canvas, led_states)
|
||||
|
||||
self.draw_statistics_panel(canvas, detection_result)
|
||||
|
||||
return canvas
|
||||
|
||||
def _convert_to_matrix(self, detection_result) -> List[List[bool]]:
|
||||
"""
|
||||
将检测结果转换为3x6矩阵格式
|
||||
|
||||
Args:
|
||||
detection_result: 检测结果
|
||||
|
||||
Returns:
|
||||
List[List[bool]]: LED状态矩阵
|
||||
"""
|
||||
matrix = [[False] * 6 for _ in range(3)]
|
||||
|
||||
# 从检测结果中提取LED状态
|
||||
if hasattr(detection_result, 'roi_detections'):
|
||||
for roi_name, detection in detection_result.roi_detections.items():
|
||||
if roi_name.startswith('R') and 'C' in roi_name:
|
||||
try:
|
||||
row = int(roi_name[1]) - 1
|
||||
col = int(roi_name[3]) - 1
|
||||
if 0 <= row < 3 and 0 <= col < 6:
|
||||
is_on = detection.get('threshold_detection', {}).get('is_on', False)
|
||||
matrix[row][col] = is_on
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
return matrix
|
||||
82
test_ui.py
Normal file
82
test_ui.py
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
测试科技感UI界面
|
||||
"""
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
project_root = Path(__file__).parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from src.ui.tech_ui import TechUI
|
||||
|
||||
|
||||
class MockDetectionResult:
|
||||
"""模拟检测结果"""
|
||||
def __init__(self):
|
||||
self.frame_count = 1234
|
||||
self.processing_time = 0.045
|
||||
self.detection_mode = "normal"
|
||||
self.detection_summary = {
|
||||
'threshold_detection': {
|
||||
'states': {
|
||||
'on': 12,
|
||||
'off': 6
|
||||
}
|
||||
}
|
||||
}
|
||||
self.roi_detections = {}
|
||||
|
||||
# 生成模拟的LED状态
|
||||
for row in range(1, 4):
|
||||
for col in range(1, 7):
|
||||
roi_name = f"R{row}C{col}"
|
||||
is_on = (row * col) % 3 == 0 # 模拟一些LED开启
|
||||
self.roi_detections[roi_name] = {
|
||||
'threshold_detection': {
|
||||
'is_on': is_on
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
"""测试UI界面"""
|
||||
print("测试科技感UI界面...")
|
||||
|
||||
# 创建UI实例
|
||||
ui = TechUI()
|
||||
|
||||
# 创建模拟视频帧
|
||||
video_frame = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
|
||||
|
||||
# 在视频帧上添加一些模拟的LED点
|
||||
for i in range(3):
|
||||
for j in range(6):
|
||||
x = 80 + j * 80
|
||||
y = 120 + i * 80
|
||||
color = (0, 255, 0) if (i * j) % 3 == 0 else (100, 100, 100)
|
||||
cv2.circle(video_frame, (x, y), 15, color, -1)
|
||||
cv2.putText(video_frame, f"R{i+1}C{j+1}", (x-15, y+30),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1)
|
||||
|
||||
# 创建模拟检测结果
|
||||
detection_result = MockDetectionResult()
|
||||
|
||||
# 生成显示帧
|
||||
display_frame = ui.create_display_frame(video_frame, detection_result)
|
||||
|
||||
print("按任意键退出...")
|
||||
cv2.imshow('烟台蓬莱国际机场低能见度识别软件', display_frame)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
print("UI测试完成!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user