社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python+OpenCV与海康工业相机交互

点云PCL • 1 年前 • 524 次点击  

点云PCL免费知识星球,点云知识点分享

文章:Python+OpenCV与海康工业相机交互(可得到OpenCV的Mat数据)

作者:登登

来源:智驾全栈与3D视觉学习星球

欢迎各位加入知识星球,获取更多技术分享,欢迎转发朋友圈分享快乐。

1

前言

因为项目的原因,笔者需要开发自己的程序与海康工业相机(黑白相机)进行实时交互,而不是简单的使用海康的驱动来调用相机。

在经历了反复的踩坑填坑之后,笔者总结了利用c#和python与海康相机交互的方法。


2

准备工作

无论是用c#还是python,都要通过海康的SDK来进行二次开发。海康的SDK实际上就是一个第三方库文件,里面有各种用于海康相机交互的函数,这些函数被封装成供各大编程语言使用的dll或者lib文件。你可以像使用OpenCV样调用海康的SDK。


海康提供了各个编程语言的例程,可以让我们对照例程快速上手。海康的例程一般放在相机驱动软件的安装文件夹下,具体路径为 …\MVS\Development\Samples

里面有大部分主流语言的例程:

除此之外,海康还提供了SDK的说明文档,文件路径在

…\MVS\Development\Documentations

c#可以参考.net版本的,python和c可以参考c版本的(两者差别都不大)。

3

C#调用

在c#中的例程里面,有很多程序

但除了basicdemo有界面,其他的都是控制台程序,显示不了图片。而且basicdemo基本涵盖了海康相机使用的各个方面,所以推荐优先学习basicdemo程序。

该程序的主界面如下图所示:

需要注意的是,虽然这里能显示图片,但得到的图片数据仍然是海康的图片格式,不是opencv可以处理的mat格式。笔者尝试了很多次,鉴于对C#不是很熟练,暂时无法将其转为可供opencv处理的数据格式。这一功能我在python中实现了。

4

Python调用

python的话,参考例程中的grabimg程序,对里面的线程进行改造即可。但这里也有一些问题需要注意

首先,官网给的源程序只能在控制台显示得到的图片帧的长和宽,并没有取得图片的数据。但这明显不是我们想要的。所以需要对其进行改造,改造的部分主要在线程函数中

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


这是官方的线程函数。我们需要在里面进行改造。

改造之后的函数为

def work_thread2(cam=0, pData=0, nDataSize=0):# 输出帧的信息stFrameInfo = MV_FRAME_OUT_INFO_EX()# void *memset(void *s, int ch, size_t n);# 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s# memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法# byref(n)返回的相当于C的指针右值&n,本身没有被分配空间# 此处相当于将帧信息全部清空了memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))

while True:temp = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)# print(temp)# print(temp.shape)temp = temp.reshape((2048, 1024, 3)) # 根据自己分辨率进行转化# temp = cv2.cvtColor(temp, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常gray = cv2.cvtColor(temp,cv2.COLOR_BGR2GRAY)ret,binary = cv2.threshold(gray,130,255,cv2.THRESH_BINARY)cv2.namedWindow( "binary", cv2.WINDOW_NORMAL)cv2.namedWindow("ori", cv2.WINDOW_NORMAL)cv2.imshow('binary',binary)cv2.imshow("ori", temp)if cv2.waitKey(1) & 0xFF == ord('q'):break# 采用超时机制获取一帧图片,SDK内部等待直到有数据时返回,成功返回0ret = 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:breakcv2.waitKey()


除此之外,还有几个点需要注意

第一个

sys.path.append(r"**\MvImport")

因为需要用到SDK的接口函数,所以需要导入相应的库,官方的路径是这样的,这是因为这个包在程序的同一个文件夹下,所以前面的都可以省略,但我们使用的时候,最好把它的绝对路径给写上,我的路径是这样的,可以参考

sys.path.append(r"C:\Users\Administrator\Desktop\python_vscode\MvImport")


第二个

在线程函数之外,还有几个关键语句需要注意



#ch:获取数据包大小 | en:Get payload sizestParam = MVCC_INTVALUE()#csharp中没有memset函数,用什么代替?memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))# MV_CC_GetIntValue,获取Integer属性值,handle [IN] 设备句柄 # strKey [IN] 属性键值,如获取宽度信息则为"Width" # pIntValue [IN][OUT] 返回给调用者有关相机属性结构体指针# 得到图片尺寸,这一句很关键# payloadsize,为流通道上的每个图像传输的最大字节数,相机的PayloadSize的典型值是(宽x高x像素大小),此时图像没有附加任何额外信息ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)


cam.MV_CC_GetIntValue(“PayloadSize”, stParam)这一句中的PayloadSize是流通道上的每个图像传输的最大字节数,相机的PayloadSize的典型值是(宽x高x像素大小),这是一个很关键的步骤,官方例子中并没有获得这个值。

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()    #  关键句,官方没有这个句子,抓取的图片数据是空的,CSharp中怎么实现这句话。    data_buf = (c_ubyte * nPayloadSize)()


data_buf = (c_ubyte * nPayloadSize)()这一句话将PayloadSize的uint数据转为可供numpy处理的数据,后面就可以用numpy将其转化为numpy数组格式。



第三个,线程的使用

官方例子是

hThreadHandle = threading.Thread(target=work_thread, args=(cam, None,None))hThreadHandle.start()

此处需要改成

try:hThreadHandle = threading.Thread(target=work_thread2, args=(cam, data_buf, nPayloadSize))hThreadHandle.start()

在这里,有些代码可能会在data_buf前面加上byteref,如果这样做的话,就会将数据转为浮点型,而opencv需要的是整型,会报错,所以这里就不需要转化了。


更多详细内容或提问作者

以上内容如有错误请留言评论,欢迎指正交流。如有侵权,请联系删除

扫描二维码

                   关注我们

让我们一起分享一起学习吧!期待有想法,乐于分享的小伙伴加入免费星球注入爱分享的新鲜活力。分享的主题包含但不限于三维视觉,点云,高精地图,自动驾驶,以及机器人等相关的领域。

分享及合作方式:微信“920177957”(需要按要求备注) 联系邮箱:dianyunpcl@163.com,欢迎企业来联系公众号展开合作。

点一下“在看”你会更好看耶

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/152056
 
524 次点击