根据以上说明可知,MV_CC_GetImageBuffer() 接口需要在开始采集图像接口调用之后使用,即官方例程中的该接口调用,如下:
# 为线程定义一个函数
def work_thread(cam=0, pData=0, nDataSize=0):
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret:
print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)
else:
print ("no data[0x%x]" % ret)
if g_bExit == True:
break
在开启取流之后,通过该接口主动去抓取 SDK 底层的 buffer 中的图像数据和信息,通过该接口,可以将图像数据给到我们,但是官方例程中,并没有提供相关数据解析和显示的相关内容,这样就导致我们在此环节需要重新开发,本文第三部分将对图像数据的解析和显示做相关的代码实现;
并且在上面代码中可以看到该接口与 MV_CC_FreeImageBuffer()接口配套使用,在取到图像数据之后,在取下一张图像数据之前将 pstOutFrame 内的数据指针权限进行了释放;
三、主动取流( getimagebuffer )对黑白图像数据解析并用 opencv 显示
1.主动取流( getimagebuffer )数据获取并解析 mono 格式的图像数据
# 为线程定义一个函数
def work_thread(cam=0, pData=0, nDataSize=0):
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret:
print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
else:
print ("no data[0x%x]" % ret)
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)
if g_bExit == True:
break
通过对官方例程中 getimagebuffer 获取图像数据的代码修改,获取到相关图像的数据,如上代码中 data 即为回调获取到的图像数据,并通过自定义函数 image_control() 对图像数据进行 reshape 操作,获取到可以显示的数据;
并且在一帧图像数据获取显示之后通过调用 MV_CC_FreeImageBuffer() 接口的调用,将数据指针权限进行了释放;
2.图像数据显示
def image_show(image):
image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)
cv2.imshow('fgmask', image)
k = cv2.waitKey(1) & 0xff
def image_control(data , stFrameInfo):
image = data.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth))
image_show(image = image)
以上代码时对使用 getimagebuffer 接口获取到的图像数据进行显示的代码,但是以上代码仅在使用海康工业相机黑白模式下使用,因为没有考虑像素格式以及通道等信息,下面第四部分对多种像素格式图像数据进行解析并显示;
四、主动取流( getimagebuffer )获取多种像素格式的图像数据解析并用 opencv 显示
1.主动取流( getimagebuffer )数据获取并解析多种像素格式的数据
基于第一章(python调用海康工业相机并用opencv显示)中,对于常用接口的封装,getimagebuffer 部分也进行相关内容的封装,并将获取的数据解析部分封装为一体,具体代码如下所示:
if active_way == "getImagebuffer":
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301505:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301514:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 35127316:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 34603039:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
else:
print("no data[0x%x]" % ret)
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)
以上部分因为与主动取流中的 getoneframetimeout 接口的调用封装到一起,所以是以 if 开头,并调用的,后续会将这两部分的代码全部放到一起;
因为工业相机总有不同的像素格式,也就对应有不同的通道数,所以在图像解析过程中就会出现不同分支的解析方式,以上内容是根据海康提供的官方定义中获取到的像素格式对应的数字,进行判定,具体的定义在海康 SDK 目录下:../MVS/Development/Samples/Python/MvImport/PixelType_header.py 文件中,如需要其他像素格式,请自行查询;
2.图像数据显示
由以上内容可以知道,通过 getimagebuffer 获取到的图像数据是多种像素格式类型的,不同像素格式类型图像通道不同,自然也会导致显示时,不同通道配置的代码,以下内容是对不同像素格式类型的图像数据的显示,代码如下:
# 显示图像
def image_show(image):
image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)
cv2.imshow('fgmask', image)
k = cv2.waitKey(1) & 0xff
# 需要显示的图像数据转换
def image_control(data , stFrameInfo):
if stFrameInfo.enPixelType == 17301505:
image = data.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth))
image_show(image=image)
elif stFrameInfo.enPixelType == 17301514:
data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
image = cv2.cvtColor(data, cv2.COLOR_BAYER_GB2RGB)
image_show(image=image)
elif stFrameInfo.enPixelType == 35127316:
data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
image = cv2.cvtColor(data, cv2.COLOR_RGB2BGR)
image_show(image=image)
elif stFrameInfo.enPixelType == 34603039:
data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
image = cv2.cvtColor(data, cv2.COLOR_YUV2BGR_Y422)
image_show(image = image)
可以看到不同的通道数,对应不同的数据转换,最终将图像显示在桌面上;
五、主动取流(getoneframetimeout & getimagebuffer)的封装
主动取流在海康提供的 SDK 底层接口中有两种,分别是 getoneframetimeout 和 getimagebuffer 两种,以下代码是对这两种取流方式的封装函数代码,如下:
# 主动图像采集
def access_get_image(cam , active_way = "getImagebuffer"):
:param cam: 相机实例
:active_way:主动取流方式的不同方法 分别是(getImagebuffer)(getoneframetimeout)
:return:
if active_way == "getImagebuffer":
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301505:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301514:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 35127316:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 34603039:
print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2),dtype=np.uint8)
image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)
else:
print("no data[0x%x]" % ret)
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)
elif active_way == "getoneframetimeout":
stParam = MVCC_INTVALUE_EX()
memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))
ret = cam.MV_CC_GetIntValueEx("PayloadSize", stParam)
if ret != 0:
print("get payload size fail! ret[0x%x]" % ret)
sys.exit()
nDataSize = stParam.nCurValue
pData = (c_ubyte * nDataSize)()
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))
image = np.asarray(pData)
image_control(data=image, stFrameInfo=stFrameInfo)
else:
print("no data[0x%x]" % ret)
工业相机的使用,不同场景使用不同的取流方式,这样才能更好的发挥相机的功能和效率,对于我们的项目能够提到事半功倍的效果,而取流部分的实现,对于项目而言是至关重要的,因而选用怎样的取流方式,以及数据解析都很重要。
系列文章目录第四章 python 语言下使用海康工业相机,主动取流方式(getimagebuffer)获取图像数据并显示文章目录目录系列文章目录文章目录前言一、使用前提二、主动取流(官方例程说明)1.接口说明2.python 下接口实现三、主动取流( getimagebuffer)对黑白图像数据解析并用 opencv 显示1.主动取流( getimagebuffer)数据获取并解析 mono 格式的图像数据2.图像数据显示四、主动取...
条件:Python+海康官方的mvs文件下的development/samples下的python文件夹
注意:相机连接后不要用官方app打开相机,不然python代码检测不到设备,代码在pycharm会提示报错,亲测能跑并能截取到图片
# -- coding: utf-8 --
import sys
import copy
import msvcrt
from ctypes import *...
易出现的问题
在使用python多线程对图像进行处理时,可能会出现要显示的图像一闪而逝的问题,而又没有任何报错。这应该是线程阻塞导致的。也许是你在循环指令下面建立了线程,从而会导致开启太多的线程。别说加锁了,似乎就算不加锁也没法解决这个问题,我感觉可能是太多线程同时竞争资源导致的死锁。
不要在循环内建立线程,把循环放在整个线程里面。也许你最初想要显示图像并处理图像,那么他们本该在同一个循环下。如果按照我说的那样,那把代码拆成两个线程的话,似乎就变成两个循环了。你可能认为这
海康机器人工业相机常用参数功能设置与获取(C语言)前言DeviceControlImageFormatControlAcquisitionControlDigitalIOControlActionControlFileAccessControlEventControlChunkDataControlTransportLayerControlUserSetControl
DeviceControl
ImageFormatControl
AcquisitionControl
DigitalIOContro
只有打开相机以后,才能对相机参数进行设置。
3、选择内触发采集模式或者外触发采集模式;
内触发采集包括连续采集和单帧采集,外触发包括软触发和硬触发两种方式。它们两者的区别是后者需要发送触发命令,才能够采集到图像信息。
4、打开采集流;
5、取流抓图
如果是内触发采集模式,则打开采集流就可以采集到图像,如果是外触发采集模式,还
三、主动取流( getoneframetimeout )对黑白图像数据解析并用 opencv 显示
1.主动取流( getoneframetimeout )数据获取并解析 mono 格式的图像数据
# 绘制矩形框
x, y, w, h = 100, 100, 200, 200
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 提取 ROI
roi = img[y:y+h, x:x+w]
# 显示结果
cv2.imshow('image', img)
cv2.imshow('roi', roi)
cv2.waitKey(0)
cv2.destroyAllWindows()