活动介绍

pyqt toolbar 改变方向

时间: 2025-07-10 17:10:13 浏览: 8
在 PyQt 中,工具栏(`QToolBar`)的方向可以通过 `setOrientation()` 方法进行调整。此方法允许将工具栏设置为水平或垂直方向,通常与主窗口的布局和用户界面设计需求相关。 默认情况下,工具栏是水平排列的,即其方向为 `Qt.Horizontal`。若需要将其改为垂直方向,则可以使用以下方式: ```python toolbar.setOrientation(Qt.Vertical) ``` 相反,如果希望恢复为水平方向,则可以使用: ```python toolbar.setOrientation(Qt.Horizontal) ``` 此外,也可以通过拖动工具栏使其停靠在主窗口的不同边缘位置,从而自动改变其方向。PyQt 提供了灵活的停靠机制来支持多个工具栏的排列组合[^1]。 ### 示例代码 以下是一个简单的示例,展示如何创建一个垂直方向的工具栏: ```python import sys from PyQt6.QtWidgets import QApplication, QMainWindow, QToolBar, QAction from PyQt6.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Toolbar Orientation Example") # 创建工具栏 toolbar = QToolBar("Vertical Toolbar") self.addToolBar(toolbar) # 设置工具栏为垂直方向 toolbar.setOrientation(Qt.Orientation.Vertical) # 添加动作 action1 = QAction("Action 1", self) toolbar.addAction(action1) action2 = QAction("Action 2", self) toolbar.addAction(action2) app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec()) ``` 该代码演示了如何将工具栏设置为垂直方向,并添加了两个动作项用于展示效果。 ### 注意事项 - 工具栏的方向变化可能会影响整体 UI 布局,因此应确保其他控件的位置和尺寸也相应调整。 - 在某些布局管理器中,直接修改工具栏方向可能会受到限制,需结合具体的父级容器进行测试。
阅读全文

相关推荐

