049_Image图片

本文详细介绍了Element UI的Image组件,包括其特性、属性、事件和插槽的使用,并通过创建多个示例(基础用法、占位内容、加载失败、懒加载和大图预览)展示了其在实际项目中的应用。这些示例涵盖了图片适应容器、自定义占位符、错误处理、懒加载和预览功能。

1. Image图片

1.1. Image图片容器, 在保留原生img的特性下, 支持懒加载, 自定义占位、加载失败等。

1.2. Attributes

参数

说明

类型

可选值

默认值

src

图片源, 同原生

string

fit

确定图片如何适应容器框, 同原生object-fit

string

fill / contain / cover / none / scale-down

alt

原生alt

string

referrer-policy

原生referrerPolicy

import numpy as np import cv2 import matplotlib.pyplot as plt from scipy.linalg import lstsq def fit_camera_poly_model_3d(world_points, image_points, order): """ 拟合多项式模型(包含XYZ坐标):世界坐标 -> 图像坐标 :param world_points: N×3数组,世界坐标(X,Y,Z) :param image_points: N×2数组,图像坐标(u,v) :param order: 多项式阶数(2或3) :return: 两个函数 (modelU, modelV) 分别预测u和v坐标 """ X = world_points[:, 0] Y = world_points[:, 1] Z = world_points[:, 2] if order == 2: # 二阶多项式: 1, x, y, z, x², xy, xz, y², yz, z² A = np.column_stack([ np.ones_like(X), X, Y, Z, X ** 2, X * Y, X * Z, Y ** 2, Y * Z, Z ** 2 ]) elif order == 3: # 三阶多项式: 1, x, y, z, x², xy, xz, y², yz, z², # x³, x²y, x²z, xy², xyz, xz², y³, y²z, yz², z³ A = np.column_stack([ np.ones_like(X), X, Y, Z, X ** 2, X * Y, X * Z, Y ** 2, Y * Z, Z ** 2, X ** 3, X ** 2 * Y, X ** 2 * Z, X * Y ** 2, X * Y * Z, X * Z ** 2, Y ** 3, Y ** 2 * Z, Y * Z ** 2, Z ** 3 ]) else: raise ValueError("多项式阶数必须是2或3") # 拟合u坐标 u = image_points[:, 0] coeffs_u, _, _, _ = lstsq(A, u) # 拟合v坐标 v = image_points[:, 1] coeffs_v, _, _, _ = lstsq(A, v) # 创建预测函数 def modelU(x, y, z): return poly_val_3d(x, y, z, coeffs_u, order) def modelV(x, y, z): return poly_val_3d(x, y, z, coeffs_v, order) return modelU, modelV def poly_val_3d(x, y, z, coeffs, order): """ 三维多项式求值 :param x: x坐标值(标量或数组) :param y: y坐标值(标量或数组) :param z: z坐标值(标量或数组) :param coeffs: 多项式系数 :param order: 多项式阶数 :return: 多项式计算结果 """ if order == 2: terms = np.column_stack([ np.ones_like(x), x, y, z, x ** 2, x * y, x * z, y ** 2, y * z, z ** 2 ]) else: # order == 3 terms = np.column_stack([ np.ones_like(x), x, y, z, x ** 2, x * y, x * z, y ** 2, y * z, z ** 2, x ** 3, x ** 2 * y, x ** 2 * z, x * y ** 2, x * y * z, x * z ** 2, y ** 3, y ** 2 * z, y * z ** 2, z ** 3 ]) return np.dot(terms, coeffs) def ortho_rectification_fixed_z(org_image, ortho_image_x, ortho_image_y, modelU, modelV, fixed_z): """ 正射纠正(固定Z值) :param org_image: 原始图像 (H, W, C) :param ortho_image_x: 正射影像网格的X坐标 (H, W) :param ortho_image_y: 正射影像网格的Y坐标 (H, W) :param modelU: u坐标预测函数 (需要xyz三个参数) :param modelV: v坐标预测函数 (需要xyz三个参数) :param fixed_z: 固定的Z值 :return: 正射纠正后的图像 """ height, width = ortho_image_x.shape channels = 1 if len(org_image.shape) == 2 else org_image.shape[2] # 展平网格坐标以提高效率 X_flat = ortho_image_x.ravel() Y_flat = ortho_image_y.ravel() Z_flat = np.full_like(X_flat, fixed_z) # 使用固定Z值 # 批量预测图像坐标 u_flat = modelU(X_flat, Y_flat, Z_flat) v_flat = modelV(X_flat, Y_flat, Z_flat) # 重塑为网格 u_map = u_flat.reshape((height, width)) v_map = v_flat.reshape((height, width)) # 创建映射矩阵(OpenCV需要xy坐标) map_x = u_map.astype(np.float32) map_y = v_map.astype(np.float32) # 使用remap进行重映射(包含插值) if channels == 1: ortho_image = cv2.remap(org_image, map_x, map_y, cv2.INTER_LINEAR) else: # 分通道处理彩色图像 ortho_image = np.zeros((height, width, channels), dtype=org_image.dtype) for c in range(channels): ortho_image[:, :, c] = cv2.remap(org_image[:, :, c], map_x, map_y, cv2.INTER_LINEAR) return ortho_image def calculate_resolution(world_points, image_points): """ 计算图像分辨率(像素/世界单位) :param world_points: N×3数组,世界坐标 :param image_points: N×2数组,图像坐标 :return: 平均分辨率 """ # 计算相邻点间的世界距离(考虑XYZ) world_diffs = np.diff(world_points, axis=0) world_dists = np.sqrt(np.sum(world_diffs ** 2, axis=1)) # 计算相邻点间的图像距离 image_diffs = np.diff(image_points, axis=0) image_dists = np.sqrt(np.sum(image_diffs ** 2, axis=1)) # 计算每像素代表的世界单位数 resolutions = world_dists / (image_dists + 1e-9) # 避免除零 return np.nanmean(resolutions[np.isfinite(resolutions)]) def calculate_optimal_z(world_points): """ 计算最优的固定Z值(取所有控制点Z值的中位数) :param world_points: N×3数组,世界坐标 :return: 最优固定Z值 """ return np.median(world_points[:, 2]) # ===================== 使用真实数据 ===================== if __name__ == "__main__": # 加载真实数据(替换为您的实际数据) # worldPoints3D: N×3数组 [X, Y, Z] # imagePoints: N×2数组 [u, v] # org_image: 原始图像 # 示例数据结构(实际使用时替换为您的数据) worldPoints3D = np.array( [ [4262845.751, 644463.054, 64.289], [4262844.149, 644468.755, 63.701] , [4262846.106, 644470.001, 63.621] , [4262844.678, 644473.34, 63.613], [4262838.693, 644473.677, 63.565] , [4262833.235, 644478.754, 63.722] , [4262853.252, 644455.049, 64.177] , [4262851.546, 644451.282, 64.875], [4262837.259, 644438.863, 67.325] , [4262841.986, 644437.241, 65.751], [4262846.305, 644431.715, 66.42] , [4262851.769, 644434.948, 64.503] , [4262850.889, 644423.337, 68.04], [4262858.526, 644426.641, 64.81] , [4262860.791, 644431.732, 63.853], [4262865.608, 644419.362, 66.008] , [4262865.978, 644423.624, 64.7] , [4262857.58, 644470.911, 63.636], [4262854.209, 644478.653, 63.629] , [4262858.634, 644475.401, 63.64] ]) imagePoints = np.array([ [1058, 614], [855, 680] , [901, 711] , [727, 739], [480, 689] , [140, 694] , [1452, 599] , [1422, 545], [1439, 421] , [1269, 467], [1401, 447] , [1515, 513] , [1534, 409], [1677, 494] , [1729, 533], [1819, 471] , [1828, 506] , [1532, 816], [1100, 983] , [1557, 940] ]) # 加载原始图像 org_image = cv2.imread(r'D:\shuiwei\2.jpg') # 替换为您的图像路径 # 设置参数 polyOrder = 3 # 多项式阶数(2或3) # 1. 拟合多项式模型(包含XYZ坐标) modelU, modelV = fit_camera_poly_model_3d(worldPoints3D, imagePoints, polyOrder) # 2. 确定正射影像范围和分辨率 x_min, x_max = worldPoints3D[:, 0].min(), worldPoints3D[:, 0].max() y_min, y_max = worldPoints3D[:, 1].min(), worldPoints3D[:, 1].max() # 计算分辨率(像素/世界单位) imageRes = calculate_resolution(worldPoints3D, imagePoints) # 3. 计算最优固定Z值(或手动指定) #fixed_z = calculate_optimal_z(worldPoints3D) # 自动计算最优Z值 fixed_z = 64.3 # 或者手动指定固定Z值 print(f"使用固定Z值: {fixed_z:.2f}") # 4. 生成正射影像网格 x_grid = np.arange(x_min, x_max, imageRes) y_grid = np.arange(y_min, y_max, imageRes) orthoImageX, orthoImageY = np.meshgrid(x_grid, y_grid) # 5. 执行正射纠正(使用固定Z值) orthoImage = ortho_rectification_fixed_z( org_image, orthoImageX, orthoImageY, modelU, modelV, fixed_z ) # 6. 保存和显示结果 cv2.imwrite(r'D:\shuiwei\current_view11.jpg', orthoImage) plt.figure(figsize=(12, 6)) plt.subplot(121) plt.title("Original Image") plt.imshow(cv2.cvtColor(org_image, cv2.COLOR_BGR2RGB)) plt.subplot(122) plt.title("Orthorectified Image") plt.imshow(cv2.cvtColor(orthoImage, cv2.COLOR_BGR2RGB)) plt.tight_layout() plt.show() print(f"分辨率:{imageRes}") 生成的图像最后横向和纵向是搞反了吗?输入的图片横向像素比纵向多,但是输出的图片看上去是横纵交换了?该怎么解决呢?
最新发布
08-29
import sys import os import cv2 import numpy as np import torch from PyQt5.QtWidgets import QListWidget from facenet_pytorch import MTCNN, InceptionResnetV1 from PIL import Image from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog, QComboBox, QSlider, QMessageBox, QTextEdit, QGroupBox, QScrollArea, QDialog) from PyQt5.QtCore import Qt, QTimer from PyQt5.QtGui import QImage, QPixmap, QIcon, QFont import joblib import logging from face_recognition import FaceRecognition # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class FaceRecognitionSystem(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("寝室人脸识别系统") self.setGeometry(100, 100, 1200, 800) # 初始化人脸识别器 self.face_recognition = FaceRecognition() # 添加反馈按钮 self.add_feedback_button() def add_feedback_button(self): """添加反馈按钮到界面""" # 创建反馈按钮 self.feedback_button = QPushButton("提供反馈", self) self.feedback_button.setFixedSize(120, 40) # 设置固定大小 self.feedback_button.setStyleSheet( "QPushButton {" " background-color: #4CAF50;" " color: white;" " border-radius: 5px;" " font-weight: bold;" "}" "QPushButton:hover {" " background-color: #45a049;" "}" ) # 连接按钮点击事件 self.feedback_button.clicked.connect(self.open_feedback_dialog) # 或者添加到工具栏 self.toolbar.addWidget(self.feedback_button) def handle_feedback(self): """处理用户反馈""" if not hasattr(self, 'last_results') or not self.last_results: QMessageBox.warning(self, "警告", "没有可反馈的识别结果") return # 创建反馈对话框 dialog = QDialog(self) dialog.setWindowTitle("识别错误反馈") dialog.setFixedSize(400, 300) layout = QVBoxLayout(dialog) # 添加当前识别结果 result_label = QLabel("当前识别结果:") layout.addWidget(result_label) self.feedback_list = QListWidget() for i, result in enumerate(self.last_results, 1): label = result["label"] confidence = result["confidence"] self.feedback_list.addItem(f"人脸 #{i}: {label} (置信度: {confidence:.2f})") layout.addWidget(self.feedback_list) # 添加正确身份选择 correct_label = QLabel("正确身份:") layout.addWidget(correct_label) self.correct_combo = QComboBox() self.correct_combo.addItems( ["选择正确身份"] + self.face_recognition.dorm_members + ["陌生人", "不在列表中"]) layout.addWidget(self.correct_combo) # 添加按钮 btn_layout = QHBoxLayout() submit_btn = QPushButton("提交反馈") submit_btn.clicked.connect(lambda: self.submit_feedback(dialog)) btn_layout.addWidget(submit_btn) cancel_btn = QPushButton("取消") cancel_btn.clicked.connect(dialog.reject) btn_layout.addWidget(cancel_btn) layout.addLayout(btn_layout) dialog.exec_() def submit_feedback(self, dialog): """提交反馈并更新模型""" selected_index = self.feedback_list.currentRow() if selected_index < 0: QMessageBox.warning(self, "警告", "请选择一个识别结果") return result = self.last_results[selected_index] correct_identity = self.correct_combo.currentText() if correct_identity == "选择正确身份": QMessageBox.warning(self, "警告", "请选择正确身份") return # 保存反馈数据 self.face_recognition.save_feedback( self.current_image.copy(), result["box"], result["label"], correct_identity ) QMessageBox.information(self, "反馈提交", "感谢您的反馈!数据已保存用于改进模型") dialog.accept() def recognize_faces(self, image): """识别人脸并在图像上标注结果""" # 使用人脸识别器进行识别 self.last_results, display_image = self.face_recognition.recognize( image, threshold=self.threshold_slider.value() / 100 ) # 更新结果文本 self.update_results_text() # 显示图像 self.display_image(display_image) def update_results_text(self): """更新结果文本区域""" if not self.last_results: self.results_text.setText("未识别到任何人脸") return # 构建结果文本 result_text = "<h3>识别结果:</h3>" for i, result in enumerate(self.last_results, 1): x1, y1, x2, y2 = result["box"] label = result["label"] confidence = result["confidence"] # 处理中文显示问题 if label in self.face_recognition.dorm_members: result_text += ( f"<p><b>人脸 #{i}:</b> " f"<span style='color:green;'>寝室成员 - {label}</span><br>" f"位置: ({x1}, {y1}), 置信度: {confidence:.2f}</p>" ) else: result_text += ( f"<p><b>人脸 #{i}:</b> " f"<span style='color:red;'>陌生人</span><br>" f"位置: ({x1}, {y1}), 置信度: {confidence:.2f}</p>" ) self.results_text.setHtml(result_text) # 初始化变量 self.model_loaded = False self.camera_active = False self.video_capture = None self.timer = QTimer() self.current_image = None self.last_results = [] # 存储上次识别结果 # 创建主界面 self.main_widget = QWidget() self.setCentralWidget(self.main_widget) self.layout = QHBoxLayout(self.main_widget) # 左侧控制面板 - 占40%宽度 self.control_panel = QWidget() self.control_layout = QVBoxLayout(self.control_panel) self.control_layout.setAlignment(Qt.AlignTop) self.control_panel.setMaximumWidth(400) self.layout.addWidget(self.control_panel, 40) # 40%宽度 # 右侧图像显示区域 - 占60%宽度 self.image_panel = QWidget() self.image_layout = QVBoxLayout(self.image_panel) self.image_label = QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(800, 600) self.image_label.setStyleSheet("background-color: #333; border: 1px solid #555;") self.image_layout.addWidget(self.image_label) self.layout.addWidget(self.image_panel, 60) # 60%宽度 # 状态栏 - 先初始化状态栏 self.status_bar = self.statusBar() self.status_bar.showMessage("系统初始化中...") # 初始化UI组件 self.init_ui() # 初始化模型 self.init_models() def init_ui(self): """初始化用户界面组件""" # 标题 title_label = QLabel("寝室人脸识别系统") title_label.setFont(QFont("Arial", 18, QFont.Bold)) title_label.setAlignment(Qt.AlignCenter) title_label.setStyleSheet("color: #2c3e50; padding: 10px;") self.control_layout.addWidget(title_label) # 模型加载 model_group = QGroupBox("模型设置") model_layout = QVBoxLayout(model_group) self.load_model_btn = QPushButton("加载模型") self.load_model_btn.setIcon(QIcon.fromTheme("document-open")) self.load_model_btn.setStyleSheet("background-color: #3498db;") self.load_model_btn.clicked.connect(self.load_model) model_layout.addWidget(self.load_model_btn) self.model_status = QLabel("模型状态: 未加载") model_layout.addWidget(self.model_status) self.control_layout.addWidget(model_group) # 识别设置 settings_group = QGroupBox("识别设置") settings_layout = QVBoxLayout(settings_group) # 置信度阈值 threshold_layout = QHBoxLayout() threshold_label = QLabel("置信度阈值:") threshold_layout.addWidget(threshold_label) self.threshold_slider = QSlider(Qt.Horizontal) self.threshold_slider.setRange(0, 100) self.threshold_slider.setValue(70) self.threshold_slider.valueChanged.connect(self.update_threshold) threshold_layout.addWidget(self.threshold_slider) self.threshold_value = QLabel("0.70") threshold_layout.addWidget(self.threshold_value) settings_layout.addLayout(threshold_layout) # 显示选项 display_layout = QHBoxLayout() display_label = QLabel("显示模式:") display_layout.addWidget(display_label) self.display_combo = QComboBox() self.display_combo.addItems(["原始图像", "检测框", "识别结果"]) self.display_combo.setCurrentIndex(2) display_layout.addWidget(self.display_combo) settings_layout.addLayout(display_layout) self.control_layout.addWidget(settings_group) # 识别功能 recognition_group = QGroupBox("识别功能") recognition_layout = QVBoxLayout(recognition_group) # 图片识别 self.image_recognition_btn = QPushButton("图片识别") self.image_recognition_btn.setIcon(QIcon.fromTheme("image-x-generic")) self.image_recognition_btn.setStyleSheet("background-color: #9b59b6;") self.image_recognition_btn.clicked.connect(self.open_image) self.image_recognition_btn.setEnabled(False) recognition_layout.addWidget(self.image_recognition_btn) # 摄像头识别 self.camera_recognition_btn = QPushButton("启动摄像头识别") self.camera_recognition_btn.setIcon(QIcon.fromTheme("camera-web")) self.camera_recognition_btn.setStyleSheet("background-color: #e74c3c;") self.camera_recognition_btn.clicked.connect(self.toggle_camera) self.camera_recognition_btn.setEnabled(False) recognition_layout.addWidget(self.camera_recognition_btn) self.control_layout.addWidget(recognition_group) # 结果展示区域 - 使用QTextEdit替代QLabel results_group = QGroupBox("识别结果") results_layout = QVBoxLayout(results_group) self.results_text = QTextEdit() self.results_text.setReadOnly(True) self.results_text.setFont(QFont("Microsoft YaHei", 12)) # 使用支持中文的字体 self.results_text.setStyleSheet("background-color: #f8f9fa; border: 1px solid #ddd; padding: 10px;") self.results_text.setPlaceholderText("识别结果将显示在这里") # 添加滚动区域 scroll_area = QScrollArea() scroll_area.setWidgetResizable(True) scroll_area.setWidget(self.results_text) results_layout.addWidget(scroll_area) self.control_layout.addWidget(results_group, 1) # 占据剩余空间 # 系统信息 info_group = QGroupBox("系统信息") info_layout = QVBoxLayout(info_group) self.device_label = QLabel(f"计算设备: {'GPU' if torch.cuda.is_available() else 'CPU'}") info_layout.addWidget(self.device_label) self.model_info = QLabel("加载模型以显示信息") info_layout.addWidget(self.model_info) self.control_layout.addWidget(info_group) # 退出按钮 exit_btn = QPushButton("退出系统") exit_btn.setIcon(QIcon.fromTheme("application-exit")) exit_btn.clicked.connect(self.close) exit_btn.setStyleSheet("background-color: #ff6b6b; color: white;") self.control_layout.addWidget(exit_btn) def open_feedback_dialog(self): """打开反馈对话框""" # 实现对话框创建逻辑 dialog = FeedbackDialog(self) dialog.exec_() def init_models(self): """初始化模型组件""" # 设置设备 self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.device_label.setText(f"计算设备: {'GPU' if torch.cuda.is_available() else 'CPU'}") # 初始化人脸检测器 try: self.detector = MTCNN( keep_all=True, post_process=False, device=self.device ) self.status_bar.showMessage("MTCNN 检测器初始化完成") logger.info("MTCNN 检测器初始化完成") except Exception as e: self.status_bar.showMessage(f"MTCNN 初始化失败: {str(e)}") logger.error(f"MTCNN 初始化失败: {str(e)}") return # 初始化人脸特征提取器 try: self.embedder = InceptionResnetV1( pretrained='vggface2', classify=False, device=self.device ).eval() self.status_bar.showMessage("FaceNet 特征提取器初始化完成") logger.info("FaceNet 特征提取器初始化完成") except Exception as e: self.status_bar.showMessage(f"FaceNet 初始化失败: {str(e)}") logger.error(f"FaceNet 初始化失败: {str(e)}") def load_model(self): """加载预训练的SVM分类器""" options = QFileDialog.Options() file_path, _ = QFileDialog.getOpenFileName( self, "选择模型文件", "", "模型文件 (*.pkl);;所有文件 (*)", options=options ) if file_path: try: # 加载模型 model_data = joblib.load(file_path) self.classifier = model_data['classifier'] self.label_encoder = model_data['label_encoder'] self.dorm_members = model_data['dorm_members'] # 更新UI状态 self.model_loaded = True self.model_status.setText("模型状态: 已加载") self.model_info.setText(f"寝室成员: {', '.join(self.dorm_members)}") self.image_recognition_btn.setEnabled(True) self.camera_recognition_btn.setEnabled(True) # 状态栏消息 self.status_bar.showMessage(f"模型加载成功: {os.path.basename(file_path)}") # 显示成功消息 QMessageBox.information( self, "模型加载", f"模型加载成功!\n识别成员: {len(self.dorm_members)}人\n置信度阈值: {self.threshold_slider.value() / 100:.2f}" ) except Exception as e: QMessageBox.critical(self, "加载错误", f"模型加载失败: {str(e)}") self.status_bar.showMessage(f"模型加载失败: {str(e)}") def update_threshold(self, value): """更新置信度阈值""" threshold = value / 100 self.threshold_value.setText(f"{threshold:.2f}") self.status_bar.showMessage(f"置信度阈值更新为: {threshold:.2f}") def open_image(self): """打开图片文件进行识别""" if not self.model_loaded: QMessageBox.warning(self, "警告", "请先加载模型!") return options = QFileDialog.Options() file_path, _ = QFileDialog.getOpenFileName( self, "选择识别图片", "", "图片文件 (*.jpg *.jpeg *.png);;所有文件 (*)", options=options ) if file_path: # 读取图片 image = cv2.imread(file_path) if image is None: QMessageBox.critical(self, "错误", "无法读取图片文件!") return # 保存当前图片 self.current_image = image.copy() # 进行识别 self.recognize_faces(image) def toggle_camera(self): """切换摄像头状态""" if not self.model_loaded: QMessageBox.warning(self, "警告", "请先加载模型!") return if not self.camera_active: # 尝试打开摄像头 self.video_capture = cv2.VideoCapture(0) if not self.video_capture.isOpened(): QMessageBox.critical(self, "错误", "无法打开摄像头!") return # 启动摄像头 self.camera_active = True self.camera_recognition_btn.setText("停止摄像头识别") self.camera_recognition_btn.setIcon(QIcon.fromTheme("media-playback-stop")) self.timer.timeout.connect(self.process_camera_frame) self.timer.start(30) # 约33 FPS self.status_bar.showMessage("摄像头已启动") else: # 停止摄像头 self.camera_active = False self.camera_recognition_btn.setText("启动摄像头识别") self.camera_recognition_btn.setIcon(QIcon.fromTheme("camera-web")) self.timer.stop() if self.video_capture: self.video_capture.release() self.status_bar.showMessage("摄像头已停止") def process_camera_frame(self): """处理摄像头帧""" ret, frame = self.video_capture.read() if ret: # 保存当前帧 self.current_image = frame.copy() # 进行识别 self.recognize_faces(frame) def recognize_faces(self, image): """识别人脸并在图像上标注结果""" # 清空上次结果 self.last_results = [] # 转换为 PIL 图像 pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) # 检测人脸 boxes, probs, _ = self.detector.detect(pil_image, landmarks=True) # 获取显示选项 display_mode = self.display_combo.currentIndex() # 准备显示图像 display_image = image.copy() # 如果没有检测到人脸 if boxes is None: if display_mode == 2: # 识别结果模式 cv2.putText(display_image, "未检测到人脸", (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) self.results_text.setText("未检测到人脸") else: # 提取每个人脸 faces = [] for box in boxes: x1, y1, x2, y2 = box face = pil_image.crop((x1, y1, x2, y2)) faces.append(face) # 提取特征 embeddings = [] if faces and self.model_loaded: # 批量处理所有人脸 face_tensors = [self.preprocess_face(face) for face in faces] if face_tensors: face_tensors = torch.stack(face_tensors).to(self.device) with torch.no_grad(): embeddings = self.embedder(face_tensors).cpu().numpy() # 处理每个人脸 for i, (box, prob) in enumerate(zip(boxes, probs)): x1, y1, x2, y2 = box w, h = x2 - x1, y2 - y1 # 在图像上绘制结果 if display_mode == 0: # 原始图像 # 不绘制任何内容 pass elif display_mode == 1: # 检测框 # 绘制人脸框 cv2.rectangle(display_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) elif display_mode == 2: # 识别结果 # 绘制人脸框 color = (0, 255, 0) # 绿色 # 如果有嵌入向量,则进行识别 if i < len(embeddings): # 预测 probabilities = self.classifier.predict_proba([embeddings[i]])[0] max_prob = np.max(probabilities) pred_class = self.classifier.predict([embeddings[i]])[0] pred_label = self.label_encoder.inverse_transform([pred_class])[0] # 获取置信度阈值 threshold = self.threshold_slider.value() / 100 # 判断是否为陌生人 if max_prob < threshold or pred_label == 'stranger': label = "陌生人" color = (0, 0, 255) # 红色 else: label = pred_label color = (0, 255, 0) # 绿色 # 保存结果用于文本显示 result = { "position": (int(x1), int(y1)), "label": label, "confidence": max_prob } self.last_results.append(result) # 绘制标签 cv2.rectangle(display_image, (int(x1), int(y1)), (int(x2), int(y2)), color, 2) cv2.putText(display_image, f"{label} ({max_prob:.2f})", (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2) else: # 无法识别的处理 cv2.rectangle(display_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 165, 255), 2) cv2.putText(display_image, "处理中...", (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 165, 255), 2) # 更新结果文本 self.update_results_text() # 在图像上显示FPS(摄像头模式下) if self.camera_active: fps = self.timer.interval() if fps > 0: cv2.putText(display_image, f"FPS: {1000 / fps:.1f}", (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) # 显示图像 self.display_image(display_image) def update_results_text(self): """更新结果文本区域""" if not self.last_results: self.results_text.setText("未识别到任何人脸") return # 构建结果文本 result_text = "<h3>识别结果:</h3>" for i, result in enumerate(self.last_results, 1): x, y = result["position"] label = result["label"] confidence = result["confidence"] # 处理中文显示问题 if label in self.dorm_members: result_text += ( f"<p><b>人脸 #{i}:</b> " f"<span style='color:green;'>寝室成员 - {label}</span><br>" f"位置: ({x}, {y}), 置信度: {confidence:.2f}</p>" ) else: result_text += ( f"<p><b>人脸 #{i}:</b> " f"<span style='color:red;'>陌生人</span><br>" f"位置: ({x}, {y}), 置信度: {confidence:.2f}</p>" ) self.results_text.setHtml(result_text) def preprocess_face(self, face_img): """预处理人脸图像""" # 调整大小 face_img = face_img.resize((160, 160)) # 转换为张量并归一化 face_img = np.array(face_img).astype(np.float32) / 255.0 face_img = (face_img - 0.5) / 0.5 # 归一化到[-1, 1] face_img = torch.tensor(face_img).permute(2, 0, 1) # HWC to CHW return face_img def display_image(self, image): """在QLabel中显示图像""" # 将OpenCV图像转换为Qt格式 height, width, channel = image.shape bytes_per_line = 3 * width q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format_RGB888).rgbSwapped() # 缩放图像以适应标签 pixmap = QPixmap.fromImage(q_img) self.image_label.setPixmap(pixmap.scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation )) def closeEvent(self, event): """关闭事件处理""" if self.camera_active: self.timer.stop() if self.video_capture: self.video_capture.release() # 确认退出 reply = QMessageBox.question( self, '确认退出', "确定要退出系统吗?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No ) if reply == QMessageBox.Yes: event.accept() else: event.ignore() 帮我改吧,已经不知道改哪里了
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值