|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
import cv2 as cv
|
|
|
|
|
|
|
|
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
|
|
|
from PyQt5.QtCore import *
|
|
|
|
|
from PyQt5.QtGui import *
|
|
|
|
|
from PyQt5.QtWidgets import QFileDialog, QMainWindow
|
|
|
|
|
|
|
|
|
|
from surface import (Ui_MainWindow)
|
|
|
|
|
os.chdir(sys.path[0])
|
|
|
|
|
|
|
|
|
|
class PyQtMainEntry(QMainWindow, Ui_MainWindow):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
|
|
super().__init__() # 调用父类的初始化函数
|
|
|
|
|
self.setupUi(self) # 设置用户界面
|
|
|
|
|
|
|
|
|
|
# 初始化摄像头,并尝试打开,默认尝试打开摄像头索引为0
|
|
|
|
|
self.camera = cv.VideoCapture(0)
|
|
|
|
|
self.is_camera_opened = False # 标记摄像头是否成功打开
|
|
|
|
|
|
|
|
|
|
# 创建一个定时器,并设置其触发间隔为10毫秒
|
|
|
|
|
self._timer = QtCore.QTimer(self)
|
|
|
|
|
self._timer.timeout.connect(self._queryFrame) # 定时器触发时调用_queryFrame函数
|
|
|
|
|
self._timer.setInterval(10) # 设置定时器触发间隔
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def btnOpenCamera_Clicked(self):
|
|
|
|
|
|
|
|
|
|
# 切换摄像头的打开状态
|
|
|
|
|
self.is_camera_opened = ~self.is_camera_opened
|
|
|
|
|
if self.is_camera_opened:
|
|
|
|
|
# 当摄像头打开时,更改按钮文本为关闭摄像头,并启动定时器
|
|
|
|
|
self.btnOpenCamera.setText("关闭摄像头")
|
|
|
|
|
self._timer.start()
|
|
|
|
|
else:
|
|
|
|
|
# 当摄像头关闭时,更改按钮文本为打开摄像头,并停止定时器
|
|
|
|
|
self.btnOpenCamera.setText("打开摄像头")
|
|
|
|
|
self._timer.stop()
|
|
|
|
|
|
|
|
|
|
def btnCapture_Clicked(self):
|
|
|
|
|
|
|
|
|
|
if not self.is_camera_opened:
|
|
|
|
|
# 如果相机未打开,则直接返回,不做任何操作
|
|
|
|
|
return
|
|
|
|
|
# 捕获图像
|
|
|
|
|
self.captured = self.frame
|
|
|
|
|
|
|
|
|
|
# 获取捕获图像的行数、列数和通道数
|
|
|
|
|
rows, cols, channels = self.captured.shape
|
|
|
|
|
# 计算每行字节数
|
|
|
|
|
bytesPerLine = channels * cols
|
|
|
|
|
|
|
|
|
|
# 使用捕获的图像数据创建QImage对象
|
|
|
|
|
QImg = QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)
|
|
|
|
|
# 将QImage对象转换为QPixmap,并按比例缩放以适应标签的大小,然后设置到标签上
|
|
|
|
|
self.labelCapture.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelCapture.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
def btnReadImage_Clicked(self):
|
|
|
|
|
|
|
|
|
|
# 使用QFileDialog获取选择的图像文件名
|
|
|
|
|
# ,_是占位符用来忽略返回值比如这里面会返回文件名和文件类型,使用占位符可以忽略文件类型
|
|
|
|
|
filename, _ = QFileDialog.getOpenFileName(self, '打开图片')
|
|
|
|
|
if filename:
|
|
|
|
|
# 通过文件名读取图像,并转换为RGB格式
|
|
|
|
|
self.captured = cv.imread(str(filename))
|
|
|
|
|
self.captured = cv.cvtColor(self.captured, cv.COLOR_BGR2RGB)
|
|
|
|
|
|
|
|
|
|
# 获取图像的尺寸信息,用于创建QImage
|
|
|
|
|
rows, cols, channels = self.captured.shape
|
|
|
|
|
bytesPerLine = channels * cols
|
|
|
|
|
|
|
|
|
|
# 将OpenCV图像转换为QImage格式
|
|
|
|
|
QImg = QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)
|
|
|
|
|
|
|
|
|
|
# 将QImage设置为标签的图片,并保持原始比例进行缩放
|
|
|
|
|
self.labelCapture.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelCapture.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
def btnGray_Clicked(self):
|
|
|
|
|
|
|
|
|
|
if not hasattr(self, "captured"):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.cpatured = cv.cvtColor(self.captured, cv.COLOR_RGB2GRAY)
|
|
|
|
|
|
|
|
|
|
rows, columns = self.cpatured.shape
|
|
|
|
|
bytesPerLine = columns
|
|
|
|
|
|
|
|
|
|
QImg = QImage(self.cpatured.data, columns, rows, bytesPerLine, QImage.Format_Indexed8)
|
|
|
|
|
self.labelResult.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelResult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
def btnThreshold_Clicked(self):
|
|
|
|
|
|
|
|
|
|
if not hasattr(self, "captured"):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_, self.cpatured = cv.threshold(
|
|
|
|
|
self.cpatured, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
|
|
|
|
|
|
|
|
|
|
rows, columns = self.cpatured.shape
|
|
|
|
|
bytesPerLine = columns
|
|
|
|
|
|
|
|
|
|
QImg = QImage(self.cpatured.data, columns, rows, bytesPerLine, QImage.Format_Indexed8)
|
|
|
|
|
self.labelResult.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelResult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot()
|
|
|
|
|
def _queryFrame(self):
|
|
|
|
|
"""
|
|
|
|
|
从相机读取一帧图像,并将其显示在标签上。
|
|
|
|
|
"""
|
|
|
|
|
# 从相机读取图像
|
|
|
|
|
ret, self.frame = self.camera.read()
|
|
|
|
|
|
|
|
|
|
# 获取图像的尺寸和每行字节数
|
|
|
|
|
img_rows, img_cols, channels = self.frame.shape
|
|
|
|
|
bytesPerLine = channels * img_cols
|
|
|
|
|
|
|
|
|
|
# 将图像从BGR转换为RGB格式
|
|
|
|
|
cv.cvtColor(self.frame, cv.COLOR_BGR2RGB, self.frame)
|
|
|
|
|
# 创建QImage对象
|
|
|
|
|
QImg = QImage(self.frame.data, img_cols, img_rows, bytesPerLine, QImage.Format_RGB888)
|
|
|
|
|
# 将QImage设置为标签的图片,并保持宽高比
|
|
|
|
|
self.labelCamera.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelCamera.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def btnDenoising_Clicked(self):
|
|
|
|
|
if not hasattr(self, "captured"):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.cpatured = cv.fastNlMeansDenoising(self.cpatured, None, 10, 7, 21)
|
|
|
|
|
|
|
|
|
|
rows, columns = self.cpatured.shape
|
|
|
|
|
bytesPerLine = columns
|
|
|
|
|
|
|
|
|
|
QImg = QImage(self.cpatured.data, columns, rows, bytesPerLine, QImage.Format_Indexed8)
|
|
|
|
|
self.labelResult.setPixmap(QPixmap.fromImage(QImg).scaled(
|
|
|
|
|
self.labelResult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def btnSaveImage_Clicked(self):
|
|
|
|
|
|
|
|
|
|
if not hasattr(self, "captured"): # 检查是否已捕获图像
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
filename, _ = QFileDialog.getSaveFileName(self, '保存图片') # 弹出保存文件对话框
|
|
|
|
|
if filename: # 如果用户选择了保存路径
|
|
|
|
|
cv.imwrite(str(filename), self.captured) # 将捕获的图像保存到选择的路径
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
app = QtWidgets.QApplication(sys.argv)
|
|
|
|
|
window = PyQtMainEntry()
|
|
|
|
|
window.show()
|
|
|
|
|
sys.exit(app.exec_())
|