# -*- coding: utf-8 -*- import sys import os import cv2 import numpy as np from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QWidget, QVBoxLayout, QHBoxLayout, QMessageBox, QLabel, QFileDialog, QToolBar, QComboBox, QStatusBar, QGroupBox, QSlider, QDockWidget, QProgressDialog) from PyQt5.QtCore import QRect, Qt, QSettings, QThread, pyqtSignal from CamOperation_class import CameraOperation sys.path.append("D:\\海康\\MVS\\Development\\Samples\\Python\\BasicDemo") from MvCameraControl_class import * from MvErrorDefine_const import * from CameraParams_header import * from PyUICBasicDemo import Ui_MainWindow import ctypes from datetime import datetime import logging import platform # 配置日志系统 logging.basicConfig( level=logging.DEBUG, # 设置为DEBUG级别获取更多信息 format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("cloth_inspection_debug.log"), logging.StreamHandler() ] ) logging.info("布料印花检测系统启动") # 全局变量 current_sample_path = "" # 当前使用的样本路径 detection_history = [] # 检测历史记录 # 帧监控线程 class FrameMonitorThread(QThread): frame_status = pyqtSignal(str) def __init__(self, cam_operation): super().__init__() self.cam_operation = cam_operation self.running = True def run(self): while self.running: if self.cam_operation: status = self.cam_operation.get_frame_status() frame_text = "有帧" if status.get('current_frame', False) else "无帧" self.frame_status.emit(f"帧状态: {frame_text}") QThread.msleep(500) def stop(self): self.running = False # 布料印花检测函数(修复版) def check_print_quality(sample_image_path, test_image, threshold=0.05): """ 检测布料印花是否合格,直接使用内存中的测试图像 :param sample_image_path: 合格样本图像路径 :param test_image: 内存中的测试图像 (numpy数组) :param threshold: 差异阈值 :return: 是否合格,差异值,标记图像 """ # 读取样本图像 try: sample_img_data = np.fromfile(sample_image_path, dtype=np.uint8) sample_image = cv2.imdecode(sample_img_data, cv2.IMREAD_GRAYSCALE) if sample_image is None: logging.error(f"无法解码样本图像: {sample_image_path}") return None, None, None except Exception as e: logging.exception(f"样本图像读取异常: {str(e)}") return None, None, None # 确保测试图像是灰度图 if len(test_image.shape) == 3: # 如果是彩色图像 test_image = cv2.cvtColor(test_image, cv2.COLOR_BGR2GRAY) # 确保两个图像大小一致 try: test_image = cv2.resize(test_image, (sample_image.shape[1], sample_image.shape[0])) except Exception as e: logging.error(f"图像调整大小失败: {str(e)}") return None, None, None # 计算差异 diff = cv2.absdiff(sample_image, test_image) # 二值化差异 _, thresholded = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 计算差异比例 diff_pixels = np.count_nonzero(thresholded) total_pixels = sample_image.size diff_ratio = diff_pixels / total_pixels # 判断是否合格 is_qualified = diff_ratio <= threshold # 创建标记图像(红色标记差异区域) marked_image = cv2.cvtColor(test_image, cv2.COLOR_GRAY2BGR) marked_image[thresholded == 255] = [0, 0, 255] # 红色标记 return is_qualified, diff_ratio, marked_image # 更新检测结果显示 def update_diff_display(diff_ratio, is_qualified): """ 更新差异度显示控件 """ # 更新当前差异度显示 ui.lblCurrentDiff.setText(f"当前差异度: {diff_ratio*100:.2f}%") # 根据合格状态设置颜色 if is_qualified: ui.lblDiffStatus.setText("状态: 合格") ui.lblDiffStatus.setStyleSheet("color: green; font-size: 12px;") else: ui.lblDiffStatus.setText("状态: 不合格") ui.lblDiffStatus.setStyleSheet("color: red; font-size: 12px;") # 更新差异度阈值显示 def update_diff_threshold(value): """ 当滑块值改变时更新阈值显示 """ ui.lblDiffValue.setText(f"{value}%") # 布料印花检测功能(修复版) def check_print(): global isGrabbing, obj_cam_operation, current_sample_path, detection_history logging.info("检测印花质量按钮按下") # 1. 检查相机状态 if not isGrabbing: logging.warning("相机未取流") QMessageBox.warning(mainWindow, "错误", "请先开始取流并捕获图像!", QMessageBox.Ok) return # 2. 检查相机操作对象 if not obj_cam_operation: logging.error("相机操作对象未初始化") QMessageBox.warning(mainWindow, "错误", "相机未正确初始化!", QMessageBox.Ok) return # 3. 检查样本路径 if not current_sample_path or not os.path.exists(current_sample_path): logging.warning(f"无效样本路径: {current_sample_path}") QMessageBox.warning(mainWindow, "错误", "请先设置有效的标准样本图像!", QMessageBox.Ok) return # 使用进度对话框防止UI阻塞 progress = QProgressDialog("正在检测...", "取消", 0, 100, mainWindow) progress.setWindowModality(Qt.WindowModal) progress.setValue(10) try: # 4. 获取当前帧 logging.info("尝试获取当前帧") test_image = obj_cam_operation.get_current_frame() progress.setValue(30) if test_image is None: logging.warning("获取当前帧失败") QMessageBox.warning(mainWindow, "错误", "无法获取当前帧图像!", QMessageBox.Ok) return # 5. 获取差异度阈值 diff_threshold = ui.sliderDiffThreshold.value() / 100.0 logging.info(f"使用差异度阈值: {diff_threshold}") progress.setValue(50) # 6. 执行检测 is_qualified, diff_ratio, marked_image = check_print_quality( current_sample_path, test_image, threshold=diff_threshold ) progress.setValue(70) # 检查返回结果是否有效 if is_qualified is None: logging.error("检测函数返回无效结果") QMessageBox.critical(mainWindow, "检测错误", "检测失败,请检查日志", QMessageBox.Ok) return logging.info(f"检测结果: 合格={is_qualified}, 差异={diff_ratio}") progress.setValue(90) # 7. 更新UI update_diff_display(diff_ratio, is_qualified) result_text = f"印花是否合格: {'合格' if is_qualified else '不合格'}\n差异占比: {diff_ratio*100:.2f}%\n阈值: {diff_threshold*100:.2f}%" QMessageBox.information(mainWindow, "检测结果", result_text, QMessageBox.Ok) if marked_image is not None: cv2.imshow("缺陷标记结果", marked_image) cv2.waitKey(0) cv2.destroyAllWindows() else: logging.warning("标记图像为空") # 8. 记录检测结果 detection_result = { 'timestamp': datetime.now(), 'qualified': is_qualified, 'diff_ratio': diff_ratio, 'threshold': diff_threshold } detection_history.append(detection_result) update_history_display() progress.setValue(100) except Exception as e: logging.exception("印花检测失败") QMessageBox.critical(mainWindow, "检测错误", f"检测过程中发生错误: {str(e)}", QMessageBox.Ok) finally: progress.close() # 保存标准样本函数 def save_sample_image(): global isGrabbing, obj_cam_operation, current_sample_path if not isGrabbing: QMessageBox.warning(mainWindow, "错误", "请先开始取流并捕获图像!", QMessageBox.Ok) return # 检查是否有有效图像 if not obj_cam_operation.is_frame_available(): QMessageBox.warning(mainWindow, "无有效图像", "未捕获到有效图像,请检查相机状态!", QMessageBox.Ok) return # 读取上次使用的路径 settings = QSettings("ClothInspection", "CameraApp") last_dir = settings.value("last_save_dir", os.path.join(os.getcwd(), "captures")) # 创建默认文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") default_filename = f"sample_{timestamp}" # 弹出文件保存对话框 file_path, selected_filter = QFileDialog.getSaveFileName( mainWindow, "保存标准样本图像", os.path.join(last_dir, default_filename), "BMP Files (*.bmp);;PNG Files (*.png);;JPEG Files (*.jpg);;所有文件 (*)", options=QFileDialog.DontUseNativeDialog ) if not file_path: logging.info("用户取消了图像保存操作") return # 用户取消保存 # 处理文件扩展名 file_extension = os.path.splitext(file_path)[1].lower() if not file_extension: # 根据选择的过滤器添加扩展名 if "BMP" in selected_filter: file_path += ".bmp" elif "PNG" in selected_filter: file_path += ".png" elif "JPEG" in selected_filter or "JPG" in selected_filter: file_path += ".jpg" else: # 默认使用BMP格式 file_path += ".bmp" file_extension = os.path.splitext(file_path)[1].lower() # 根据扩展名设置保存格式 format_mapping = { ".bmp": "bmp", ".png": "png", ".jpg": "jpg", ".jpeg": "jpg" } save_format = format_mapping.get(file_extension) if not save_format: QMessageBox.warning(mainWindow, "错误", "不支持的文件格式!", QMessageBox.Ok) return # 确保目录存在 directory = os.path.dirname(file_path) if directory and not os.path.exists(directory): try: os.makedirs(directory, exist_ok=True) logging.info(f"创建目录: {directory}") except OSError as e: error_msg = f"无法创建目录 {directory}: {str(e)}" QMessageBox.critical(mainWindow, "目录创建错误", error_msg, QMessageBox.Ok) return # 保存当前帧作为标准样本 try: ret = obj_cam_operation.save_image(file_path, save_format) if ret != MV_OK: strError = f"保存样本图像失败: {hex(ret)}" QMessageBox.warning(mainWindow, "错误", strError, QMessageBox.Ok) else: success_msg = f"标准样本已保存至:\n{file_path}" QMessageBox.information(mainWindow, "成功", success_msg, QMessageBox.Ok) # 更新当前样本路径 current_sample_path = file_path update_sample_display() # 保存当前目录 settings.setValue("last_save_dir", os.path.dirname(file_path)) except Exception as e: error_msg = f"保存图像时发生错误: {str(e)}" QMessageBox.critical(mainWindow, "异常错误", error_msg, QMessageBox.Ok) logging.exception("保存样本图像时发生异常") # 预览当前样本 def preview_sample(): global current_sample_path if not current_sample_path or not os.path.exists(current_sample_path): QMessageBox.warning(mainWindow, "错误", "请先设置有效的标准样本图像!", QMessageBox.Ok) return try: # 使用安全方法读取图像 img_data = np.fromfile(current_sample_path, dtype=np.uint8) sample_img = cv2.imdecode(img_data, cv2.IMREAD_COLOR) if sample_img is None: raise Exception("无法加载图像") cv2.imshow("标准样本预览", sample_img) cv2.waitKey(0) cv2.destroyAllWindows() except Exception as e: QMessageBox.warning(mainWindow, "错误", f"预览样本失败: {str(e)}", QMessageBox.Ok) # 更新样本路径显示 def update_sample_display(): global current_sample_path if current_sample_path: ui.lblSamplePath.setText(f"当前样本: {os.path.basename(current_sample_path)}") ui.lblSamplePath.setToolTip(current_sample_path) ui.bnPreviewSample.setEnabled(True) else: ui.lblSamplePath.setText("当前样本: 未设置样本") ui.bnPreviewSample.setEnabled(False) # 更新历史记录显示 def update_history_display(): global detection_history ui.cbHistory.clear() for i, result in enumerate(detection_history[-10:]): # 显示最近10条记录 timestamp = result['timestamp'].strftime("%H:%M:%S") status = "合格" if result['qualified'] else "不合格" ratio = f"{result['diff_ratio']*100:.2f}%" ui.cbHistory.addItem(f"[{timestamp}] {status} - 差异: {ratio}") # 获取选取设备信息的索引,通过[]之间的字符去解析 def TxtWrapBy(start_str, end, all): start = all.find(start_str) if start >= 0: start += len(start_str) end = all.find(end, start) if end >= 0: return all[start:end].strip() # 将返回的错误码转换为十六进制显示 def ToHexStr(num): """将错误码转换为十六进制字符串""" # 处理非整数输入 if not isinstance(num, int): try: # 尝试转换为整数 num = int(num) except: # 无法转换时返回类型信息 return f"<非整数:{type(num)}>" chaDic = {10: 'a', 11: 'b', 12: 'c', 13: 'd', 14: 'e', 15: 'f'} hexStr = "" # 处理负数 if num < 0: num = num + 2 ** 32 # 转换为十六进制 while num >= 16: digit = num % 16 hexStr = chaDic.get(digit, str(digit)) + hexStr num //= 16 hexStr = chaDic.get(num, str(num)) + hexStr return "0x" + hexStr # ch:初始化SDK | en: initialize SDK MvCamera.MV_CC_Initialize() global deviceList deviceList = MV_CC_DEVICE_INFO_LIST() global cam cam = MvCamera() global nSelCamIndex nSelCamIndex = 0 global obj_cam_operation obj_cam_operation = 0 global isOpen isOpen = False global isGrabbing isGrabbing = False global isCalibMode # 是否是标定模式(获取原始图像) isCalibMode = True global frame_monitor_thread # 绑定下拉列表至设备信息索引 def xFunc(event): global nSelCamIndex nSelCamIndex = TxtWrapBy("[", "]", ui.ComboDevices.get()) # Decoding Characters def decoding_char(c_ubyte_value): c_char_p_value = ctypes.cast(c_ubyte_value, ctypes.c_char_p) try: decode_str = c_char_p_value.value.decode('gbk') # Chinese characters except UnicodeDecodeError: decode_str = str(c_char_p_value.value) return decode_str # ch:枚举相机 | en:enum devices def enum_devices(): global deviceList global obj_cam_operation deviceList = MV_CC_DEVICE_INFO_LIST() n_layer_type = (MV_GIGE_DEVICE | MV_USB_DEVICE | MV_GENTL_CAMERALINK_DEVICE | MV_GENTL_CXP_DEVICE | MV_GENTL_XOF_DEVICE) ret = MvCamera.MV_CC_EnumDevices(n_layer_type, deviceList) if ret != 0: strError = "Enum devices fail! ret = :" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) return ret if deviceList.nDeviceNum == 0: QMessageBox.warning(mainWindow, "Info", "Find no device", QMessageBox.Ok) return ret print("Find %d devices!" % deviceList.nDeviceNum) devList = [] for i in range(0, deviceList.nDeviceNum): mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE or mvcc_dev_info.nTLayerType == MV_GENTL_GIGE_DEVICE: print("\ngige device: [%d]" % i) user_defined_name = decoding_char(mvcc_dev_info.SpecialInfo.stGigEInfo.chUserDefinedName) model_name = decoding_char(mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName) print("device user define name: " + user_defined_name) print("device model name: " + model_name) nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24) nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16) nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8) nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff) print("current ip: %d.%d.%d.%d " % (nip1, nip2, nip3, nip4)) devList.append( "[" + str(i) + "]GigE: " + user_defined_name + " " + model_name + "(" + str(nip1) + "." + str( nip2) + "." + str(nip3) + "." + str(nip4) + ")") elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE: print("\nu3v device: [%d]" % i) user_defined_name = decoding_char(mvcc_dev_info.SpecialInfo.stUsb3VInfo.chUser极DefinedName) model_name = decoding_char(mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName) print("device user define name: " + user_defined_name) print("device model name: " + model_name) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print("user serial number: " + strSerialNumber) devList.append("[" + str(i) + "]USB: " + user_defined_name + " " + model_name + "(" + str(strSerialNumber) + ")") elif mvcc_dev_info.nTLayerType == MV_GENTL_CAMERALINK_DEVICE: print("\nCML device: [%d]" % i) user_defined_name = decoding_char(mvcc_dev_info.SpecialInfo.stCMLInfo.chUserDefinedName) model_name = decoding_char(mvcc_dev_info.SpecialInfo.stCMLInfo.chModelName) print("device user define name: " + user_defined_name) print("device model name: " + model_name) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stCMLInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print("user serial number: " + strSerialNumber) devList.append("[" + str(i) + "]CML: " + user_defined_name + " " + model_name + "(" + str(strSerialNumber) + ")") elif mvcc_dev_info.nTLayerType == MV_GENTL_CXP_DEVICE: print("\nCXP device: [%d]" % i) user_defined_name = decoding_char(mvcc_dev_info.SpecialInfo.stCXPInfo.chUserDefinedName) model_name = decoding_char(mvcc_dev_info.SpecialInfo.stCXPInfo.chModelName) print("device user define name: " + user_defined_name) print("device model name: " + model_name) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stCXPInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print("user serial number: "+strSerialNumber) devList.append("[" + str(i) + "]CXP: " + user_defined_name + " " + model_name + "(" + str(strSerialNumber) + ")") elif mvcc_dev_info.nTLayerType == MV_GENTL_XOF_DEVICE: print("\nXoF device: [%d]" % i) user_defined_name = decoding_char(mvcc_dev_info.SpecialInfo.stXoFInfo.chUserDefinedName) model_name = decoding_char(mvcc_dev_info.SpecialInfo.stXoFInfo.chModelName) print("device user define name: " + user_defined_name) print("device model name: " + model_name) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stXoFInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print("user serial number: " + strSerialNumber) devList.append("[" + str(i) + "]XoF: " + user_defined_name + " " + model_name + "(" + str(strSerialNumber) + ")") ui.ComboDevices.clear() ui.ComboDevices.addItems(devList) ui.ComboDevices.setCurrentIndex(0) # ch:打开相机 | en:open device def open_device(): global deviceList global nSelCamIndex global obj_cam_operation global isOpen global frame_monitor_thread if isOpen: QMessageBox.warning(mainWindow, "Error", 'Camera is Running!', QMessageBox.Ok) return MV_E_CALLORDER nSelCamIndex = ui.ComboDevices.currentIndex() if nSelCamIndex < 0: QMessageBox.warning(mainWindow, "Error", 'Please select a camera!', QMessageBox.Ok) return MV_E_CALLORDER obj_cam_operation = CameraOperation(cam, deviceList, nSelCamIndex) ret = obj_cam_operation.open_device() if 0 != ret: strError = "Open device failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) isOpen = False else: set_continue_mode() get_param() isOpen = True enable_controls() # 启动帧监控线程 frame_monitor_thread = FrameMonitorThread(obj_cam_operation) frame_monitor_thread.frame_status.connect(ui.statusBar.showMessage) frame_monitor_thread.start() # ch:开始取流 | en:Start grab image def start_grabbing(): global obj_cam_operation global isGrabbing ret = obj_cam_operation.start_grabbing(ui.widgetDisplay.winId()) if ret != 0: strError = "Start grabbing failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) else: isGrabbing = True enable_controls() # ch:停止取流 | en:Stop grab image def stop_grabbing(): global obj_cam_operation global isGrabbing ret = obj_cam_operation.Stop_grabbing() if ret != 0: strError = "Stop grabbing failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) else: isGrabbing = False enable_controls() # ch:关闭设备 | Close device def close_device(): global isOpen global isGrabbing global obj_cam_operation global frame_monitor_thread # 停止帧监控线程 if frame_monitor_thread and frame_monitor_thread.isRunning(): frame_monitor_thread.stop() frame_monitor_thread.wait(2000) if isOpen: obj_cam_operation.close_device() isOpen = False isGrabbing = False enable_controls() # ch:设置触发模式 | en:set trigger mode def set_continue_mode(): ret = obj_cam_operation.set_trigger_mode(False) if ret != 0: strError = "Set continue mode failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) else: ui.radioContinueMode.setChecked(True) ui.radioTriggerMode.setChecked(False) ui.bnSoftwareTrigger.setEnabled(False) # ch:设置软触发模式 | en:set software trigger mode def set_software_trigger_mode(): ret = obj_cam_operation.set_trigger_mode(True) if ret != 0: strError = "Set trigger mode failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) else: ui.radioContinueMode.setChecked(False) ui.radioTriggerMode.setChecked(True) ui.bnSoftwareTrigger.setEnabled(isGrabbing) # ch:设置触发命令 | en:set trigger software def trigger_once(): ret = obj_cam_operation.trigger_once() if ret != 0: strError = "TriggerSoftware failed ret:" + ToHexStr(ret) QMessageBox.warning(mainWindow, "Error", strError, QMessageBox.Ok) # 保存图像对话框 def save_image_dialog(): """ 打开保存图像对话框并保存当前帧 """ global isGrabbing, obj_cam_operation # 检查相机状态 if not isGrabbing: QMessageBox.warning(mainWindow, "相机未就绪", "请先开始取流并捕获图像!", QMessageBox.Ok) return # 检查是否有有效图像 if not obj_cam_operation.is_frame_available(): QMessageBox.warning(mainWindow, "无有效图像", "未捕获到有效图像,请检查相机状态!", QMessageBox.Ok) return # 读取上次使用的路径 settings = QSettings("ClothInspection", "CameraApp") last_dir = settings.value("last_save_dir", os.path.join(os.getcwd(), "captures")) # 创建默认文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") default_filename = f"capture_{timestamp}" # 弹出文件保存对话框 file_path, selected_filter = QFileDialog.getSaveFileName( mainWindow, "保存图像", os.path.join(last_dir, default_filename), # 初始路径 "BMP 图像 (*.bmp);;JPEG 图像 (*.jpg);;PNG 图像 (*.png);;TIFF 图像 (*.tiff);;所有文件 (*)", options=QFileDialog.DontUseNativeDialog ) # 用户取消操作 if not file_path: logging.info("用户取消了图像保存操作") return # 处理文件扩展名 file_extension = os.path.splitext(file_path)[1].lower() if not file_extension: # 根据选择的过滤器添加扩展名 if "BMP" in selected_filter: file_path += ".bmp" elif "JPEG" in selected_filter or "JPG" in selected_filter: file_path += ".jpg" elif "PNG" in selected_filter: file_path += ".png" elif "TIFF" in selected_filter: file_path += ".tiff" else: # 默认使用BMP格式 file_path += ".bmp" # 确定保存格式 format_mapping = { ".bmp": "bmp", ".jpg": "jpg", ".jpeg": "jpg", ".png": "png", ".tiff": "tiff", ".tif": "tiff" } file_extension = os.path.splitext(file_path)[1].lower() save_format = format_mapping.get(file_extension, "bmp") # 确保目录存在 directory = os.path.dirname(file_path) if directory and not os.path.exists(directory): try: os.makedirs(directory, exist_ok=True) except OSError as e: QMessageBox.critical(mainWindow, "目录错误", f"无法创建目录:\n{str(e)}", QMessageBox.Ok) return # 保存图像 try: ret = obj_cam_operation.save_image(file_path, save_format) if ret == MV_OK: QMessageBox.information(mainWindow, "保存成功", f"图像已保存至:\n{file_path}", QMessageBox.Ok) logging.info(f"图像保存成功: {file_path}") # 保存当前目录 settings.setValue("last_save_dir", os.path.dirname(file_path)) else: error_msg = f"保存失败! 错误代码: {hex(ret)}" QMessageBox.warning(mainWindow, "保存失败", error_msg, QMessageBox.Ok) logging.error(f"图像保存失败: {file_path}, 错误代码: {hex(ret)}") except Exception as e: QMessageBox.critical(mainWindow, "保存错误", f"保存图像时发生错误:\n{str(e)}", QMessageBox.Ok) logging.exception(f"保存图像时发生异常: {file_path}") def is_float(str): try: float(str) return True except ValueError: return False # ch: 获取参数 | en:get param def get_param(): try: # 调用方法获取参数 ret = obj_cam_operation.get_parameters() # 记录调用结果(调试用) logging.debug(f"get_param() 返回: {ret} (类型: {type(ret)})") # 处理错误码 if ret != MV_OK: strError = "获取参数失败,错误码: " + ToHexStr(ret) QMessageBox.warning(mainWindow, "错误", strError, QMessageBox.Ok) else: # 成功获取参数后更新UI ui.edtExposureTime.setText("{0:.2f}".format(obj_cam_operation.exposure_time)) ui.edtGain.setText("{0:.2f}".format(obj_cam_operation.gain)) ui.edtFrameRate.setText("{0:.2f}".format(obj_cam_operation.frame_rate)) # 记录成功信息 logging.info("成功获取相机参数") except Exception as e: # 处理所有异常 error_msg = f"获取参数时发生错误: {str(e)}" logging.error(error_msg) QMessageBox.critical(mainWindow, "严重错误", error_msg, QMessageBox.Ok) # ch: 设置参数 | en:set param def set_param(): frame_rate = ui.edtFrameRate.text() exposure = ui.edtExposureTime.text() gain = ui.edtGain.text() if not (is_float(frame_rate) and is_float(exposure) and is_float(gain)): strError = "设置参数失败: 参数必须是有效的浮点数" QMessageBox.warning(mainWindow, "错误", strError, QMessageBox.Ok) return MV_E_PARAMETER try: # 使用正确的参数顺序和关键字 ret = obj_cam_operation.set_param( frame_rate=float(frame_rate), exposure_time=float(exposure), gain=float(gain) ) if ret != MV_OK: strError = "设置参数失败,错误码: " + ToHexStr(ret) QMessageBox.warning(mainWindow, "错误", strError, QMessageBox.Ok) else: logging.info("参数设置成功") return MV_OK except Exception as e: error_msg = f"设置参数时发生错误: {str(e)}" logging.error(error_msg) QMessageBox.critical(mainWindow, "严重错误", error_msg, QMessageBox.Ok) return MV_E_STATE # ch: 设置控件状态 | en:set enable status def enable_controls(): global isGrabbing global isOpen # 先设置group的状态,再单独设置各控件状态 ui.groupGrab.setEnabled(isOpen) ui.groupParam.setEnabled(isOpen) ui.bnOpen.setEnabled(not isOpen) ui.bnClose.setEnabled(isOpen) ui.bnStart.setEnabled(isOpen and (not isGrabbing)) ui.bnStop.setEnabled(isOpen and isGrabbing) ui.bnSoftwareTrigger.setEnabled(isGrabbing and ui.radioTriggerMode.isChecked()) ui.bnSaveImage.setEnabled(isOpen and isGrabbing) # 添加检测按钮控制 ui.bnCheckPrint.setEnabled(isOpen and isGrabbing) ui.bnSaveSample.setEnabled(isOpen and isGrabbing) ui.bnPreviewSample.setEnabled(bool(current_sample_path)) if __name__ == "__main__": # ch:初始化SDK | en: initialize SDK MvCamera.MV_CC_Initialize() deviceList = MV_CC_DEVICE_INFO_LIST() cam = MvCamera() nSelCamIndex = 0 obj_cam_operation = 0 isOpen = False isGrabbing = False isCalibMode = True # 是否是标定模式(获取原始图像) frame_monitor_thread = None # 初始化UI app = QApplication(sys.argv) mainWindow = QMainWindow() ui = Ui_MainWindow() ui.setupUi(mainWindow) # 扩大主窗口尺寸 mainWindow.resize(1200, 800) # 宽度1200,高度800 # 创建工具栏 toolbar = mainWindow.addToolBar("检测工具") # 添加检测按钮 ui.bnCheckPrint = QPushButton("检测印花质量") toolbar.addWidget(ui.bnCheckPrint) # 添加保存样本按钮 ui.bnSaveSample = QPushButton("保存标准样本") toolbar.addWidget(ui.bnSaveSample) # 添加预览样本按钮 ui.bnPreviewSample = QPushButton("预览样本") toolbar.addWidget(ui.bnPreviewSample) # 添加历史记录下拉框 ui.cbHistory = QComboBox() ui.cbHistory.setMinimumWidth(300) toolbar.addWidget(QLabel("历史记录:")) toolbar.addWidget(ui.cbHistory) # 添加当前样本显示标签 ui.lblSamplePath = QLabel("当前样本: 未设置样本") status_bar = mainWindow.statusBar() status_bar.addPermanentWidget(ui.lblSamplePath) # === 新增差异度调整控件 === # 创建右侧面板容器 right_panel = QWidget() right_layout = QVBoxLayout(right_panel) right_layout.setContentsMargins(10, 10, 10, 10) # 创建差异度调整组 diff_group = QGroupBox("差异度调整") diff_layout = QVBoxLayout(diff_group) # 差异度阈值控制 ui.lblDiffThreshold = QLabel("差异度阈值 (0-100%):") ui.sliderDiffThreshold = QSlider(Qt.Horizontal) ui.sliderDiffThreshold.setRange(0, 100) # 0-100% ui.sliderDiffThreshold.setValue(5) # 默认5% ui.lblDiffValue = QLabel("5%") # 当前差异度显示 ui.lblCurrentDiff = QLabel("当前差异度: -") ui.lblCurrentDiff.setStyleSheet("font-size: 14px; font-weight: bold;") # 差异度状态指示器 ui.lblDiffStatus = QLabel("状态: 未检测") ui.lblDiffStatus.setStyleSheet("font-size: 12px;") # 布局控件 diff_layout.addWidget(ui.lblDiffThreshold) diff_layout.addWidget(ui.sliderDiffThreshold) diff_layout.addWidget(ui.lblDiffValue) diff_layout.addWidget(ui.lblCurrentDiff) diff_layout.addWidget(ui.lblDiffStatus) # 添加差异度组到右侧布局 right_layout.addWidget(diff_group) # 添加拉伸项使控件靠上 right_layout.addStretch(1) # 创建停靠窗口 dock = QDockWidget("检测控制面板", mainWindow) dock.setWidget(right_panel) dock.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable) mainWindow.addDockWidget(Qt.RightDockWidgetArea, dock) # === 差异度调整功能实现 === # 更新差异度阈值显示 def update_diff_threshold(value): ui.lblDiffValue.setText(f"{value}%") # 连接滑块信号 ui.sliderDiffThreshold.valueChanged.connect(update_diff_threshold) # 更新检测结果显示 def update_diff_display(diff_ratio, is_qualified): # 更新当前差异度显示 ui.lblCurrentDiff.setText(f"当前差异度: {diff_ratio*100:.2f}%") # 根据合格状态设置颜色 if is_qualified: ui.lblDiffStatus.setText("状态: 合格") ui.lblDiffStatus.setStyleSheet("color: green; font-size: 12px;") else: ui.lblDiffStatus.setText("状态: 不合格") ui.lblDiffStatus.setStyleSheet("color: red; font-size: 12px;") # 绑定按钮事件 ui.bnCheckPrint.clicked.connect(check_print) ui.bnSaveSample.clicked.connect(save_sample_image) ui.bnPreviewSample.clicked.connect(preview_sample) # 绑定其他按钮事件 ui.bnEnum.clicked.connect(enum_devices) ui.bnOpen.clicked.connect(open_device) ui.bnClose.clicked.connect(close_device) ui.bnStart.clicked.connect(start_grabbing) ui.bnStop.clicked.connect(stop_grabbing) ui.bnSoftwareTrigger.clicked.connect(trigger_once) ui.radioTriggerMode.clicked.connect(set_software_trigger_mode) ui.radioContinueMode.clicked.connect(set_continue_mode) ui.bnGetParam.clicked.connect(get_param) ui.bnSetParam.clicked.connect(set_param) # 修改保存图像按钮连接 ui.bnSaveImage.clicked.connect(save_image_dialog) # 显示主窗口 mainWindow.show() # 执行应用 app.exec_() # 关闭设备 close_device() # ch:反初始化SDK | en: finalize SDK MvCamera.MV_CC_Finalize() sys.exit() 我感觉这个代码对于印花图案缺陷检测能力还是不够精准能否更新算法让它缺陷检测更加敏锐

