因为项目的原因,笔者需要利用程序来实时调用海康工业相机,而不是简单的利用海康的驱动来调用相机。
在经历了反复的踩坑填坑之后,笔者总结了利用c#和python调用海康相机的两种方法
无论是用c#还是python,都是要通过海康的SDK来进行二次开发的。海康的SDK相当于一个库,里面有各种用于海康相机的函数,这些函数被封装成供各大编程语言使用。所以,要想利用python或者c#与海康进行实时交互,就得像学习SDK中的各个函数的用法。但好在海康提供了各个编程语言的例程,可以让我们对照例程快速上手。海康的例程一般放在
海康相机驱动软件
的安装文件夹下,具体路径为
…\MVS\Development\Samples
里面有大部分主流语言的例程
除此之外,海康还提供了SDK的说明文档,文件路径在
…\MVS\Development\Documentations
c#可以参考.net版本的,python和c可以参考c版本的(两者差别都不大)
在c#中的例程里面,有很多程序
但除了basicdemo有界面,其他的都是控制台程序,显示不了图片。
而且basicdemo基本涵盖了海康相机使用的各个方面,所以推荐优先学习basicdemo程序。
该程序的主界面如下图所示。
需要注意的是,虽然这里能显示图片,但得到的图片数据仍然是海康的图片格式,不是opencv可以处理的mat格式。笔者尝试了很多次,仍然没法将其转化为可以供opencv处理的数据格式。这一功能我在python中实现了,在c#中还没找到方法(应该是因为我对c#不是很熟),对c#比较熟悉的可以参考我的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()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
temp = np.asarray(pData)
temp = temp.reshape((2048, 1024, 3))
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
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
cv2.waitKey()
除此之外,还有几个点需要注意
第一个
sys.path.append(r"**\MvImport")
因为需要用到SDK的接口函数,所以需要导入相应的库,官方的路径是这样的,这是因为这个包在程序的同一个文件夹下,所以前面的都可以省略,但我们使用的时候,最好把它的绝对路径给写上,我的路径是这样的,可以参考
sys.path.append(r"C:\Users\Administrator\Desktop\python_vscode\MvImport")
第二个
在线程函数之外,还有几个关键语句需要注意
stParam = MVCC_INTVALUE()
memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))
ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)
cam.MV_CC_GetIntValue(“PayloadSize”, stParam)这一句中的PayloadSize是流通道上的每个图像传输的最大字节数,相机的PayloadSize的典型值是(宽x高x像素大小),这是一个很关键的步骤,官方例子中并没有获得这个值。
nPayloadSize = stParam.nCurValue
ret = cam.MV_CC_StartGrabbing()
if ret != 0:
print ("start grabbing fail! ret[0x%x]" % ret)
sys.exit()
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需要的是整型,会报错,所以这里就不需要转化了
import
sys
import threading
import msvcrt
import numpy as np
from cv2 import cv2
from ctypes import *
sys.path.append(r"C:\Users\Administrator\Desktop\python_vscode\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
def work_thread2(cam=0, pData=0, nDataSize=0):
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
temp = np.asarray(pData)
temp = temp.reshape((2048, 1024, 3))
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
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
cv2.waitKey()
if __name__ == "__main__":
deviceList = MV_CC_DEVICE_INFO_LIST()
tlayerType = MV_GIGE_DEVICE | MV_USB_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()
cam = MvCamera()
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()
ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
if ret != 0:
print ("open device fail! ret[0x%x]" % ret)
sys.exit()
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)
ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
if ret != 0:
print ("set trigger mode fail! ret[0x%x]" % ret)
sys.exit()
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
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_thread2, args=(cam, 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()
ret = cam.MV_CC_StopGrabbing()
if ret != 0:
print ("stop grabbing fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
ret = cam.MV_CC_CloseDevice()
if ret != 0:
print ("close deivce fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
ret = cam.MV_CC_DestroyHandle()
if ret != 0:
print ("destroy handle fail! ret[0x%x]" % ret)
del data_buf
sys.exit()
del data_buf
结果图

结果展示的一个是原图,一个是用opencv二值化之后的图。经过上述处理之后,就可以得到供opencv处理的数据格式了。
本论文主要介绍了如何用c#或者python调用海康工业相机。并且在python中实现了将海康相机提取到的相机数据转化为opencv支持的格式,这样就实现了python加opencv对海康相机的实时调用。
注意:网上有很多利用rtsp地址格式来获取海康相机数据的方法,笔者一开始也是想用这种方法实现,因为这样就可以直接用opencv中的videocapture类直接调用相机了。但经过多番尝试之后,仍然无果。后来是在联系了海康客服才知道,所有的工业网口相机都不支持rtsp格式获取数据,网上的方法都是针对于海康摄像机、录影机的。而且也只有摄像机、录影机才需要先激活再使用,工业网口相机拿来就用即可,亏的我一开始还想办法激活我的工业相机,我可真是个憨憨。
代码都已开源,喜欢的还请一键三连。
2022.01.07:
看到自己写的博客下面有这么多人评论,同时也能给很多人带来帮助,甚是开心啊。因为笔者平时科研比较忙,很多消息都没有回复,我只能挑一些比较典型的问题回复,其他一些问题希望各位小伙伴互帮互助,笔者先在这谢过了。
除了与海康威视的相机交互,笔者也使用过大恒相机,不过是使用c#结合emgucv(opencv在.net平台下的版本)与大恒相机交互,相关的资料我已经封装成了类供大家下载(笔者需要一些积分下载资料,所以这一块就不公开了,有能力的可以下载,实在没钱但又需要的可以私信我)。c#与大恒相机交互
笔者最近还在使用海康威视的三维激光轮廓扫描仪,如何利用c++结合qt以及pcl与扫描仪进行交互,把扫描仪数据直接转为pcl中的点云对象,是笔者最近研究的一个小问题。
笔者发现网上关于这块的资料基本没有,很多都是与二维相机的交互。本着开源互助的理念,有进展之后会另写一篇文章与大家分享。对三维相机感兴趣的小伙伴抓紧点赞收藏啊,点赞和收藏数达到100之后将会公布所有源码(注释很详细)手动滑稽。
文章目录前言一、准备工作二、c#调用1.引入库3、python调用4 完整代码总结题外话前言因为项目的原因,笔者需要利用程序来实时调用海康工业相机,而不是简单的利用海康的驱动来调用相机。在经历了反复的踩坑填坑之后,笔者总结了利用c#和python调用海康相机的两种方法一、准备工作无论是用c#还是python,都是要通过海康的SDK来进行二次开发的。海康的SDK相当于一个库,里面有各种用于海康相机的函数,这些函数被封装成供各大编程语言使用。所以,要想利用python或者c#与海康进行实时交互,就
图片信息的表示不止只有我们熟知的RGB,还有HLS、HSV、YUV、bayer,由于opencv等视觉处理库的广泛运用,RGB空间色彩模型运用最为广泛(实际上是BGR)。
摄像头传感器的感光原理是通过一个个的感光点对光进行采样和量化。但是每一个感光点只能感光RGB中的一种颜色。所以通常所说的50万像素或5000万像素等,指的是有50万或5000万个感光点。每一个感光点只能感光一种颜色,但一个真正图像需要每一个像素点都有RGB三种颜色分量。
在传感器模组的内部有ISP模块,主要用来对前
temp = np.asarray(pData2) # 将c_ubyte_Array转化成ndarray得到(3686400,)
temp = temp.reshape((2592, 2048, 1)) # 根据自己分辨率进行转化
gray = cv2.cvtColor(temp,cv2.COLOR_BGR2GRAY)
cv2.imshow("img", gray)
rtsp://<address>:<port>/Streaming/Channels/<id>/
rtsp://<username>:<password>@<address>:<port>/Streaming/Channels/<id>/
Where <address> is the IP address of your camera, <port> is the RTSP port of the camera, and <username> and <password> refer to the login credentials of your camera.
Using the first format, you will be asked to login and verify your credentials before being allowed to view the stream.
Using the second format, you will automatically login when requesting the stream
<id> refers to the channel number and stream type of the camera. For example, an <id> of 101 refers to channel #1 (first digit, 1xx) using the main stream (second and third digits, x01).
Typically, you'll use a program such as VLC Media Player to decode the RTSP stream.
利用python加opencv与海康工业相机交互。(得到供opencv处理的数据)
心清似水淡若云、:
c#和Python交互,完美解决Python调用OpenCV等第三方库以及分发时需配置python环境的问题
用svm对数据进行二分类(完整代码)
L0wRy: