1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 使用PYQT5打开海康威视工业相机并获取图像进行显示

使用PYQT5打开海康威视工业相机并获取图像进行显示

时间:2023-06-18 14:41:43

相关推荐

使用PYQT5打开海康威视工业相机并获取图像进行显示

目录

0 前言

1 UI界面的布局

2 UI界面布局对应的代码

3 打开海康威视工业相机等功能的完整代码

4 一些代码函数和注意事项

5 界面操作步骤和最终效果图

0 前言

因为这段时间我主要在学习图像特征提取和机器学习,但有一些实验结果还没有出来,不能进行下去,同时也遇到了点瓶颈,不知该从哪方面继续进行下去或者如何做到创新;就简单地学习了PYQT5上位机界面可视化的内容并简单实现了一些功能(感觉也挺好玩的),后面也是需要设计一个可视化界面。就通过这时间学习了PYQT5知识。刚开始问同学这部分该如何学习,他们跟我说从网上找一些别人的demo,然后进行更改,一两天就可以学会了;我一开始还不太相信,就尝试了一下,结果发现真不难,通过学习简单实现了用PYQT5打开了电脑摄像头等功能,就有了我上两篇博客,具体也可以参考一下。

由于我们项目使用的是海康威视工业相机,在学习PYQT5的时候我只打开了电脑自带的免驱摄像机。使用PYQT5打开海康威视相机的教程网上比较少,而且一些教程我尝试后也打不开相机,在这里就没有之前那么顺利了,花了两三天摸索。 通过几天的努力,终于实现了使用PYQT5打开海康威视工业相机。

1 UI界面的布局

下图是简单设计的一个UI控制的输出可视化界面。

其中,<摄像头><图片显示>使用的是左边功能的label类、<获取相机信息><打开摄像头><拍照><关闭摄像头>使用的是左边功能的Push Button类。这些输出显示和按键功能中的字体大小和边框都可以对应根据右边的属性进行更改配置。

2 UI界面布局对应的代码

(1)项目的目录如下,open_camera.ui是上面保存的的界面布局。

其中,MvImport文件是在安装海康威视时候开放给我们进行二次开发的,python中支持的接口以及参数可以从相应文件中查取,可以在你安装路径中找到(...\MVS\Development\Samples\python\MvImport),然后将MvImport文件复制到你的代码中。海康威视相机官方软件下载链接海康机器人-机器视觉-下载中心。

(2)UI界面布局的对应代码,则是open_camera.py文件,可以右击open_camera.ui文件,找到Exernal Tools。然后点击PyUIC,就可以自动生成open_camera.py文件,具体操作和生成的代码如下:

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'open_camera.ui'## Created by: PyQt5 UI code generator 5.15.4## WARNING: Any manual changes made to this file will be lost when pyuic5 is# run again. Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(970, 858)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.label = QtWidgets.QLabel(self.centralwidget)self.label.setGeometry(QtCore.QRect(30, 10, 571, 391))font = QtGui.QFont()font.setPointSize(46)font.setBold(True)font.setItalic(True)font.setWeight(75)self.label.setFont(font)self.label.setFrameShape(QtWidgets.QFrame.Box)self.label.setFrameShadow(QtWidgets.QFrame.Raised)self.label.setLineWidth(3)self.label.setAlignment(QtCore.Qt.AlignCenter)self.label.setObjectName("label")self.label_2 = QtWidgets.QLabel(self.centralwidget)self.label_2.setGeometry(QtCore.QRect(30, 410, 571, 391))font = QtGui.QFont()font.setPointSize(46)font.setBold(True)font.setItalic(True)font.setWeight(75)self.label_2.setFont(font)self.label_2.setFrameShape(QtWidgets.QFrame.Box)self.label_2.setFrameShadow(QtWidgets.QFrame.Raised)self.label_2.setLineWidth(3)self.label_2.setAlignment(QtCore.Qt.AlignCenter)self.label_2.setObjectName("label_2")self.pushButton = QtWidgets.QPushButton(self.centralwidget)self.pushButton.setGeometry(QtCore.QRect(700, 110, 201, 81))font = QtGui.QFont()font.setPointSize(20)font.setBold(True)font.setWeight(75)self.pushButton.setFont(font)self.pushButton.setObjectName("pushButton")self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_2.setGeometry(QtCore.QRect(700, 240, 201, 81))font = QtGui.QFont()font.setPointSize(20)font.setBold(True)font.setWeight(75)self.pushButton_2.setFont(font)self.pushButton_2.setObjectName("pushButton_2")self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_3.setGeometry(QtCore.QRect(700, 370, 201, 81))font = QtGui.QFont()font.setPointSize(20)font.setBold(True)font.setWeight(75)self.pushButton_3.setFont(font)self.pushButton_3.setObjectName("pushButton_3")self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_4.setGeometry(QtCore.QRect(700, 500, 201, 81))font = QtGui.QFont()font.setPointSize(20)font.setBold(True)font.setWeight(75)self.pushButton_4.setFont(font)self.pushButton_4.setObjectName("pushButton_4")MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 970, 22))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.label.setText(_translate("MainWindow", "摄像头"))self.label_2.setText(_translate("MainWindow", "图片显示"))self.pushButton.setText(_translate("MainWindow", "获取相机信息"))self.pushButton_2.setText(_translate("MainWindow", "打开摄像机"))self.pushButton_3.setText(_translate("MainWindow", "拍照"))self.pushButton_4.setText(_translate("MainWindow", "关闭摄像机"))