exe
Windows 系统修复工具主要用于解决 Windows 11/10 系统中的各种常见问题,具有操作简单、功能全面等特点: 文件资源管理器修复:可解决文件资源管理器卡死、崩溃、无响应等问题,能终止崩溃循环。还可修复右键菜单无响应或选项缺失问题,以及重建缩略图缓存,让图片、视频等文件的缩略图正常显示,此外,还能处理桌面缺少回收站图标、回收站损坏等问题。 互联网和连接修复:能够刷新 DNS 缓存,加速网页加载速度,减少访问延迟。可重置 TCP/IP 协议栈,增强网络连接稳定性,减少网络掉线情况,还能还原 Hosts 文件,清除恶意程序对网络设置的篡改,保障网络安全,解决电脑重装系统后网络无法连接、浏览器主页被篡改等问题。 系统修复:集成系统文件检查器(SFC),可自动扫描并修复受损的系统文件。能解决 Windows 激活状态异常的问题,还可重建 DLL 注册库,恢复应用程序兼容性,解决部分软件无法正常运行的问题,同时也能处理如 Windows 沙箱无法启动、Windows 将 JPG 或 JPEG 保存为 JFIF 等系统问题。 系统工具维护:提供启动管理器、服务管理器和进程管理器等工具,用户可控制和管理启动程序、系统服务和当前运行的进程,提高系统的启动和运行速度,防止不必要的程序和服务占用系统资源。还能查看系统规格,如处理器线程数、最大显示分辨率等。 故障排除:集成超过 20 个微软官方诊断工具,可对系统问题进行专业排查,还能生成硬件健康状态报告。能解决搜索和索引故障、邮件和日历应用程序崩溃、设置应用程序无法启动等问题,也可处理打印机、网络适配器、Windows 更新等相关故障。 其他修复功能:可以重置组策略设置、catroot2 文件夹、记事本等多种系统设置和组件,如重置 Windows 应用商店缓存、Windows 防火墙设置等。还能添加重建图标缓存支持,恢复粘滞便笺删除

