暑假开始了解python了,记录一下最近实现的小相机,只有功能,没有qss😀,还参考了很多博主😂
貌似还有一个小问题,就是转成灰度图后转不回去了,我比较懒就不研究了🎈
import time
import cv2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtGui
from PyQt5.QtWidgets import *
from qtpy import uic
class Win(QWidget):
msg = pyqtSignal(bool)
def __init__(self):
super(Win, self).__init__()
self.flag = True
self.photoname = 1
self.ui = uic.loadUi("ui/untitled.ui") # 导入ui文件
self.ui.setParent(self) # 将ui文件设置父窗口,将它显示出来
self.timeThread = Time() # 创建一个自己写的Time类
self.timeThread.start()
self.resize(820, 600) # 改变窗口大小
self.timeThread.update.connect(self.update_time) # 给信号设置槽函数
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 打开内置摄像头,windows特有的,加上CAP_DSHOW,不加关闭程序摄像头不会关闭
self.cap.set(3, 640) # 设置相机窗口
self.cap.set(4, 480)
self.video = Video(self.cap)
self._timer = QTimer(self) # 创建定时器对象
self._timer.timeout.connect(self.play) # 连接timeout信号到槽函数
self._timer.start(30) # 多少时间间隔内执行一次
self.ui.jietu.clicked.connect(self.cliek_jietu) # 绑定槽函数
self.ui.luxiang.clicked.connect(self.click_luxiang)
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 设置录像格式
self.vm = cv2.VideoWriter('E:\opencvLZvideo\out007.avi', fourcc, 30, (640, 480))
self.ui.fbl.currentIndexChanged.connect(self.click_fbl)
self.ui.td.currentIndexChanged.connect(self.click_td)
self.msg.connect(self.video.change)
def click_td(self):
self.ys = self.ui.fbl.currentText() # 如果组合框改变内容
if self.ys == '原':
self.msg.emit(True)
else:
self.msg.emit(False)
def click_fbl(self):
self.hz = self.ui.fbl.currentText() # 改变内容修改分辨率
if self.hz == '1280*760':
self.cap.set(3, 1280)
self.cap.set(4, 760)
elif self.hz == '640*480':
self.cap.set(3, 640)
self.cap.set(4, 480)
else:
self.cap.set(3, 640)
self.cap.set(4, 360)
def click_luxiang(self):
while self.cap.isOpened(): # 当摄像头是打开的时候
frame1 = cv2.cvtColor(self.video.currentFrame, cv2.COLOR_BGR2RGB) # 获取当前帧并转为RGB
self.vm.write(frame1) # 写入vm
if cv2.waitKey(30) == ord('q'): # 退出按钮
break
def closeEvent(self, event: QtGui.QCloseEvent) -> None: # 设置关闭事件
print(event)
self.cap.release()
self.vm.release()
print("closing...")
def cliek_jietu(self):
filename = str(self.photoname) + '.png' # 设置图片名字
Frame_ = cv2.cvtColor(self.video.currentFrame, cv2.COLOR_BGR2RGB)
cv2.imwrite('sava/' + filename, Frame_) # 写入当前路劲下的sava文件
print(filename + '保存成功')
self.photoname = self.photoname + 1
def play(self): # 定时器的槽函数
self.video.captureNextFrame() # 读取每一帧
frame = self.video.convertFrame() # 获取当前帧
if frame: # 获取到则放到label控件上展示
self.ui.label.setPixmap(frame)
def update_time(self, data):
self.ui.time.setText(data)
class Time(QThread): # 继承了QT特有的多线程
update = pyqtSignal(str) # 设置信号
def run(self):
while True:
date = QDateTime.currentDateTime() # 创建对象
currrntTime = date.toString("yyyy-MM-dd hh:mm:ss") # 设置格式
self.update.emit(str(currrntTime)) # 发信号
time.sleep(1)
class Video(): # 摄像机类
def __init__(self, capture):
self.capture = capture
self.currentFrame = None
self.flag = True
def change(self, msg):
if msg == True:
self.flag = True
else:
self.flag = False
def captureNextFrame(self):
ret, readFrame = self.capture.read()
if ret == True:
if self.flag == False: # 读为灰度图
self.currentFrame = cv2.cvtColor(readFrame, cv2.COLOR_BGR2GRAY)
else: # 正常
self.currentFrame = cv2.cvtColor(readFrame, cv2.COLOR_BGR2RGB)
# return self.convertFrame()
def convertFrame(self):
try: # 不建议写异常
# height, width, _ = self.currentFrame.shape
# img = QImage(self.currentFrame, width, height, QImage.Format_RGB888)
img = self.cvToQImage(self.currentFrame) # 转为QImage
img = QPixmap.fromImage(img) # 转为QPixmap
return img
except TypeError:
print(22222)
def cvToQImage(self, data): # 找的一个博主的转的函数
channels = 1 # 设置通道默认为1
if len(data.shape) == 3: # 3维则将通道改为3
channels = 3
if channels == 3:
img = QImage(data.data, data.shape[1], data.shape[0], data.strides[0], QImage.Format_RGB888)
return img
elif channels == 1:
img = QImage(data, data.shape[1], data.shape[0], data.strides[0], QImage.Format_Indexed8)
return img
else:
qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % data.shape[2])
return QImage()
if __name__ == '__main__':
app = QApplication([])
win = Win()
win.show()
app.exec_()
UI长这个样子
UI文件长这样
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>821</width>
<height>621</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QLineEdit" name="time">
<property name="geometry">
<rect>
<x>0</x>
<y>20</y>
<width>191</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">#time{background-color:rgba(0,0,0,0);
border-width:0;border-style:outset}</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>30</x>
<y>70</y>
<width>791</width>
<height>451</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>540</y>
<width>801</width>
<height>61</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="jietu">
<property name="text">
<string>截图</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="luxiang">
<property name="text">
<string>录像</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="fbl">
<item>
<property name="text">
<string>640*480</string>
</property>
</item>
<item>
<property name="text">
<string>1280*760</string>
</property>
</item>
<item>
<property name="text">
<string>640*360</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="td">
<item>
<property name="text">
<string>原</string>
</property>
</item>
<item>
<property name="text">
<string>灰</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>