opencv 读取 海康GIGE相机视频流
新项目中我们需要使用opencv读取海康威视的工业相机 MV-CA060-10GM 的视频流进行处理。那么首先我们要读取到相机的视频流,总所周知 opencv 读取视频流的办法就是使用 VideoCapture 函数 来读取。 但是经过多次测试,读取了文档和源代码 发现 opencv没有公版驱动可以和GIGE 协议的相机直接对接。那么怎么办呢?
然后我想到了海康威视提供的SDK 开发包。在sdk里面翻找了一下 终于发现一批python的例程,所以说大公司就是周到。那么我们来看一下如何把 海康的sdk连接到 opencv吧。
经过筛选我们选个了海康sdk python 例子中 的GrabImage.py 这个例子,来改造加入opencv 元素。
这个是 安装了海康威视最新的相机驱动之后都带的 sdk开发包中 就有 这个文件
下面是这个例子的源代码
# -- coding: utf-8 --
import sys
import threading
import msvcrt
from ctypes import *
sys.path.append("../MvImport")
from MvCameraControl_class import *
g_bExit = False
# 为线程定义一个函数
def work_thread(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:
print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
else:
print ("no data[0x%x]" % ret)
if g_bExit == True:
break
if __name__ == "__main__":
deviceList = MV_CC_DEVICE_INFO_LIST()
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
# ch:枚举设备 | en:Enum device
ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)
if ret != 0:
print ("enum devices fail! ret[0x%x]" % ret)
sys.exit()
if deviceList.nDeviceNum == 0:
print ("find no device!")
sys.exit()
print ("Find %d devices!" % deviceList.nDeviceNum)
for i in range(0, deviceList.nDeviceNum):
mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
if 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)
nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)
nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)
nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)
nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)
print ("current ip: %d.%d.%d.%d\n" % (nip1, nip2, nip3, nip4))
elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:
print ("\nu3v device: [%d]" % i)
strModeName = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:
if per == 0:
break
strModeName = strModeName + chr(per)
print ("device model name: %s" % strModeName)
strSerialNumber = ""
for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:
if per == 0:
break
strSerialNumber = strSerialNumber + chr(per)
print ("user serial number: %s" % strSerialNumber)
nConnectionNum = input("please input the number of the device to connect:")
if int(nConnectionNum) >= deviceList.nDeviceNum:
print ("intput error!")
sys.exit()
# ch:创建相机实例 | en:Creat Camera Object
cam = MvCamera()
# ch:选择设备并创建句柄 | en:Select device and create handle
stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contents
ret = cam.MV_CC_CreateHandle(stDeviceList)
if ret != 0:
print ("create handle fail! ret[0x%x]" % ret)
sys.exit()
# ch:打开设备 | en:Open device
ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
print ("open device fail! 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 = cam.MV_CC_GetOptimalPacketSize()
if int(nPacketSize) > 0:
ret = cam.MV_CC_SetIntValue("GevSCPSPacketSize",nPacketSize)
if ret != 0:
print ("Warning: Set Packet Size fail! ret[0x%x]" % ret)
else:
print ("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)
# ch:设置触发模式为off | en:Set trigger mode as off
ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
if ret != 0:
print ("set trigger mode fail! ret[0x%x]" % ret)
sys.exit()
# ch:获取数据包大小 | en:Get payload size
stParam = MVCC_INTVALUE()
memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))
ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)
if ret != 0:
print ("get payload size fail! ret[0x%x]" % ret)
sys.exit()
nPayloadSize = stParam.nCurValue
# ch:开始取流 | en:Start grab image
ret = cam.MV_CC_StartGrabbing()
if ret != 0:
print ("start grabbing fail! ret[0x%x]" % ret)
sys.exit()
data_buf = (c_ubyte * nPayloadSize)()
try:
hThreadHandle = threading.Thread(target=work_thread, args=(cam, byref(data_buf), nPayloadSize))
hThreadHandle.start()
except:
print ("error: unable to start thread")
print ("press a key to stop grabbing.")
msvcrt.getch()
g_bExit = True
hThreadHandle.join()
# ch:停止取流 | en:Stop grab image
ret = cam.MV_CC_StopGrabbing()
if ret != 0:
print ("stop grabbing fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
# ch:关闭设备 | Close device
ret = cam.MV_CC_CloseDevice()
if ret != 0:
print ("close deivce fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
# ch:销毁句柄 | Destroy handle
ret = cam.MV_CC_DestroyHandle()
if ret != 0:
print ("destroy handle fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
del data_buf
我们看到程序中主要程序里面的功能就是 读取电脑中GIGE 的相机列表 让你选择相机,然后打开设备,再然后读取视屏流数据
我们看到运行结果是读取了一帧画面。
那么我们要做的就是把这一帧画面转换成 opencv的图像格式并显示。
所以我们要在线程函数work_thread中去修改。
# 为线程定义一个函数
def work_thread(cam=0, pData=0, nDataSize=0):
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
temp = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)
temp = temp.reshape((2048, 3072, 1)) # 根据自己分辨率进行转化
# print(temp)
# print(temp.shape)
temp = cv2.cvtColor(temp, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常
cv2.namedWindow("result", cv2.WINDOW_AUTOSIZE)
cv2.imshow("result", temp)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
if ret == 0:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (
stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
else:
print("no data[0x%x]" % ret)
if g_bExit == True:
break
我们看到在 这个 函数中 pdata 这个参数就是我们需要的 数据流块,nDataSize就是 数据大小。
我们需要把pdata 格式化一下,因为目前数据是线性的一维数据,所以 我们根据图像格式将数据数组重新构建。
temp.reshape((2048, 3072, 1)) 这里我们根据相机 来确定维度。图像的高和宽,颜色通道。这里相机是灰度的 所以使用单通道 参数惨设置为1.
然后的到的temp 图像数据 还需要转换成 opencv格式, opencv格式是 RGB 而 海康 取到的数据是BGR的
temp = cv2.cvtColor(temp, cv2.COLOR_BGR2RGB)
其实到了这一步大家都看到了。后面就是循环显示了。只是对sdk 稍作改动就行了。
哦对了这里还有个坑。就是
try:
hThreadHandle = threading.Thread(target=work_thread, args=(cam, byref(data_buf), nPayloadSize))
hThreadHandle.start()
这句代码里面 byref(data_buf) 这个参数 如果直接使用会让opencv程序报错。 应为opencv 的数据格式 是 int 型的不是 浮点型。所以我们只要把 byref()去掉就不会报错了。
效果图。
图不太好看 没上镜头。好了 言归正传。解决了 opencv读取相机的问题 那么我们就要把视频流在pyqt 中去实时显示了
pyqt5 opencv 动态显示相机视频流
下面我们用Qt Designer 创建一个ui界面,界面包括相机选取列表,显示label,打开相机按钮,关闭相机按钮,界面如下:
然后我们在程序启动的时候就必须读取所有 海康gigie 的相机列表。所以我们需要从上面的 sdk sample里面找出相机列表的相关代码 编辑成一个函数SelectDevice()
#获得所有相机的列表存入cmbSelectDevice中
def SelectDevice(self):
'''选择所有能用的相机到列表中,
gige相机需要配合 sdk 得到。
'''
#得到相机列表
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
# ch:枚举设备 | en:Enum device
ret = MvCamera.MV_CC_EnumDevices(tlayerType, self.deviceList)
if ret != 0:
print("enum devices fail! ret[0x%x]" % ret)
sys.exit()
if self.deviceList.nDeviceNum == 0:
print("find no device!")
sys.exit()
print("Find %d devices!" % self.deviceList.nDeviceNum)
for i in range(0, self.deviceList.nDeviceNum):
mvcc_dev_info = cast(self.deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
if 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.camSelect.addItem(strModeName,i) #写入设备列表。
然后在ui初始化的时候 创建一个自定义信号连接槽函数。执行读取相机列表。
sendAddDeviceName = pyqtSignal() #定义一个添加设备列表的信号。
def connect_and_emit_sendAddDeviceName(self):
# Connect the sendAddDeviceName signal to a slot.
self.sendAddDeviceName.connect(self.SelectDevice)
# Emit the signal.
self.sendAddDeviceName.emit()
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.connect_and_emit_sendAddDeviceName()
这样就读取了系统已连接的所有gige相机的列表。
然后给打开按钮和关闭相机按钮点击事件信号连接曹函数。
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.connect_and_emit_sendAddDeviceName()
self.butopenCam.clicked.connect(lambda:self.openCam(self.camSelect.currentData()))
self.butcloseCam.clicked.connect(self.closeCam)
然后通过更改SDK 编辑 openCam 和 closeCam 两个曹函数
#打开摄像头。
def openCam(self,camid):
self.g_bExit = False
# ch:选择设备并创建句柄 | en:Select device and create handle
stDeviceList = cast(self.deviceList.pDeviceInfo[int(camid)], POINTER(MV_CC_DEVICE_INFO)).contents
ret = self.cam.MV_CC_CreateHandle(stDeviceList)
if ret != 0:
print("create handle fail! ret[0x%x]" % ret)
sys.exit()
# ch:打开设备 | en:Open device
ret = self.cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
print("open device fail! 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)
else:
print("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)
# ch:设置触发模式为off | en:Set trigger mode as off
ret = self.cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
if ret != 0:
print("set trigger mode fail! ret[0x%x]" % ret)
sys.exit()
# ch:获取数据包大小 | en:Get payload size
stParam = 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)
sys.exit()
nPayloadSize = stParam.nCurValue
# ch:开始取流 | en:Start grab image
ret = self.cam.MV_CC_StartGrabbing()
if ret != 0:
print("start grabbing fail! ret[0x%x]" % ret)
sys.exit()
data_buf = (c_ubyte * nPayloadSize)()
try:
hThreadHandle = threading.Thread(target=self.work_thread, args=(self.cam, data_buf, nPayloadSize))
hThreadHandle.start()
except:
print("error: unable to start thread")
函数的参数 camid 是选择的相机的编号。通过读取 UI控件camSelect来得到。
self.camSelect.currentData()
这个我在编辑的时候遇到了一个问题困扰了半天。就是在pyqt5里面 带参数传入的曹函数连接 一定需要使用lambda语句所以连接曹函数的语句就需要写成
self.butopenCam.clicked.connect(lambda:self.openCam(self.camSelect.currentData()))
下面是关闭相机的曹函数。
#关闭相机
def closeCam(self):
self.g_bExit=True
# ch:停止取流 | en:Stop grab image
ret = self.cam.MV_CC_StopGrabbing()
if ret != 0:
print("stop grabbing fail! ret[0x%x]" % ret)
sys.exit()
# ch:关闭设备 | Close device
ret = self.cam.MV_CC_CloseDevice()
if ret != 0:
print("close deivce fail! ret[0x%x]" % ret)
# ch:销毁句柄 | Destroy handle
ret = self.cam.MV_CC_DestroyHandle()
if ret != 0:
print("destroy handle fail! ret[0x%x]" % ret)
实现了相机的打开与关闭那么我们就要实现 最重要的 主体图像显示线程函数了。
def work_thread(self,cam=0, pData=0, nDataSize=0):
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
QIm = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)
QIm = QIm.reshape((2048, 3072, 1)) # 根据自己分辨率进行转化
# print(temp)
# print(temp.shape)
QIm = cv2.cvtColor(QIm, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常
pyrD1=cv2.pyrDown(QIm) #向下取样
pyrD2 = cv2.pyrDown(pyrD1) # 向下取样
image_height, image_width, image_depth = pyrD2.shape # 读取图像高宽深度
#QIm = cv2.cvtColor(QIm, cv2.COLOR_BGR2RGB)
pyrD3 = QImage(pyrD2, image_width, image_height, image_width * image_depth,QImage.Format_RGB888)
self.label.setPixmap(QPixmap.fromImage(pyrD3))
#cv2.namedWindow("result", cv2.WINDOW_AUTOSIZE)
#cv2.imshow("result", temp)
#if cv2.waitKey(1) & 0xFF == ord('q'):
# break
ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
if ret == 0:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (
stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
else:
print("no data[0x%x]" % ret)
if self.g_bExit == True:
del pData
break
在前文中我们已经学习了如何在pyqt5的窗口中显示 opencv 图像。那么我们要把显示图像的功能中加入 相机sdk读取数据流后显示到ui的功能。前文中已经读取了数据流并显示在了 opencv的窗口中,而这里我们只要把数据作为窗体控件label 的背景显示出来就行了
QIm = cv2.cvtColor(QIm, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常
pyrD1=cv2.pyrDown(QIm) #向下取样
pyrD2 = cv2.pyrDown(pyrD1) # 向下取样
image_height, image_width, image_depth = pyrD2.shape # 读取图像高宽深度
pyrD3 = QImage(pyrD2, image_width, image_height, image_width * image_depth,QImage.Format_RGB888)
self.label.setPixmap(QPixmap.fromImage(pyrD3))
这些代码里由于取得的图样太大所有我们对其进行了缩小,使用的是 金字塔向下取样。
这样我们整个程序就完成了。可以在pyqt5 中实现海康Gige相机的实时视频了
全部源码:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainWindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# 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, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(589, 530)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.camSelect = QtWidgets.QComboBox(self.centralwidget)
self.camSelect.setObjectName("camSelect")
self.verticalLayout.addWidget(self.camSelect)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.butopenCam = QtWidgets.QPushButton(self.centralwidget)
self.butopenCam.setObjectName("butopenCam")
self.verticalLayout.addWidget(self.butopenCam)
self.butcloseCam = QtWidgets.QPushButton(self.centralwidget)
self.butcloseCam.setObjectName("butcloseCam")
self.verticalLayout.addWidget(self.butcloseCam)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 589, 23))
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.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "TextLabel"))
self.butopenCam.setText(_translate("MainWindow", "打开相机"))
self.butcloseCam.setText(_translate("MainWindow", "关闭相机"))
这是UI窗口类
# -- coding: utf-8 --
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import *
import numpy as np
from MvImport.MvCameraControl_header import MV_CC_DEVICE_INFO_LIST
from mainWindow import Ui_MainWindow # 导入创建的GUI类
import sys
import threading
import msvcrt
from ctypes import *
sys.path.append("./MvImport")
from MvCameraControl_class import *
class mywindow(QtWidgets.QMainWindow, Ui_MainWindow):
sendAddDeviceName = pyqtSignal() #定义一个添加设备列表的信号。
deviceList = MV_CC_DEVICE_INFO_LIST()
g_bExit = False
# ch:创建相机实例 | en:Creat Camera Object
cam = MvCamera()
def connect_and_emit_sendAddDeviceName(self):
# Connect the sendAddDeviceName signal to a slot.
self.sendAddDeviceName.connect(self.SelectDevice)
# Emit the signal.
self.sendAddDeviceName.emit()
def __init__(self):
super(mywindow, self).__init__()
self.setupUi(self)
self.connect_and_emit_sendAddDeviceName()
self.butopenCam.clicked.connect(lambda:self.openCam(self.camSelect.currentData()))
self.butcloseCam.clicked.connect(self.closeCam)
# setting main window geometry
desktop_geometry = QtWidgets.QApplication.desktop() # 获取屏幕大小
main_window_width = desktop_geometry.width() # 屏幕的宽
main_window_height = desktop_geometry.height() # 屏幕的高
rect = self.geometry() # 获取窗口界面大小
window_width = rect.width() # 窗口界面的宽
window_height = rect.height() # 窗口界面的高
x = (main_window_width - window_width) // 2 # 计算窗口左上角点横坐标
y = (main_window_height - window_height) // 2 # 计算窗口左上角点纵坐标
self.setGeometry(x, y, window_width, window_height) # 设置窗口界面在屏幕上的位置
# 无边框以及背景透明一般不会在主窗口中用到,一般使用在子窗口中,例如在子窗口中显示gif提示载入信息等等
# self.setWindowFlags(Qt.FramelessWindowHint)
# self.setAttribute(Qt.WA_TranslucentBackground)
#打开摄像头。
def openCam(self,camid):
self.g_bExit = False
# ch:选择设备并创建句柄 | en:Select device and create handle
stDeviceList = cast(self.deviceList.pDeviceInfo[int(camid)], POINTER(MV_CC_DEVICE_INFO)).contents
ret = self.cam.MV_CC_CreateHandle(stDeviceList)
if ret != 0:
print("create handle fail! ret[0x%x]" % ret)
sys.exit()
# ch:打开设备 | en:Open device
ret = self.cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
print("open device fail! 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)
else:
print("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)
# ch:设置触发模式为off | en:Set trigger mode as off
ret = self.cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
if ret != 0:
print("set trigger mode fail! ret[0x%x]" % ret)
sys.exit()
# ch:获取数据包大小 | en:Get payload size
stParam = 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)
sys.exit()
nPayloadSize = stParam.nCurValue
# ch:开始取流 | en:Start grab image
ret = self.cam.MV_CC_StartGrabbing()
if ret != 0:
print("start grabbing fail! ret[0x%x]" % ret)
sys.exit()
data_buf = (c_ubyte * nPayloadSize)()
try:
hThreadHandle = threading.Thread(target=self.work_thread, args=(self.cam, data_buf, nPayloadSize))
hThreadHandle.start()
except:
print("error: unable to start thread")
#关闭相机
def closeCam(self):
self.g_bExit=True
# ch:停止取流 | en:Stop grab image
ret = self.cam.MV_CC_StopGrabbing()
if ret != 0:
print("stop grabbing fail! ret[0x%x]" % ret)
sys.exit()
# ch:关闭设备 | Close device
ret = self.cam.MV_CC_CloseDevice()
if ret != 0:
print("close deivce fail! ret[0x%x]" % ret)
# ch:销毁句柄 | Destroy handle
ret = self.cam.MV_CC_DestroyHandle()
if ret != 0:
print("destroy handle fail! ret[0x%x]" % ret)
def work_thread(self,cam=0, pData=0, nDataSize=0):
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
QIm = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)
QIm = QIm.reshape((2048, 3072, 1)) # 根据自己分辨率进行转化
# print(temp)
# print(temp.shape)
QIm = cv2.cvtColor(QIm, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常
pyrD1=cv2.pyrDown(QIm) #向下取样
pyrD2 = cv2.pyrDown(pyrD1) # 向下取样
image_height, image_width, image_depth = pyrD2.shape # 读取图像高宽深度
pyrD3 = QImage(pyrD2, image_width, image_height, image_width * image_depth,QImage.Format_RGB888)
self.label.setPixmap(QPixmap.fromImage(pyrD3))
#cv2.namedWindow("result", cv2.WINDOW_AUTOSIZE)
#cv2.imshow("result", temp)
#if cv2.waitKey(1) & 0xFF == ord('q'):
# break
ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
if ret == 0:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (
stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
else:
print("no data[0x%x]" % ret)
if self.g_bExit == True:
del pData
break
#获得所有相机的列表存入cmbSelectDevice中
def SelectDevice(self):
'''选择所有能用的相机到列表中,
gige相机需要配合 sdk 得到。
'''
#得到相机列表
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
# ch:枚举设备 | en:Enum device
ret = MvCamera.MV_CC_EnumDevices(tlayerType, self.deviceList)
if ret != 0:
print("enum devices fail! ret[0x%x]" % ret)
sys.exit()
if self.deviceList.nDeviceNum == 0:
print("find no device!")
sys.exit()
print("Find %d devices!" % self.deviceList.nDeviceNum)
for i in range(0, self.deviceList.nDeviceNum):
mvcc_dev_info = cast(self.deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents
if 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.camSelect.addItem(strModeName,i) #写入设备列表。
def pushbutton_function(self):
#do some things
Img=cv2.imread('JP1.JPG') #通过opencv读入一张图片
image_height, image_width, image_depth=Img.shape #读取图像高宽深度
QIm=cv2.cvtColor(Img,cv2.COLOR_BGR2RGB)
QIm=QImage(QIm.data, image_width, image_height, image_width * image_depth,QImage.Format_RGB888)
self.label.setPixmap(QPixmap.fromImage(QIm))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = mywindow()
window.show()
sys.exit(app.exec_())
以上是主程序。