大家在看

recommend-type

美敦力BIS监护仪串口通讯协议手册

Document Title: BIS, MONITORING SYSTEMS, SERIAL PORT TECHNICAL SPEC
recommend-type

Cisco Enterprise Print System-开源

一组使大量打印机的管理和支持变得更加容易的工具。
recommend-type

web仿淘宝项目

大一时团队做的一个仿淘宝的web项目,没有实现后台功能
recommend-type

只输入固定-vc实现windows多显示器编程的方法

P0.0 只输入固定 P0.1 P0CON.1 P0.2 P0CON.2 PORT_SET.PORT_REFEN P0.3 P0CON.3 自动“偷”从C2的交易应用程序在. PORT_SET.PORT_CLKEN PORT_SET.PORT_CLKOUT[0] P0.4 P0CON.4 C2调试的LED驱动器的时钟输入,如果作为 未启用. P0.5 PORT_CTRL.PORT_LED[1:0] 输出港口被迫为.阅读 实际LED驱动器的状态(开/关) 用户应阅读 RBIT_DATA.GPIO_LED_DRIVE 14只脚 不能用于在开发系统中,由于C2交易扰 乱输出. 参考区间的时钟频率 对抗 控制控制 评论评论 NVM的编程电压 VPP = 6.5 V 矩阵,和ROFF工业* PORT_CTRL 2 GPIO 1 矩阵,和ROFF工业* PORT_CTRL 3 参考 clk_ref GPIO 矩阵 4 C2DAT 产量 CLK_OUT GPIO 5 C2CLK LED驱动器 1 2 工业* PORT_CTRL 1 2 3 1 2 6 产量 CLK_OUT GPIO 1 2 1 1 1 PORT_SET.PORT_CLKEN PORT_SET.PORT_CLKOUT[1] P0.6 P0CON.6 P0.7 P0CON.7 P1.0 P1CON.0 P1.1 P1CON.1 7 8 9 GPIO GPIO GPIO 14只脚 14只脚 14只脚 *注:工业注:工业 代表“独立报”设置. “ 矩阵矩阵 and Roff 模式控制模拟垫电路. 116 修订版修订版1.0
recommend-type