3 打开海康威视工业相机等功能的完整代码

下面是打开海康威视摄像头和进行拍照的完整代码open_camera_main.py;这里面的一些打印输出的代码被我给注释掉了,换成系统的提示、警告代码。

import cv2from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import pyqtSignalfrom PyQt5.QtGui import *import numpy as npimport matplotlib.pyplot as plt# from MvImport.MvCameraControl_header import MV_CC_DEVICE_INFO_LISTfrom open_camera import Ui_MainWindow # 导入创建的GUI类import sysimport threadingimport msvcrtfrom ctypes import *from PyQt5.Qt import *from PIL import Image,ImageTksys.path.append("../MvImport")from MvCameraControl_class import *import timeimport osclass mywindow(QtWidgets.QMainWindow, Ui_MainWindow):sendAddDeviceName = pyqtSignal() # 定义一个添加设备列表的信号。deviceList = MV_CC_DEVICE_INFO_LIST()tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICEg_bExit = Falsecamera_information = False #获取相机标志opencamera_flay = False #打开相机标志# ch:创建相机实例 | en:Creat Camera Objectcam = MvCamera()def __init__(self):super(mywindow, self).__init__()self.setupUi(self)# self.connect_and_emit_sendAddDeviceName()self.init()self.label.setScaledContents(True) # 图片自适应self.label_2.setScaledContents(True) # 图片自适应def init(self):#获取相机相信self.pushButton.clicked.connect(self.get_camera_information)# 打开摄像头self.pushButton_2.clicked.connect(self.openCamera)# 拍照self.pushButton_3.clicked.connect(self.taking_pictures)# 关闭摄像头self.pushButton_4.clicked.connect(self.closeCamera)# Connect the sendAddDeviceName signal to a slot.# self.sendAddDeviceName.connect(self.camera_information)# Emit the signal.# self.sendAddDeviceName.emit()# 获得所有相机的列表存入cmbSelectDevice中def get_camera_information(self):'''选择所有能用的相机到列表中,gige相机需要配合 sdk 得到。'''# 得到相机列表# tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE# ch:枚举设备 | en:Enum deviceret = MvCamera.MV_CC_EnumDevices(self.tlayerType, self.deviceList)if ret != 0:print("enum devices fail! ret[0x%x]" % ret)# QMessageBox.critical(self, '错误', '读取设备驱动失败!')# sys.exit()if self.deviceList.nDeviceNum == 0:QMessageBox.critical(self, "错误", "没有发现设备 ! ")# print("find no device!")# sys.exit()else:QMessageBox.information(self, "提示", "发现了 %d 个设备 !" % self.deviceList.nDeviceNum)# print("Find %d devices!" % self.deviceList.nDeviceNum)if self.deviceList.nDeviceNum == 0:return Nonefor i in range(0, self.deviceList.nDeviceNum):mvcc_dev_info = cast(self.deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contentsif mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:print("\ngige device: [%d]" % i)strModeName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:strModeName = strModeName + chr(per)print("device model name: %s" % strModeName)self.camera_information = True# 打开摄像头。def openCamera(self, camid=0):if self.camera_information == True:self.g_bExit = False# ch:选择设备并创建句柄 | en:Select device and create handlestDeviceList = cast(self.deviceList.pDeviceInfo[int(0)], POINTER(MV_CC_DEVICE_INFO)).contentsret = self.cam.MV_CC_CreateHandle(stDeviceList)if ret != 0:# print("create handle fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "创建句柄失败 ! ret[0x%x]" % ret)# sys.exit()# ch:打开设备 | en:Open deviceret = self.cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)if ret != 0:# print("open device fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "打开设备失败 ! ret[0x%x]" % ret)# sys.exit()# ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)if stDeviceList.nTLayerType == MV_GIGE_DEVICE:nPacketSize = self.cam.MV_CC_GetOptimalPacketSize()if int(nPacketSize) > 0:ret = self.cam.MV_CC_SetIntValue("GevSCPSPacketSize", nPacketSize)if ret != 0:# print("Warning: Set Packet Size fail! ret[0x%x]" % ret)QMessageBox.warning(self, "警告", "报文大小设置失败 ! ret[0x%x]" % ret)else:# print("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)QMessageBox.warning(self, "警告", "报文大小获取失败 ! ret[0x%x]" % nPacketSize)# ch:设置触发模式为off | en:Set trigger mode as offret = self.cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)if ret != 0:# print("set trigger mode fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "设置触发模式失败 ! ret[0x%x]" % ret)# sys.exit()# ch:获取数据包大小 | en:Get payload sizestParam = MVCC_INTVALUE()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))ret = self.cam.MV_CC_GetIntValue("PayloadSize", stParam)if ret != 0:# print("get payload size fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "获取有效负载大小失败 ! ret[0x%x]" % ret)# sys.exit()nPayloadSize = stParam.nCurValue# ch:开始取流 | en:Start grab imageret = self.cam.MV_CC_StartGrabbing()if ret != 0:# print("start grabbing fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "开始抓取图像失败 ! ret[0x%x]" % ret)# sys.exit()data_buf = (c_ubyte * nPayloadSize)()self.opencamera_flay = Truetry:hThreadHandle = threading.Thread(target=self.work_thread, args=(self.cam, data_buf, nPayloadSize))hThreadHandle.start()except:# print("error: unable to start thread")QMessageBox.critical(self, "错误", "无法启动线程 ! ")else:QMessageBox.critical(self, '错误', '获取相机信息失败!')return None# 关闭相机def closeCamera(self):if self.opencamera_flay == True:self.g_bExit = True# ch:停止取流 | en:Stop grab imageret = self.cam.MV_CC_StopGrabbing()if ret != 0:# print("stop grabbing fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "停止抓取图像失败 ! ret[0x%x]" % ret)# sys.exit()# ch:关闭设备 | Close deviceret = self.cam.MV_CC_CloseDevice()if ret != 0:# print("close deivce fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "停止设备失败 ! ret[0x%x]" % ret)# ch:销毁句柄 | Destroy handleret = self.cam.MV_CC_DestroyHandle()if ret != 0:# print("destroy handle fail! ret[0x%x]" % ret)QMessageBox.critical(self, "错误", "销毁处理失败 ! ret[0x%x]" % ret)self.label.clear() # 清除label组件上的图片self.label_2.clear() # 清除label组件上的图片self.label.setText("摄像头")self.label_2.setText("显示图片")self.camera_information = Falseself.opencamera_flay = Falseelse:QMessageBox.critical(self, '错误', '未打开摄像机!')return Nonedef work_thread(self, cam=0, pData=0, nDataSize=0):stFrameInfo = MV_FRAME_OUT_INFO_EX()memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))while True:ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)if ret == 0:image = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)# print(image.shape)image = image.reshape((2000, 2688, 1)) # 根据自己分辨率进行转化# image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常image = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2BGR) # Bayer格式(raw data)向RGB或BGR颜色空间的转换# print(image.shape)# pyrD1 = cv2.pyrDown(image) # 向下取样# pyrD2 = cv2.pyrDown(pyrD1) # 向下取样image_height, image_width, image_depth = image.shape # 读取图像高宽深度self.image_show = QImage(image.data, image_width, image_height, image_width * image_depth,QImage.Format_RGB888)self.label.setPixmap(QPixmap.fromImage(self.image_show))if self.g_bExit == True:del pDatabreak#拍照def taking_pictures(self):if self.opencamera_flay == True:FName = fr"images/cap{time.strftime('%Y%m%d%H%M%S', time.localtime())}"print(FName)self.label_2.setPixmap(QtGui.QPixmap.fromImage(self.image_show))# self.showImage.save(FName + ".jpg", "JPG", 100)self.image_show.save('./1.bmp')else:QMessageBox.critical(self, '错误', '摄像机未打开!')return None#重写关闭函数def closeEvent(self, event):reply = QMessageBox.question(self,'提示',"确认退出吗?",QMessageBox.Yes | QMessageBox.No,QMessageBox.No)if reply == QMessageBox.Yes:event.accept()#用过sys.exit(0)和sys.exit(app.exec_()),但没起效果os._exit(0)else:event.ignore()if __name__ == '__main__':from PyQt5 import QtCoreQtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 自适应分辨率app = QtWidgets.QApplication(sys.argv)window = mywindow()window.show()sys.exit(app.exec_())

