用户数据采集实验软件
本软件用于采集用户实验过程中的视频图像。
点击查看代码
# 用于录制实验视频软件, 摄像头编号为1
import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QLineEdit, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QPushButton, QFileDialog, QLabel, QFrame, QMessageBox)
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QImage, QPixmap
import os
class CameraApp(QMainWindow):
def __init__(self):
super().__init__()
self.camera = None
self.is_camera_active = False
self.timer = QTimer()
self.recording = False
self.video_writer = None
self.save_path = None
self.init_ui()
self.connect_signals()
def init_ui(self):
self.setWindowTitle("摄像头控制界面")
self.setGeometry(600, 200, 800, 600)
# 创建中央窗口部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QHBoxLayout(central_widget)
# 左侧控制面板
control_frame = QFrame()
control_frame.setFrameShape(QFrame.StyledPanel)
control_frame.setFixedWidth(300)
control_layout = QVBoxLayout(control_frame)
# 状态标签
self.status_label = QLabel('请选择保存位置并开始录制')
control_layout.addWidget(self.status_label)
# 选择保存位置按钮
self.select_button = QPushButton('选择保存位置')
self.subject_id_label = QLabel('填写被试编号: ')
self.subject_id = QLineEdit()
self.subject_id.setPlaceholderText("如sub01")
# self.subject_id.textChanged.connect(self.validate_filename)
# control_layout.addRow("被试id:", self.subject_id)
# 创建按钮
self.open_btn = QPushButton("打开摄像头")
self.start_btn = QPushButton("开始录制") # 点击之后变成结束录制
self.pause_btn = QPushButton("暂停")
self.stop_btn = QPushButton("关闭摄像头")
# 设置按钮样式 # 16
button_style = """
QPushButton {
background-color: #4CAF50;
border: none;
color: white;
padding: 10px;
text-align: center;
text-decoration: none;
font-size: 20px;
margin: 4px 2px;
border-radius: 8px;
}
QPushButton:hover {
background-color: #45a049;
}
QPushButton:disabled {
background-color: #cccccc;
}
"""
self.select_button.setStyleSheet(button_style)
self.select_button.clicked.connect(self.select_save_location)
control_layout.addWidget(self.select_button)
control_layout.addWidget(self.subject_id_label) #被试id放在文件夹保存按钮下面
control_layout.addWidget(self.subject_id)
self.open_btn.setStyleSheet(button_style)
self.start_btn.setStyleSheet(button_style)
self.pause_btn.setStyleSheet(button_style)
self.stop_btn.setStyleSheet(button_style)
self.start_btn.setEnabled(False) # 初始不可用
# 将按钮添加到控制布局
control_layout.addWidget(self.open_btn)
control_layout.addWidget(self.start_btn)
control_layout.addWidget(self.pause_btn)
control_layout.addWidget(self.stop_btn)
control_layout.addStretch() # 添加弹性空间
# 右侧显示面板
display_frame = QFrame()
display_frame.setFrameShape(QFrame.StyledPanel)
display_layout = QVBoxLayout(display_frame)
# 创建显示图像的标签
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignCenter)
self.image_label.setMinimumSize(640, 480)
self.image_label.setText("摄像头未启动")
self.image_label.setStyleSheet("border: 1px solid black; background-color: #f0f0f0;")
display_layout.addWidget(self.image_label)
# 将左右面板添加到主布局
main_layout.addWidget(control_frame)
main_layout.addWidget(display_frame)
# 更新按钮状态
self.update_button_states()
def select_save_location(self):
# 弹出文件夹选择对话框
folder_path = QFileDialog.getExistingDirectory(
self,
"选择视频保存文件夹",
os.path.expanduser("~"), # 默认从用户主目录开始
QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks
)
if folder_path:
self.save_path = folder_path
self.status_label.setText(f'保存位置: {folder_path}')
# self.start_btn.setEnabled(True)
# 初始化摄像头
# self.init_camera()
def connect_signals(self):
# 连接按钮信号
self.open_btn.clicked.connect(self.open_camera)
self.start_btn.clicked.connect(self.toggle_recording) #开始录制
self.pause_btn.clicked.connect(self.pause_camera)
self.stop_btn.clicked.connect(self.stop_camera)
# 连接定时器信号
self.timer.timeout.connect(self.update_frame)
def open_camera(self):
#打开之后,右边就开始显示了
self.camera = cv2.VideoCapture(1) #0 罗技摄像头
if not self.camera.isOpened():
self.image_label.setText("无法访问摄像头")
return
self.is_camera_active = True
self.update_button_states()
# 右边显示摄像头正在打开...
self.image_label.setText("摄像头正在打开...")
# 启动定时器,每30毫秒更新一帧
self.timer.start(30)
def update_button_states(self):
# 根据摄像头状态更新按钮可用状态
if not self.is_camera_active:
self.open_btn.setEnabled(True)
self.start_btn.setEnabled(False) # True
self.pause_btn.setEnabled(False)
self.stop_btn.setEnabled(False)
else:
self.open_btn.setEnabled(False) #打开摄像头设置为灰
self.start_btn.setEnabled(True) #录制按钮
self.pause_btn.setEnabled(True) # 暂停那妞
self.stop_btn.setEnabled(True) #结束按钮
def toggle_recording(self):
if not self.recording:
# 开始录制
self.start_recording()
else:
# 停止录制
self.stop_recording()
def start_recording(self):
# 设置保存数据的文件名
if not self.save_path:
QMessageBox.warning(self, "警告", "请先选择保存位置")
return
# 生成文件名(使用时间戳)
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
if self.subject_id.text():
# print('subject id: ', self.subject_id.text())
filename = f"{self.subject_id.text()}_video_{timestamp}.avi"
else:
filename = f"video_{timestamp}.avi"
file_path = os.path.join(self.save_path, filename)
# 设置视频编码器和参数
frame_width = int(self.camera.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 20.0
# 创建视频写入器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.video_writer = cv2.VideoWriter(file_path, fourcc, fps, (frame_width, frame_height))
if not self.video_writer.isOpened():
QMessageBox.critical(self, "错误", "无法创建视频文件")
return
self.recording = True
# return True
self.start_btn.setText('停止录制')
self.status_label.setText(f'正在录制: {filename}')
self.status_label.setStyleSheet("color: red")#font-size: 16px;
def stop_recording(self):
self.recording = False
self.start_btn.setText('开始录制')
self.status_label.setText(f'录制已停止,视频保存在: {self.save_path}')
self.status_label.setStyleSheet("color: black")
if self.video_writer:
self.video_writer.release()
self.video_writer = None
def start_camera(self):
# 初始化摄像头
self.camera = cv2.VideoCapture(1) #0 罗技摄像头
if not self.camera.isOpened():
self.image_label.setText("无法访问摄像头")
return
self.is_camera_active = True
self.update_button_states()
# 启动定时器,每30毫秒更新一帧
self.timer.start(30)
# 设置录制视频名称
# self.start_recording()
def pause_camera(self):
if self.is_camera_active:
if self.timer.isActive():
self.timer.stop()
self.pause_btn.setText("继续")
else:
self.timer.start(30)
self.pause_btn.setText("暂停")
def stop_camera(self):
self.is_camera_active = False
self.timer.stop()
if self.camera:
self.camera.release()
self.camera = None
# self.record_button.setText('开始录制')
if self.recording:
self.recording = False
self.status_label.setText(f'录制已停止,视频保存在: {self.save_path}')
#停止录制变回开始录制
self.start_btn.setText("开始录制")
if self.video_writer:
self.video_writer.release()
self.video_writer = None
self.image_label.setText("摄像头已停止")
# 保存数据
self.update_button_states()
self.pause_btn.setText("暂停")
def update_frame(self):
if self.camera and self.camera.isOpened():
ret, frame = self.camera.read()
if ret:
# 将OpenCV的BGR格式转换为RGB
frame = cv2.flip(frame, 1)
# 如果正在录制,保存帧
if self.recording and self.video_writer:
self.video_writer.write(frame)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 将图像转换为Qt格式
h, w, ch = frame_rgb.shape
bytes_per_line = ch * w
qt_image = QImage(frame_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)
# 缩放图像以适应标签大小
scaled_pixmap = QPixmap.fromImage(qt_image).scaled(
self.image_label.width(),
self.image_label.height(),
Qt.KeepAspectRatio
)
# 显示图像
self.image_label.setPixmap(scaled_pixmap)
else:
self.image_label.setText("无法读取帧")
def closeEvent(self, event):
# 关闭应用程序时释放摄像头资源
self.stop_camera()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = CameraApp()
window.show()
sys.exit(app.exec_())
每天快乐敲代码,快乐生活

浙公网安备 33010602011771号