小游戏源码-端午节龙舟大赛.rar

小游戏源码-端午节龙舟大赛.rar

最新推荐

recommend-type

PyQt5 多窗口连接实例

在PyQt5编程中,创建和管理多个窗口是常见的需求,尤其在开发复杂的GUI应用程序时。本篇将详细解析PyQt5中实现多窗口切换的实例,帮助你理解和掌握这一核心概念。 首先,多窗口应用的基本思路是通过定义不同的窗口...
recommend-type

pyQt5实时刷新界面的示例

在Python的GUI编程中,PyQt5是一个广泛使用的库,它提供了丰富的组件和功能来创建交互式用户界面。在某些应用中,如监控、数据分析或实时数据显示,我们需要界面能够实时更新以反映最新的数据状态。本文将详细讲解...
recommend-type

PyQt5 对图片进行缩放的实例

在PyQt5中,对图片进行缩放是一个常见的任务,特别是在开发图形用户界面(GUI)应用时。在本文中,我们将深入探讨如何使用PyQt5库来实现这一功能。PyQt5是一个Python绑定的Qt库,它提供了丰富的功能,包括处理图像。...
recommend-type

PyQt5每天必学之关闭窗口

在PyQt5编程中,窗口的管理是至关重要的部分,特别是在设计用户界面时。本篇文章主要探讨了如何在PyQt5中实现窗口的关闭功能,这涉及到信号与槽的机制,以及窗口控件的交互。以下是对文章内容的详细解释: 首先,...
recommend-type