4 一些代码函数和注意事项

(1)在MvImport文件中,最主要调用的是MvCameraControl_class.py,该文件中包含从C语言底层接口封装过来的所有 python 可调用接口,在调用时是需要导入该文件作为调用包;需要注意的是sys.path.append("../MvImport")使用的路径是相对路径,主要是用于from MvCameraControl_class import *这句包导入时使用,在此处可能会遇到一个问题,问题报错如下:

Traceback (most recent call last):File "D:/代码练习/PYQT5/PYQT5_demo_2/open_camera_main.py", line 17, in <module>from MvCameraControl_class import *File "D:\代码练习\PYQT5\PYQT5_demo_2\MvImport\MvCameraControl_class.py", line 15, in <module>MvCamCtrldll = WinDLL("MvCameraControl.dll")File "E:\anaconda\envs\pytorch\lib\ctypes\__init__.py", line 373, in __init__self._handle = _dlopen(self._name, mode)FileNotFoundError: Could not find module 'MvCameraControl.dll' (or one of its dependencies). Try using the full path with constructor syntax.

主要原因是在MvCameraControl_class.py文件中,使用MvCameraControl.dll文件时,相对路径失效导致,可以对MvCameraControl_class.py文件中导包部分进行如下修改即可;

MvCamCtrldll = WinDLL("C:\\Program Files (x86)\\Common Files\\MVS\\Runtime\\Win64_x64\\MvCameraControl.dll")

