diff --git a/LPRNET_part/LPRNet__iteration_74000.pth b/LPRNET_part/LPRNet__iteration_74000.pth new file mode 100644 index 0000000..6189faa Binary files /dev/null and b/LPRNET_part/LPRNet__iteration_74000.pth differ diff --git a/LPRNET_part/吉CF18040.jpg b/LPRNET_part/吉CF18040.jpg new file mode 100644 index 0000000..29d94e6 Binary files /dev/null and b/LPRNET_part/吉CF18040.jpg differ diff --git a/LPRNET_part/藏A0DBN8.jpg b/LPRNET_part/藏A0DBN8.jpg new file mode 100644 index 0000000..32ddef3 Binary files /dev/null and b/LPRNET_part/藏A0DBN8.jpg differ diff --git a/main.py b/main.py index e0d6477..a589b39 100644 --- a/main.py +++ b/main.py @@ -1,25 +1,23 @@ import sys +import os import cv2 import numpy as np -from PyQt5.QtWidgets import ( - QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, - QLabel, QPushButton, QScrollArea, QFrame, QSizePolicy -) +from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, \ + QFileDialog, QFrame, QScrollArea, QComboBox from PyQt5.QtCore import QTimer, Qt, pyqtSignal, QThread from PyQt5.QtGui import QImage, QPixmap, QFont, QPainter, QPen, QColor -import os from yolopart.detector import LicensePlateYOLO #选择使用哪个模块 -from LPRNET_part.lpr_interface import LPRNmodel_predict -from LPRNET_part.lpr_interface import LPRNinitialize_model +# from LPRNET_part.lpr_interface import LPRNmodel_predict +# from LPRNET_part.lpr_interface import LPRNinitialize_model #使用OCR -#from OCR_part.ocr_interface import LPRNmodel_predict -#from OCR_part.ocr_interface import LPRNinitialize_model +# from OCR_part.ocr_interface import LPRNmodel_predict +# from OCR_part.ocr_interface import LPRNinitialize_model # 使用CRNN -#from CRNN_part.crnn_interface import LPRNmodel_predict -#from CRNN_part.crnn_interface import LPRNinitialize_model +# from CRNN_part.crnn_interface import LPRNmodel_predict +# from CRNN_part.crnn_interface import LPRNinitialize_model class CameraThread(QThread): """摄像头线程类""" @@ -56,6 +54,60 @@ class CameraThread(QThread): self.frame_ready.emit(frame) self.msleep(30) # 约30fps +class VideoThread(QThread): + """视频处理线程类""" + frame_ready = pyqtSignal(np.ndarray) + video_finished = pyqtSignal() + + def __init__(self): + super().__init__() + self.video_path = None + self.cap = None + self.running = False + self.paused = False + + def load_video(self, video_path): + """加载视频文件""" + self.video_path = video_path + self.cap = cv2.VideoCapture(video_path) + return self.cap.isOpened() + + def start_video(self): + """开始播放视频""" + if self.cap and self.cap.isOpened(): + self.running = True + self.paused = False + self.start() + return True + return False + + def pause_video(self): + """暂停/继续视频""" + self.paused = not self.paused + return self.paused + + def stop_video(self): + """停止视频""" + self.running = False + if self.cap: + self.cap.release() + self.quit() + self.wait() + + def run(self): + """线程运行函数""" + while self.running: + if not self.paused and self.cap and self.cap.isOpened(): + ret, frame = self.cap.read() + if ret: + self.frame_ready.emit(frame) + else: + # 视频播放结束 + self.video_finished.emit() + self.running = False + break + self.msleep(30) # 约30fps + class LicensePlateWidget(QWidget): """单个车牌结果显示组件""" @@ -162,15 +214,21 @@ class MainWindow(QMainWindow): super().__init__() self.detector = None self.camera_thread = None + self.video_thread = None self.current_frame = None self.detections = [] + self.current_mode = "camera" # 当前模式:camera, video, image + self.is_processing = False # 标志位,表示是否正在处理识别任务 + self.last_plate_results = [] # 存储上一次的车牌识别结果 + self.current_recognition_method = "CRNN" # 当前识别方法 self.init_ui() self.init_detector() self.init_camera() + self.init_video() - # 初始化OCR/CRNN模型(函数名改成一样的了,所以不要修改这里了,想用哪个模块直接导入) - LPRNinitialize_model() + # 初始化默认识别方法(CRNN)的模型 + self.change_recognition_method(self.current_recognition_method) def init_ui(self): @@ -197,7 +255,7 @@ class MainWindow(QMainWindow): self.camera_label.setStyleSheet("QLabel { background-color: black; border: 1px solid #ccc; }") self.camera_label.setAlignment(Qt.AlignCenter) self.camera_label.setText("摄像头未启动") - self.camera_label.setScaledContents(True) + self.camera_label.setScaledContents(False) # 控制按钮 button_layout = QHBoxLayout() @@ -207,8 +265,26 @@ class MainWindow(QMainWindow): self.stop_button.clicked.connect(self.stop_camera) self.stop_button.setEnabled(False) + # 视频控制按钮 + self.open_video_button = QPushButton("打开视频") + self.stop_video_button = QPushButton("停止视频") + self.pause_video_button = QPushButton("暂停视频") + self.open_video_button.clicked.connect(self.open_video_file) + self.stop_video_button.clicked.connect(self.stop_video) + self.pause_video_button.clicked.connect(self.pause_video) + self.stop_video_button.setEnabled(False) + self.pause_video_button.setEnabled(False) + + # 图片控制按钮 + self.open_image_button = QPushButton("打开图片") + self.open_image_button.clicked.connect(self.open_image_file) + button_layout.addWidget(self.start_button) button_layout.addWidget(self.stop_button) + button_layout.addWidget(self.open_video_button) + button_layout.addWidget(self.stop_video_button) + button_layout.addWidget(self.pause_video_button) + button_layout.addWidget(self.open_image_button) button_layout.addStretch() left_layout.addWidget(self.camera_label) @@ -227,6 +303,20 @@ class MainWindow(QMainWindow): title_label.setFont(QFont("Arial", 16, QFont.Bold)) title_label.setStyleSheet("QLabel { color: #333; padding: 10px; }") + # 识别方法选择 + method_layout = QHBoxLayout() + method_label = QLabel("识别方法:") + method_label.setFont(QFont("Arial", 10)) + + self.method_combo = QComboBox() + self.method_combo.addItems(["CRNN", "LPRNET", "OCR"]) + self.method_combo.setCurrentText("CRNN") # 默认选择CRNN + self.method_combo.currentTextChanged.connect(self.change_recognition_method) + + method_layout.addWidget(method_label) + method_layout.addWidget(self.method_combo) + method_layout.addStretch() + # 车牌数量显示 self.count_label = QLabel("识别到的车牌数量: 0") self.count_label.setAlignment(Qt.AlignCenter) @@ -253,9 +343,17 @@ class MainWindow(QMainWindow): scroll_area.setWidget(self.results_widget) + # 当前识别任务显示 + self.current_method_label = QLabel("当前识别方法: CRNN") + self.current_method_label.setAlignment(Qt.AlignRight) + self.current_method_label.setFont(QFont("Arial", 9)) + self.current_method_label.setStyleSheet("QLabel { color: #666; padding: 5px; }") + right_layout.addWidget(title_label) + right_layout.addLayout(method_layout) right_layout.addWidget(self.count_label) right_layout.addWidget(scroll_area) + right_layout.addWidget(self.current_method_label) # 添加到主布局 main_layout.addWidget(left_frame, 2) @@ -296,6 +394,12 @@ class MainWindow(QMainWindow): self.camera_thread = CameraThread() self.camera_thread.frame_ready.connect(self.process_frame) + def init_video(self): + """初始化视频线程""" + self.video_thread = VideoThread() + self.video_thread.frame_ready.connect(self.process_frame) + self.video_thread.video_finished.connect(self.on_video_finished) + def start_camera(self): """启动摄像头""" if self.camera_thread.start_camera(): @@ -311,23 +415,167 @@ class MainWindow(QMainWindow): self.start_button.setEnabled(True) self.stop_button.setEnabled(False) self.camera_label.setText("摄像头已停止") - self.camera_label.clear() + # 只在摄像头模式下清除标签内容 + if self.current_mode == "camera": + self.camera_label.clear() + + def on_video_finished(self): + """视频播放结束时的处理""" + self.video_thread.stop_video() + self.open_video_button.setEnabled(True) + self.stop_video_button.setEnabled(False) + self.pause_video_button.setEnabled(False) + self.camera_label.setText("视频播放结束") + self.current_mode = "camera" + + def open_video_file(self): + """打开视频文件""" + # 停止当前模式 + if self.current_mode == "camera" and self.camera_thread and self.camera_thread.running: + self.stop_camera() + elif self.current_mode == "video" and self.video_thread and self.video_thread.running: + self.stop_video() + + # 选择视频文件 + video_path, _ = QFileDialog.getOpenFileName(self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mov *.mkv)") + + if video_path: + if self.video_thread.load_video(video_path): + self.current_mode = "video" + self.start_video() + self.camera_label.setText(f"正在播放视频: {os.path.basename(video_path)}") + else: + self.camera_label.setText("视频加载失败") + + def start_video(self): + """开始播放视频""" + if self.video_thread.start_video(): + self.open_video_button.setEnabled(False) + self.stop_video_button.setEnabled(True) + self.pause_video_button.setEnabled(True) + self.pause_video_button.setText("暂停") + else: + self.camera_label.setText("视频播放失败") + + def pause_video(self): + """暂停/继续视频""" + if self.video_thread.pause_video(): + self.pause_video_button.setText("继续") + else: + self.pause_video_button.setText("暂停") + + def stop_video(self): + """停止视频""" + self.video_thread.stop_video() + self.open_video_button.setEnabled(True) + self.stop_video_button.setEnabled(False) + self.pause_video_button.setEnabled(False) + self.camera_label.setText("视频已停止") + # 只在视频模式下清除标签内容 + if self.current_mode == "video": + self.camera_label.clear() + self.current_mode = "camera" + + def open_image_file(self): + """打开图片文件""" + # 停止当前模式 + if self.current_mode == "camera" and self.camera_thread and self.camera_thread.running: + self.stop_camera() + elif self.current_mode == "video" and self.video_thread and self.video_thread.running: + self.stop_video() + + # 选择图片文件 + image_path, _ = QFileDialog.getOpenFileName(self, "选择图片文件", "", "图片文件 (*.jpg *.jpeg *.png *.bmp)") + + if image_path: + self.current_mode = "image" + try: + # 读取图片 - 方法1: 使用cv2.imdecode处理中文路径 + image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR) + + # 如果方法1失败,尝试方法2: 直接使用cv2.imread + if image is None: + image = cv2.imread(image_path) + + if image is not None: + print(f"成功加载图片: {image_path}, 尺寸: {image.shape}") + self.process_image(image) + # 不在这里设置文本,避免覆盖图片 + # self.camera_label.setText(f"正在显示图片: {os.path.basename(image_path)}") + else: + print(f"图片加载失败: {image_path}") + self.camera_label.setText("图片加载失败") + except Exception as e: + print(f"图片处理异常: {str(e)}") + self.camera_label.setText(f"图片处理错误: {str(e)}") + + def process_image(self, image): + """处理图片""" + try: + print(f"开始处理图片,图片尺寸: {image.shape}") + self.current_frame = image.copy() + + # 进行车牌检测 + print("正在进行车牌检测...") + self.detections = self.detector.detect_license_plates(image) + print(f"检测到 {len(self.detections)} 个车牌") + + # 在图像上绘制检测结果 + print("正在绘制检测结果...") + display_frame = self.draw_detections(image.copy()) + + # 转换为Qt格式并显示 + print("正在显示图片...") + self.display_frame(display_frame) + + # 更新右侧结果显示 + print("正在更新结果显示...") + self.update_results_display() + print("图片处理完成") + except Exception as e: + print(f"图片处理过程中出错: {str(e)}") + import traceback + traceback.print_exc() def process_frame(self, frame): """处理摄像头帧""" self.current_frame = frame.copy() - # 进行车牌检测 - self.detections = self.detector.detect_license_plates(frame) + # 先显示原始帧,保证视频流畅播放 + self.display_frame(frame) - # 在图像上绘制检测结果 - display_frame = self.draw_detections(frame.copy()) - - # 转换为Qt格式并显示 - self.display_frame(display_frame) - - # 更新右侧结果显示 - self.update_results_display() + # 如果当前没有在处理识别任务,则开始新的识别任务 + if not self.is_processing: + self.is_processing = True + # 异步进行车牌检测和识别 + QTimer.singleShot(0, self.async_detect_and_update) + + def async_detect_and_update(self): + """异步进行车牌检测和识别""" + if self.current_frame is None: + self.is_processing = False # 重置标志位 + return + + try: + # 进行车牌检测 + self.detections = self.detector.detect_license_plates(self.current_frame) + + # 在图像上绘制检测结果 + display_frame = self.draw_detections(self.current_frame.copy()) + + # 更新显示帧(显示带检测结果的帧) + # 无论是摄像头模式还是视频模式,都显示检测框 + self.display_frame(display_frame) + + # 更新右侧结果显示 + self.update_results_display() + except Exception as e: + print(f"异步检测和更新失败: {str(e)}") + import traceback + traceback.print_exc() + finally: + # 无论成功或失败,都要重置标志位 + self.is_processing = False def draw_detections(self, frame): """在图像上绘制检测结果""" @@ -335,14 +583,96 @@ class MainWindow(QMainWindow): def display_frame(self, frame): """显示帧到界面""" - rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - h, w, ch = rgb_frame.shape - bytes_per_line = ch * w - qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) - - pixmap = QPixmap.fromImage(qt_image) - scaled_pixmap = pixmap.scaled(self.camera_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) - self.camera_label.setPixmap(scaled_pixmap) + try: + print(f"开始显示帧,帧尺寸: {frame.shape}") + + # 方法1: 标准方法 + try: + rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + h, w, ch = rgb_frame.shape + bytes_per_line = ch * w + qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) + + print(f"方法1: 创建QImage,尺寸: {qt_image.width()}x{qt_image.height()}") + if qt_image.isNull(): + print("方法1: QImage为空,尝试方法2") + raise Exception("QImage为空") + + pixmap = QPixmap.fromImage(qt_image) + if pixmap.isNull(): + print("方法1: QPixmap为空,尝试方法2") + raise Exception("QPixmap为空") + + # 手动缩放图片以适应标签大小,保持宽高比 + scaled_pixmap = pixmap.scaled(self.camera_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) + self.camera_label.setPixmap(scaled_pixmap) + print("方法1: 帧显示完成") + return + except Exception as e1: + print(f"方法1失败: {str(e1)}") + + # 方法2: 使用imencode和imdecode + try: + print("尝试方法2: 使用imencode和imdecode") + _, buffer = cv2.imencode('.jpg', frame) + rgb_frame = cv2.imdecode(buffer, cv2.IMREAD_COLOR) + rgb_frame = cv2.cvtColor(rgb_frame, cv2.COLOR_BGR2RGB) + h, w, ch = rgb_frame.shape + bytes_per_line = ch * w + qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) + + print(f"方法2: 创建QImage,尺寸: {qt_image.width()}x{qt_image.height()}") + if qt_image.isNull(): + print("方法2: QImage为空") + raise Exception("QImage为空") + + pixmap = QPixmap.fromImage(qt_image) + if pixmap.isNull(): + print("方法2: QPixmap为空") + raise Exception("QPixmap为空") + + # 手动缩放图片以适应标签大小,保持宽高比 + scaled_pixmap = pixmap.scaled(self.camera_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) + self.camera_label.setPixmap(scaled_pixmap) + print("方法2: 帧显示完成") + return + except Exception as e2: + print(f"方法2失败: {str(e2)}") + + # 方法3: 直接使用QImage的构造函数 + try: + print("尝试方法3: 直接使用QImage的构造函数") + height, width, channel = frame.shape + bytes_per_line = 3 * width + q_image = QImage(frame.data, width, height, bytes_per_line, QImage.Format_BGR888) + + print(f"方法3: 创建QImage,尺寸: {q_image.width()}x{q_image.height()}") + if q_image.isNull(): + print("方法3: QImage为空") + raise Exception("QImage为空") + + pixmap = QPixmap.fromImage(q_image) + if pixmap.isNull(): + print("方法3: QPixmap为空") + raise Exception("QPixmap为空") + + # 手动缩放图片以适应标签大小,保持宽高比 + scaled_pixmap = pixmap.scaled(self.camera_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) + self.camera_label.setPixmap(scaled_pixmap) + print("方法3: 帧显示完成") + return + except Exception as e3: + print(f"方法3失败: {str(e3)}") + + # 所有方法都失败 + print("所有显示方法都失败") + self.camera_label.setText("图片显示失败") + + except Exception as e: + print(f"显示帧过程中出错: {str(e)}") + import traceback + traceback.print_exc() + self.camera_label.setText(f"显示错误: {str(e)}") def update_results_display(self): """更新右侧结果显示""" @@ -350,13 +680,8 @@ class MainWindow(QMainWindow): count = len(self.detections) self.count_label.setText(f"识别到的车牌数量: {count}") - # 清除之前的结果 - for i in reversed(range(self.results_layout.count())): - child = self.results_layout.itemAt(i).widget() - if child: - child.setParent(None) - - # 添加新的结果 + # 准备新的车牌结果列表 + new_plate_results = [] for i, detection in enumerate(self.detections): # 矫正车牌图像 corrected_image = self.correct_license_plate(detection) @@ -364,15 +689,53 @@ class MainWindow(QMainWindow): # 获取车牌号,传入车牌类型信息 plate_number = self.recognize_plate_number(corrected_image, detection['class_name']) - # 创建车牌显示组件 - plate_widget = LicensePlateWidget( - i + 1, - detection['class_name'], - corrected_image, - plate_number - ) + # 添加到新结果列表 + new_plate_results.append({ + 'id': i + 1, + 'class_name': detection['class_name'], + 'corrected_image': corrected_image, + 'plate_number': plate_number + }) + + # 比较新旧结果是否相同 + results_changed = False + if len(self.last_plate_results) != len(new_plate_results): + results_changed = True + else: + for i in range(len(new_plate_results)): + if i >= len(self.last_plate_results): + results_changed = True + break + + last_result = self.last_plate_results[i] + new_result = new_plate_results[i] + + # 比较车牌类型和车牌号 + if (last_result['class_name'] != new_result['class_name'] or + last_result['plate_number'] != new_result['plate_number']): + results_changed = True + break + + # 只有当结果发生变化时才更新显示 + if results_changed: + # 清除之前的结果 + for i in reversed(range(self.results_layout.count())): + child = self.results_layout.itemAt(i).widget() + if child: + child.setParent(None) - self.results_layout.addWidget(plate_widget) + # 添加新的结果 + for result in new_plate_results: + plate_widget = LicensePlateWidget( + result['id'], + result['class_name'], + result['corrected_image'], + result['plate_number'] + ) + self.results_layout.addWidget(plate_widget) + + # 更新存储的上一次结果 + self.last_plate_results = new_plate_results def correct_license_plate(self, detection): """矫正车牌图像""" @@ -390,40 +753,69 @@ class MainWindow(QMainWindow): ) def recognize_plate_number(self, corrected_image, class_name): - """识别车牌号""" - if corrected_image is None: - return "识别失败" - - try: - # 预测函数(来自模块) - # 函数名改成一样的了,所以不要修改这里了,想用哪个模块直接导入 - result = LPRNmodel_predict(corrected_image) - - # 将字符列表转换为字符串,支持8位车牌号 - if isinstance(result, list) and len(result) >= 7: - # 根据车牌类型决定显示位数 - if class_name == '绿牌' and len(result) >= 8: - # 绿牌显示8位,过滤掉空字符占位符 - plate_chars = [char for char in result[:8] if char != ''] - # 如果过滤后确实有8位,显示8位;否则显示7位 - if len(plate_chars) == 8: - return ''.join(plate_chars) - else: - return ''.join(plate_chars[:7]) - else: - # 蓝牌或其他类型显示前7位,过滤掉空字符 - plate_chars = [char for char in result[:7] if char != ''] - return ''.join(plate_chars) - else: - return "识别失败" - except Exception as e: - print(f"车牌号识别失败: {e}") - return "识别失败" + """识别车牌号""" + if corrected_image is None: + return "识别失败" + + try: + # 根据当前选择的识别方法调用相应的函数 + if self.current_recognition_method == "CRNN": + from CRNN_part.crnn_interface import LPRNmodel_predict + elif self.current_recognition_method == "LPRNET": + from LPRNET_part.lpr_interface import LPRNmodel_predict + elif self.current_recognition_method == "OCR": + from OCR_part.ocr_interface import LPRNmodel_predict + + # 预测函数(来自模块) + result = LPRNmodel_predict(corrected_image) + + # 将字符列表转换为字符串,支持8位车牌号 + if isinstance(result, list) and len(result) >= 7: + # 根据车牌类型决定显示位数 + if class_name == '绿牌' and len(result) >= 8: + # 绿牌显示8位,过滤掉空字符占位符 + plate_chars = [char for char in result[:8] if char != ''] + # 如果过滤后确实有8位,显示8位;否则显示7位 + if len(plate_chars) == 8: + return ''.join(plate_chars) + else: + return ''.join(plate_chars[:7]) + else: + # 蓝牌或其他类型显示前7位,过滤掉空字符 + plate_chars = [char for char in result[:7] if char != ''] + return ''.join(plate_chars) + else: + return "识别失败" + except Exception as e: + print(f"车牌号识别失败: {e}") + return "识别失败" + + def change_recognition_method(self, method): + """切换识别方法""" + self.current_recognition_method = method + self.current_method_label.setText(f"当前识别方法: {method}") + + # 初始化对应的模型 + if method == "CRNN": + from CRNN_part.crnn_interface import LPRNinitialize_model + LPRNinitialize_model() + elif method == "LPRNET": + from LPRNET_part.lpr_interface import LPRNinitialize_model + LPRNinitialize_model() + elif method == "OCR": + from OCR_part.ocr_interface import LPRNinitialize_model + LPRNinitialize_model() + + # 如果当前有显示的帧,重新处理以更新识别结果 + if self.current_frame is not None: + self.process_frame(self.current_frame) def closeEvent(self, event): """窗口关闭事件""" - if self.camera_thread: + if self.camera_thread and self.camera_thread.running: self.camera_thread.stop_camera() + if self.video_thread and self.video_thread.running: + self.video_thread.stop_video() event.accept() def main(): diff --git a/test_lpr_real_images.py b/test_lpr_real_images.py new file mode 100644 index 0000000..ce32954 --- /dev/null +++ b/test_lpr_real_images.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +LPRNet接口真实图片测试脚本 +测试LPRNET_part目录下的真实车牌图片 +""" + +import cv2 +import numpy as np +import os +from LPRNET_part.lpr_interface import LPRNinitialize_model, LPRNmodel_predict + +def test_real_images(): + """ + 测试LPRNET_part目录下的真实车牌图片 + """ + print("=== LPRNet真实图片测试 ===") + + # 初始化模型 + print("1. 初始化LPRNet模型...") + success = LPRNinitialize_model() + if not success: + print("模型初始化失败!") + return + + # 获取LPRNET_part目录下的图片文件 + lprnet_dir = "LPRNET_part" + image_files = [] + + if os.path.exists(lprnet_dir): + for file in os.listdir(lprnet_dir): + if file.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')): + image_files.append(os.path.join(lprnet_dir, file)) + + if not image_files: + print("未找到图片文件!") + return + + print(f"2. 找到 {len(image_files)} 个图片文件") + + # 测试每个图片 + for i, image_path in enumerate(image_files, 1): + print(f"\n--- 测试图片 {i}: {os.path.basename(image_path)} ---") + + try: + # 使用支持中文路径的方式读取图片 + image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR) + + if image is None: + print(f"无法读取图片: {image_path}") + continue + + print(f"图片尺寸: {image.shape}") + + # 进行预测 + result = LPRNmodel_predict(image) + print(f"识别结果: {result}") + print(f"识别车牌号: {''.join(result)}") + + except Exception as e: + print(f"处理图片 {image_path} 时出错: {e}") + import traceback + traceback.print_exc() + + print("\n=== 测试完成 ===") + +def test_image_loading(): + """ + 测试图片加载方式 + """ + print("\n=== 图片加载测试 ===") + + lprnet_dir = "LPRNET_part" + + if os.path.exists(lprnet_dir): + for file in os.listdir(lprnet_dir): + if file.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')): + image_path = os.path.join(lprnet_dir, file) + print(f"\n测试文件: {file}") + + # 方法1: 普通cv2.imread + img1 = cv2.imread(image_path) + print(f"cv2.imread结果: {img1 is not None}") + + # 方法2: 支持中文路径的方式 + try: + img2 = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR) + print(f"cv2.imdecode结果: {img2 is not None}") + if img2 is not None: + print(f"图片尺寸: {img2.shape}") + except Exception as e: + print(f"cv2.imdecode失败: {e}") + +if __name__ == "__main__": + # 首先测试图片加载 + test_image_loading() + + # 然后测试完整的识别流程 + test_real_images() \ No newline at end of file