Python PyQt5整理介绍

PyQt5是Qt5库与Python的无缝集成,它使得开发者能够利用Python语言构建功能丰富的桌面应用程序。PyQt5支持Python 2.x和3.x版本,确保了广泛兼容性。 PyQt5由Riverbank Computing公司开发并维护,其官方网站提供了...
recommend-type

获取本机IP地址的程序源码分析

从给定文件信息中我们可以提取出的关键知识点是“取本机IP”的实现方法以及与之相关的编程技术和源代码。在当今的信息技术领域中,获取本机IP地址是一项基本技能,广泛应用于网络通信类的软件开发中,下面将详细介绍这一知识点。 首先,获取本机IP地址通常需要依赖于编程语言和操作系统的API。不同的操作系统提供了不同的方法来获取IP地址。在Windows操作系统中,可以通过调用Windows API中的GetAdaptersInfo()或GetAdaptersAddresses()函数来获取网络适配器信息,进而得到IP地址。在类Unix操作系统中,可以通过读取/proc/net或是使用系统命令ifconfig、ip等来获取网络接口信息。 在程序设计过程中,获取本机IP地址的源程序通常会用到网络编程的知识,比如套接字编程(Socket Programming)。网络编程允许程序之间进行通信,套接字则是在网络通信过程中用于发送和接收数据的接口。在许多高级语言中,如Python、Java、C#等,都提供了内置的网络库和类来简化网络编程的工作。 在网络通信类中,IP地址是区分不同网络节点的重要标识,它是由IP协议规定的,用于在网络中唯一标识一个网络接口。IP地址可以是IPv4,也可以是较新的IPv6。IPv4地址由32位二进制数表示,通常分为四部分,每部分由8位构成,并以点分隔,如192.168.1.1。IPv6地址则由128位二进制数表示,其表示方法与IPv4有所不同,以冒号分隔的8组16进制数表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。 当编写源代码以获取本机IP地址时,通常涉及到以下几个步骤: 1. 选择合适的编程语言和相关库。 2. 根据目标操作系统的API或系统命令获取网络接口信息。 3. 分析网络接口信息,提取出IP地址。 4. 将提取的IP地址转换成适合程序内部使用的格式。 5. 在程序中提供相应功能,如显示IP地址或用于网络通信。 例如,在Python中,可以使用内置的socket库来获取本机IP地址。一个简单的示例代码如下: ```python import socket # 获取主机名 hostname = socket.gethostname() # 获取本机IP local_ip = socket.gethostbyname(hostname) print("本机IP地址是:", local_ip) ``` 在实际应用中,获取本机IP地址通常是为了实现网络通信功能,例如建立客户端与服务器的连接,或者是在开发涉及到IP地址的其他功能时使用。 关于文件名称“getIP”,这是一个自解释的文件名,明显表示该文件或程序的作用是获取本机的IP地址。从标签“控件 源码 网络通信类 资源”中我们可以看出,这个文件很可能是一个可以嵌入其他软件中的代码片段,用以实现网络通信功能的一部分,具有较高的灵活性和重用性。 综上所述,获取本机IP地址是一个涉及到操作系统API、网络编程以及特定编程语言知识的技能。它不仅需要对编程语言提供的库函数有深入的理解,还要对操作系统的网络配置和IP协议有足够的认识。通过阅读和分析相关的源代码,如“getIP”,可以加深对网络编程实现细节的理解,并能够在实际开发中快速地应用这一技术。
recommend-type