(2) 红色框中的第一步,需要根据你使用相机的分辨率进行更改,注意顺序不能搞错。

在红色框的第二步,我设置后只能显示灰度图片,具体我也不清楚什么原因,然后我将其改成红色框的第三步代码,就可以实现彩色图像显示。

(3) 假如打开海康威视相机后,没有点击关闭摄像机,直接关闭窗口,会出现程序还一直在运行,没有结束,具体我也不清楚是什么原因,可能是线程问题,如下所示:

然后我在程序中添加了以下代码( 重写关闭函数),则就可以解决以上情况,具体原因还没分析,后续可以深入了解一下。

def closeEvent(self, event):reply = QtWidgets.QMessageBox.question(self,'提示',"确认退出吗?",QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,QtWidgets.QMessageBox.No)if reply == QtWidgets.QMessageBox.Yes:event.accept()#用过sys.exit(0)和sys.exit(app.exec_()),但没起效果os._exit(0)else:event.ignore()

(4) 相机分辨率与PYQT5上位机显示界面图像显示自适应问题;一般由于工业相机的分辨率比较高,但我们设计的上位机的相机图片实时显示范围有限,所以会出现显示不全的结果。为了解决以上的问题,可在如下位置添加以下这两行代码,则可解决相机分辨高而图像显示不全的问题,即显示图像自适应。

self.label.setScaledContents(True) # 窗口显示图片自适应self.label_2.setScaledContents(True) # 窗口显示图片自适应

5 界面操作步骤和最终效果图

(1)操作步骤(这些操作逻辑可以根据自己的方式更改)

第一步:点击<获取相机信息>按钮,若弹出没有发现设备的弹窗,则获取相机信息失败,不能操作接下来步骤;

第二步:点击<打开摄像机>按钮,若出现一些弹窗提示或警告,则打开摄像机失败,不能进行拍照;

第三步:点击<拍照>按钮,只有执行以上两步并都成功了,才可以进行拍照采集图像,不然会出现未打开摄像机的弹窗;

第四步:操作完成后,就可以关闭摄像机。

(2)效果图:

参考来源:

使用PYQT5打开电脑摄像头并进行拍照_暂未成功人士!的博客-CSDN博客

pyQT5 学习使用 笔记 六 pyQt5+opencv 显示海康GIGE相机动态视频流_youandme520的博客-CSDN博客_pyqt 海康相机

python调用海康工业相机并用opencv显示(整体实现)_J&A~ing的博客-CSDN博客_python调用海康工业相机

python语言下使用pyqt中的QImage对海康工业相机获取到的图像进行显示_J&A~ing的博客-CSDN博客_python qimage

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。