当前位置: 首页 > news >正文

linux实战:基于Ubuntu的专业相机

核心组件就是QTimer+OpenCV的组合方案
摄像头启停控制用QPushButton实现,帧显示必须用QLabel而不能用普通控件,视频流刷新用QTimer比多线程更简单
想快速实现摄像头控制功能,核心组件就是QTimer+OpenCV的组合方案。摄像头启停控制用QPushButton实现,帧显示必须用QLabel而不能用普通控件,视频流刷新用QTimer比多线程更简单。拍照功能整合进来作为扩展功能。代码结构上应该分三层:界面层用QMainWindow组织按钮和显示区域,逻辑层用VideoCapture和QTimer控制帧率,转换层需要处理OpenCV的BGR转Qt的RGB格式。特别注意摄像头资源释放要放在窗口关闭事件里,不然会报错。
import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget, QSlider, QGroupBox, QGridLayout, QComboBox, QMessageBox,QHBoxLayout)
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import Qt, QTimer,QDateTimeclass CameraController(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("专业级摄像头控制器")self.setGeometry(100, 100, 800, 600)# 主组件self.central_widget = QWidget()self.setCentralWidget(self.central_widget)self.layout = QVBoxLayout()self.central_widget.setLayout(self.layout)# 摄像头显示区域self.video_label = QLabel()self.video_label.setAlignment(Qt.AlignCenter)self.video_label.setMinimumSize(640, 480)self.layout.addWidget(self.video_label)# 控制按钮self.control_layout = QVBoxLayout()# 相机控制按钮self.btn_layout = QHBoxLayout()self.start_btn = QPushButton("启动摄像头")self.pause_btn = QPushButton("暂停")self.pause_btn.setEnabled(False)self.capture_btn = QPushButton("拍照")self.capture_btn.setEnabled(False)self.close_btn = QPushButton("退出")self.btn_layout.addWidget(self.start_btn)self.btn_layout.addWidget(self.pause_btn)self.btn_layout.addWidget(self.capture_btn)self.btn_layout.addWidget(self.close_btn)self.control_layout.addLayout(self.btn_layout)# 参数控制面板self.create_parameter_controls()self.layout.addLayout(self.control_layout)# 摄像头及计时器self.camera = Noneself.timer = QTimer()self.is_camera_active = False# 连接信号self.start_btn.clicked.connect(self.start_camera)self.pause_btn.clicked.connect(self.pause_camera)self.capture_btn.clicked.connect(self.capture_frame)self.close_btn.clicked.connect(self.close_app)# 状态提示self.status_label = QLabel("状态: 未启动")self.layout.addWidget(self.status_label)def create_parameter_controls(self):"""创建相机参数控制面板"""# 参数控制组self.params_group = QGroupBox("相机参数调节")params_layout = QGridLayout()# 亮度控制self.brightness_slider = self.create_slider("亮度", 0, 255, 128)params_layout.addWidget(QLabel("亮度:"), 0, 0)params_layout.addWidget(self.brightness_slider, 0, 1)# 对比度控制self.contrast_slider = self.create_slider("对比度", 0, 100, 50)params_layout.addWidget(QLabel("对比度:"), 1, 0)params_layout.addWidget(self.contrast_slider, 1, 1)# 饱和度控制self.saturation_slider = self.create_slider("饱和度", 0, 100, 60)params_layout.addWidget(QLabel("饱和度:"), 2, 0)params_layout.addWidget(self.saturation_slider, 2, 1)# 锐度控制self.sharpness_slider = self.create_slider("锐度", 0, 100, 50)params_layout.addWidget(QLabel("锐度:"), 3, 0)params_layout.addWidget(self.sharpness_slider, 3, 1)# 曝光控制self.exposure_slider = self.create_slider("曝光", -7, 7, 0)params_layout.addWidget(QLabel("曝光:"), 4, 0)params_layout.addWidget(self.exposure_slider, 4, 1)# 分辨率选择self.resolution_combo = QComboBox()self.resolution_combo.addItems(["640x480", "1280x720", "1920x1080"])params_layout.addWidget(QLabel("分辨率:"), 0, 2)params_layout.addWidget(self.resolution_combo, 0, 3)self.resolution_combo.currentIndexChanged.connect(self.change_resolution)# 白平衡预设self.wb_preset_combo = QComboBox()self.wb_preset_combo.addItems(["自动", "日光", "阴天", "钨丝灯", "荧光灯"])params_layout.addWidget(QLabel("白平衡:"), 1, 2)params_layout.addWidget(self.wb_preset_combo, 1, 3)# 滤镜效果self.filter_combo = QComboBox()self.filter_combo.addItems(["无", "灰度", "暖色", "冷色", "复古"])params_layout.addWidget(QLabel("滤镜:"), 2, 2)params_layout.addWidget(self.filter_combo, 2, 3)self.params_group.setLayout(params_layout)self.control_layout.addWidget(self.params_group)# 初始不可用,相机启动后启用self.params_group.setEnabled(False)def create_slider(self, name, min_val, max_val, default):"""创建带标签的滑块控件"""slider = QSlider(Qt.Horizontal)slider.setMinimum(min_val)slider.setMaximum(max_val)slider.setValue(default)slider.setToolTip(f"{name}调节")slider.valueChanged.connect(self.adjust_camera_params)return sliderdef start_camera(self):"""启动摄像头"""# 尝试打开摄像头self.camera = cv2.VideoCapture(0)if not self.camera.isOpened():QMessageBox.critical(self, "错误", "无法打开摄像头")return# 设置初始分辨率res = self.resolution_combo.currentText()width, height = map(int, res.split('x'))self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, width)self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, height)# 设置初始参数self.adjust_camera_params()# 设置自动曝光self.camera.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)# 启动定时器读取帧self.timer.timeout.connect(self.update_frame)self.timer.start(30)  # ≈33 FPS# 更新界面状态self.is_camera_active = Trueself.status_label.setText("状态: 运行中")self.start_btn.setEnabled(False)self.pause_btn.setEnabled(True)self.capture_btn.setEnabled(True)self.params_group.setEnabled(True)def pause_camera(self):"""暂停摄像头"""if self.is_camera_active:self.timer.stop()self.is_camera_active = Falseself.status_label.setText("状态: 已暂停")self.pause_btn.setText("继续")self.params_group.setEnabled(False)else:self.timer.start(30)self.is_camera_active = Trueself.status_label.setText("状态: 运行中")self.pause_btn.setText("暂停")self.params_group.setEnabled(True)def capture_frame(self):"""捕获当前帧并保存为文件"""if self.is_camera_active:_, frame = self.camera.read()if frame is not None:# 应用当前滤镜frame = self.apply_filter(frame)# 保存为文件filename = f"capture_{QDateTime.currentDateTime().toString('yyyyMMdd_hhmmss')}.png"cv2.imwrite(filename, frame)QMessageBox.information(self, "拍照成功", f"已保存为 {filename}")def change_resolution(self):"""改变分辨率"""if self.is_camera_active and self.camera is not None:res = self.resolution_combo.currentText()width, height = map(int, res.split('x'))# 停止定时器self.timer.stop()# 设置分辨率self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, width)self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, height)# 重启定时器self.timer.start(30)def adjust_camera_params(self):"""实时调整相机参数"""if self.is_camera_active and self.camera is not None:# 获取参数值brightness = self.brightness_slider.value()contrast = self.contrast_slider.value() / 50.0  # 0-2范围saturation = self.saturation_slider.value() / 50.0sharpness = self.sharpness_slider.value()exposure = self.exposure_slider.value()# 设置相机属性self.camera.set(cv2.CAP_PROP_BRIGHTNESS, brightness)self.camera.set(cv2.CAP_PROP_CONTRAST, contrast)self.camera.set(cv2.CAP_PROP_SATURATION, saturation)self.camera.set(cv2.CAP_PROP_SHARPNESS, sharpness)self.camera.set(cv2.CAP_PROP_EXPOSURE, exposure)def apply_filter(self, frame):"""应用选择的滤镜效果"""filter_type = self.filter_combo.currentIndex()if filter_type == 1:  # 灰度return cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)elif filter_type == 2:  # 暖色# 增加红色通道,减少蓝色通道frame[:, :, 2] = np.clip(frame[:, :, 2] * 1.2, 0, 255)frame[:, :, 0] = np.clip(frame[:, :, 0] * 0.8, 0, 255)return frameelif filter_type == 3:  # 冷色# 增加蓝色通道,减少红色通道frame[:, :, 0] = np.clip(frame[:, :, 0] * 1.2, 0, 255)frame[:, :, 2] = np.clip(frame[:, :, 2] * 0.8, 0, 255)return frameelif filter_type == 4:  # 复古# 添加棕褐色调frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)frame = np.array(frame, dtype=np.float32) * np.array([1.0, 0.7, 0.4], dtype=np.float32)frame = np.clip(frame, 0, 255)return cv2.cvtColor(frame.astype(np.uint8), cv2.COLOR_RGB2BGR)return framedef update_frame(self):"""更新摄像头帧显示"""if self.is_camera_active and self.camera is not None:ret, frame = self.camera.read()if ret:# 应用当前滤镜frame = self.apply_filter(frame)# 应用白平衡预设 (此处简化为颜色调整)wb_preset = self.wb_preset_combo.currentIndex()if wb_preset > 0:# 简化的白平衡调整if wb_preset == 1:  # 日光frame[:, :, 2] = np.clip(frame[:, :, 2] * 1.1, 0, 255)elif wb_preset == 2:  # 阴天frame[:, :, 0] = np.clip(frame[:, :, 0] * 1.2, 0, 255)elif wb_preset == 3:  # 钨丝灯frame[:, :, 2] = np.clip(frame[:, :, 2] * 1.3, 0, 255)elif wb_preset == 4:  # 荧光灯frame[:, :, 1] = np.clip(frame[:, :, 1] * 1.2, 0, 255)# 转换为QImage并显示if len(frame.shape) == 2:  # 灰度图像q_img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_Grayscale8)else:  # 彩色图像frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)q_img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)self.video_label.setPixmap(QPixmap.fromImage(q_img))def close_app(self):"""安全关闭应用"""if self.camera is not None:self.camera.release()self.close()if __name__ == "__main__":app = QApplication(sys.argv)window = CameraController()window.show()sys.exit(app.exec_())

http://www.dtcms.com/a/325568.html

相关文章:

  • MySQL 8.4.5 中分区相关变量的查看
  • kubeadm搭建生产环境的双master节点k8s高可用集群
  • ubuntu20.04交叉编译vlc3.0.21 x64 windows版本
  • C++ 限制类对象数量的技巧与实践
  • 案例实战,一文吃透 Web Components
  • Docker中ES安装分词器
  • CW32L011 GTIM通用定时器配置
  • 打破内网枷锁!TRAE SOLO + cpolar 让AI开发告别“孤岛困境”
  • ctc 解码原理
  • 正则表达式:文本模式的数学语言与编程工具
  • Selenium经典面试题 - 多窗口切换解决方案
  • redis笔记(二)
  • 排错000
  • 《基于Pytorch实现的声音分类 :网页解读》
  • 基于数据结构用java实现二叉树的排序器
  • Godot ------ 平滑拖动02
  • 使用Springboot实现简单的ELK日志搜索系统
  • 游戏引擎(Unreal Engine、Unity、Godot等)大对比:选择最适合你的工具
  • Godot ------ 平滑拖动01
  • OpenAI COO谈ChatGPT5的技术突破:编程、医疗、自动推理
  • 【LeetCode 热题 100】(七)链表
  • window显示驱动开发—创建多平面覆盖资源
  • 适合物流/应急/工业的对讲机,AORO M6 Pro构建高效指挥调度方案
  • 运动规划实战案例 | 基于多源流场(Flow Field)的路径规划(附ROS C++/Python实现)
  • 直接编辑pdf文件教程
  • 作用域与作用域链深度解析
  • 复杂提示词配置文件
  • wpf问题记录
  • 重学React(五):脱围机制一
  • 关于JavaScript 性能优化的实战指南