【权威指南】:Win11笔记本上RTX4080驱动的安装与调试秘籍

# 1. Win11笔记本与RTX4080显卡介绍 随着技术的不断发展,笔记本电脑已不再是仅仅满足办公需求的移动设备,而是逐渐成为可以胜任复杂图形处理和游戏任务的强大工具。微软推出的Windows 11操作系统,以其全新的用户界面和改进的系统性能,为用户提供了更为流畅的操作体验。而在硬件方面,NVIDIA的RTX 4080显卡以其卓越的图形处理能力和AI支持,为笔记本电脑带来了前所未有的性能提升。本章节将带您初步了解Windows 11笔记本与NVIDIA RTX 4080显卡的基础信息,为进一步深入探讨它们的优化和调试技巧奠定基础。 ## 1.1 Win11笔记本的优势 Windows
recommend-type

windows环境举例

<think>好的,用户现在想在Windows环境下创建C函数库,需要具体的方法和示例代码。我需要结合之前的回答和用户提供的引用内容来给出合适的指导。 首先回顾之前的回答,用户已经了解了在Linux下创建静态库和动态库的方法,现在需要切换到Windows环境。根据引用[2],Windows下的C标准库和动态链接库的处理与Linux不同,比如使用dlfcn.h在Linux,而Windows可能需要其他方式。另外,引用[1]提到了在Windows下配置gcc环境(MinGW-w64),这可能是一个关键点,因为用户可能需要使用MinGW来编译库。 用户提供的引用[3]提到了使用MSVC编译器,这
recommend-type

QQ自动发送/回复系统源代码开放

根据提供的文件信息,我们可以了解到以下几点关键的知识点: ### 标题:“qqhelp” 1. **项目类型**: 标题“qqhelp”暗示这是一个与QQ相关的帮助工具或项目。QQ是中国流行的即时通讯软件,因此这个标题表明项目可能提供了对QQ客户端功能的辅助或扩展。 2. **用途**: “help”表明此项目的主要目的是提供帮助或解决问题。由于它提到了QQ,并且涉及“autosend/reply”功能,我们可以推测该项目可能用于自动化发送消息回复,或提供某种形式的自动回复机制。 ### 描述:“I put it to my web, but nobody sendmessage to got the source, now I public it. it supply qq,ticq autosend/reply ,full sourcecode use it as you like” 1. **发布情况**: 描述提到该项目原先被放置在某人的网站上,并且没有收到请求源代码的消息。这可能意味着项目不够知名或者需求不高。现在作者决定公开发布,这可能是因为希望项目能够被更多人了解和使用,或是出于开源共享的精神。 2. **功能特性**: 提到的“autosend/reply”表明该项目能够实现自动发送和回复消息。这种功能对于需要进行批量或定时消息沟通的应用场景非常有用,例如客户服务、自动化的营销通知等。 3. **代码可用性**: 作者指出提供了“full sourcecode”,意味着源代码完全开放,用户可以自由使用,无论是查看、学习还是修改,用户都有很大的灵活性。这对于希望学习编程或者有特定需求的开发者来说是一个很大的优势。 ### 标签:“综合系统类” 1. **项目分类**: 标签“综合系统类”表明这个项目可能是一个多功能的集成系统,它可能不仅限于QQ相关的功能,还可能包含了其他类型的综合服务或特性。 2. **技术范畴**: 这个标签可能表明该项目的技术实现比较全面,可能涉及到了多个技术栈或者系统集成的知识点,例如消息处理、网络编程、自动化处理等。 ### 压缩包子文件的文件名称列表: 1. **Unit1.dfm**: 这是一个Delphi或Object Pascal语言的窗体定义文件,用于定义应用程序中的用户界面布局。DFM文件通常用于存储组件的属性和位置信息,使得开发者可以快速地进行用户界面的设计和调整。 2. **qqhelp.dpr**: DPR是Delphi项目文件的扩展名,包含了Delphi项目的核心设置,如程序入口、使用的单元(Units)等。这个文件是编译和构建Delphi项目的起点,它能够帮助开发者了解项目的组织结构和编译指令。 3. **Unit1.pas**: PAS是Delphi或Object Pascal语言的源代码文件。这个文件可能包含了与QQ帮助工具相关的核心逻辑代码,例如处理自动发送和回复消息的算法等。 4. **readme.txt**: 这是一个常见的文本文件,包含项目的基本说明和使用指导,帮助用户了解如何获取、安装、运行和定制该项目。README文件通常是用户与项目首次交互时首先阅读的文件,因此它对于一个开源项目的用户友好度有着重要影响。 通过以上分析,我们可以看出“qqhelp”项目是一个针对QQ通讯工具的自动化消息发送与回复的辅助工具。项目包含完整的源代码,用户可以根据自己的需要进行查看、修改和使用。它可能包含Delphi语言编写的窗体界面和后端逻辑代码,具有一定的综合系统特性。项目作者出于某种原因将其开源,希望能够得到更广泛的使用和反馈。
recommend-type

【7步打造Win11深度学习利器】:Tensorflow-GPU与RTX4080终极优化指南

# 1. 深度学习与Windows 11的融合 在人工智能时代,深度学习已渗透到生活的方方面面,而Windows 11作为最新一代的操作系统,为深度学习提供了一个高效的工作平台。本章节将探讨深度学习技术如何与Windows 11系统融合,以及这一