python使用dir()函数获取对象中可用的属性和方法(看不到python源码又想知道怎么调用,DLL调用分析,SDK二次开发技巧)
有时候调用一些SDK,但是人家又是封装成dll文件形式调用的,这时没法看源码,也不想看其对应的开发文档(尤其有些开发文档写得还很难懂,或者你从某个开源社区拿过来,就根本没找到开发文档),
一.动态链接库之为啥你看不到源码
DLL(Dynamic Link Library)和 SO(Shared Object)都是可执行文件的一种形式,用于在运行时动态链接到程序中。它们的意义是为了实现代码的模块化和共享,提高代码的复用性和可维护性。
也就是说他们相当于打包好了的模块,你是看不到内部的代码的(当然逆向或许可以)
他所暴露的就只有调用的python接口,当然这个暴露的接口实际上也是通过python的ctypes模块调用编写的py文件中来看的,不过有些项目写得很混乱或易读性不够好,不论是结构还是命名,因此,本文是给出通过python的dir()模块来获取对象中可用的属性和方法并讨论说明在实际开发过程中如何玄学使用。
DLL(Windows 操作系统):
DLL 是 Windows 操作系统中的动态链接库文件,以 .dll 扩展名结尾。 DLL
文件包含函数、数据和资源等可供程序在运行时动态链接的代码。 多个程序可以共享使用同一个 DLL 文件,避免了重复编写和存储相同的代码。
DLL 的优势在于实现代码的动态链接,程序在运行时才将所需的函数和资源链接到程序中,而不是在编译时静态链接。 SO(Linux 操作系统):
SO 是 Linux 操作系统中的共享对象文件,以 .so 扩展名结尾。 SO 文件也是包含可供程序在运行时动态链接的代码、数据和资源等。
在 Linux 系统中,SO 文件可以被多个程序共享使用,实现代码的模块化和共享。 SO 文件的概念和作用与 DLL 文件相似,但在
Linux 系统下使用。
1.1简单dir()例子(不用dll的情况)
下面我给出一个简单的例子,这个例子我们可以清晰的看到 名为A的类的结构
# 定义一个类
class A():a_num = 1111a_string = "AAAAAAAAA"def A_fun(self):print("这是A函数")def A_add_1(self, num):return num+1# 创建一个对象
a = A()# 使用 dir() 显示当前作用域中的所有名称列表
name_list = dir(a)
print(name_list)
输出:
['A_add_1', 'A_fun', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a_num', 'a_string']
这里可以看到,‘A_add_1’, ‘A_fun’,‘a_num’, ‘a_string’ 这几个我们自定义的类函数与变量都存在了
1.2 简单dir()例子(调用DLL的情况)
A.dll 零积分下载链接
或者看 下文 四章节 自己将打包一个等效刚才A类功能的dll文件,
import ctypes# 加载 DLL 文件
dll = ctypes.CDLL("A.dll")# 定义函数的返回类型和参数类型
dll.A_add_1.restype = ctypes.c_int
dll.A_add_1.argtypes = [ctypes.c_void_p, ctypes.c_int]# 创建 A 类的实例
class A(ctypes.Structure):_fields_ = [("a_num", ctypes.c_int),("a_string", ctypes.c_char * 10)]# 调用 A_new 函数创建实例
dll.A_new.restype = ctypes.POINTER(A)
a_ptr = dll.A_new()
a = a_ptr.contents# 调用 A_add_1 函数
num = 5
result = dll.A_add_1(ctypes.byref(a), num)
print("Result:", result)# 获取 a_num 的值
a_num = a.a_num
print("a_num:", a_num)# 释放实例
dll.A_del(a_ptr)print(dir(A))
['__class__', '__ctypes_from_outparam__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_b_base_', '_b_needsfree_', '_fields_', '_objects', 'a_num', 'a_string']
这里实现的功能是和之前的A类是相同的,不过这里只能看到 ‘a_num’, ‘a_string’*,
至于为什么,因为python没法直接与获得dll文件的数据,只能得到一堆指向某个函数或者某个变量的指针,所以你想使用dll调用的方法复刻 A类 的各个函数(方法),变量。
那你可以下面这样写(当然这个,存python开发者不用掌握,我都用python了还要管变量类型与输出定义?能看懂已经很不错了)
import ctypes# 加载 DLL 文件
dll = ctypes.CDLL("A.dll")# 定义函数的返回类型和参数类型
dll.A_add_1.restype = ctypes.c_int
dll.A_add_1.argtypes = [ctypes.c_void_p, ctypes.c_int]dll.A_fun.restype = ctypes.c_char
dll.A_fun.argtypes = [ctypes.c_void_p]# dll.not_exist.restype = ctypes.c_char
# dll.not_exist.argtypes = [ctypes.c_void_p]# 创建 A 类的实例
class A(ctypes.Structure):_fields_ = [("a_num", ctypes.c_int),("a_string", ctypes.c_char * 10),("not_exist_val", ctypes.c_char * 10),]def A_add_1(self, num):return dll.A_add_1(ctypes.byref(self), num)def A_fun(self):return dll.A_fun(ctypes.byref(self))# 调用 A_new 函数创建实例
dll.A_new.restype = ctypes.POINTER(A)
a_ptr = dll.A_new()
a = a_ptr.contents# 调用 A_fun方法
result = a.A_fun()print("*"*10)
# 调用 A_add_1 方法
num = 5
result = a.A_add_1(num)
print("A_add_1 Result:", result)# 获取 a_num 的值
a_num = a.a_num
print("a_num:", a_num)# 获取 not_exist_val 的值(实际上该值并不存在,但是程序依然后随机分配一个数据地址指针给你,
# 你可以看到每次运行的结果都是空,但不会报错)
a_not_exist_val= a.not_exist_val
print("a_not_exist_val:", a_not_exist_val)# 释放实例
dll.A_del(a_ptr)print(dir(A))
输出
**********
A_add_1 Result: 6
a_num: 1111
a_not_exist_val: b''
['A_add_1', 'A_fun', '__class__', '__ctypes_from_outparam__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_b_base_', '_b_needsfree_', '_fields_', '_objects', 'a_num', 'a_string', 'not_exist_val']
这是A函数
提示: 在上面代码中我还多加了一个 名叫 not_exist_val 的值,这个值在A.dll文件中是不存在的,但是作为变量依然不会报错,只是返回了个空(也有可能随机一个十六进制数),这里主要是想说明,如果看到一个从dll调用的变量值是空或者乱码,极有可能这个调用的 名字错了,比如我这里的 not_exist_val ,而不是这个dll文件中真的存在 not_exist_val 这个变量。
二.实例分析
尤其是针对一些硬件的sdk的开发,要么没技术支持,要么连手册都没有,要么有手册但是和python没关系,但是又想用python来进行调用。
比如下面的例子,我要使用海康的MV-DLS600P深度相机做手眼标定的开发, 我想获取深度相机的视频流,就2023年而言海康给了一部分调用代码,但又没有完全给,成功运行上了示例代码,相机是亮了,但是只得到了一个 stFrameData.stImageData[i] 的变量,然后你就可以从这个变量上把深度图和点云图求出来了。如下图:
开发手册是c++的,看起来只能所有定义参考作用,鉴定为不如直接用dir()自己看,而且总感觉代码更新了,手册没更新…
但是不知道视频流的返回函数是什么(即stFrameData.stImageData[i]这个对象到底应该调用什么才能返回视频流),例如下面代码中 stFrameData.stImageData[i].nWidth是返回宽度,那么返回视频流是什么呢?
def work_thread(camera=0,pdata=0,nDataSize=0):while True:stFrameData=MV3D_RGBD_FRAME_DATA()ret=camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 1000)if ret==0:for i in range(0, stFrameData.nImageCount):# print("MV3D_RGBD_FetchFrame[%d]:nFrameNum[%d],nDataLen[%d],nWidth[%d],nHeight[%d]" % (# i, stFrameData.stImageData[i].nFrameNum, stFrameData.stImageData[i].nDataLen, stFrameData.stImageData[i].nWidth, stFrameData.stImageData[i].nHeight))print("MV3D_RGBD_FetchFrame[%d]:帧号[%d],数据长度[%d],宽度[%d],高度[%d]" % (i, stFrameData.stImageData[i].nFrameNum, stFrameData.stImageData[i].nDataLen,stFrameData.stImageData[i].nWidth, stFrameData.stImageData[i].nHeight))
1.通过dir查看
dir() 是一个内置函数,用于获取对象的所有属性和方法的列表。它返回一个包含字符串的列表,这些字符串表示对象拥有的属性和方法的名称。
dir() 函数有以下两种常见的用法:
无参数使用:当不传入任何参数时,dir() 返回当前作用域中的所有名称列表,包括内置的名称。
python Copy print(dir()) # 返回当前作用域中的所有名称列表 有参数使用:当传入一个对象作为参数时,dir()
返回该对象的属性和方法列表。python Copy my_list = [1, 2, 3] print(dir(my_list)) # 返回 my_list
对象的属性和方法列表 注意:参数可以是任何对象,包括内置对象(如列表、字典、字符串等)和自定义对象。dir()
函数返回的列表中的字符串代表对象的属性和方法名称。属性名称以字符串的形式表示,而方法名称则以函数对象的形式表示。您可以通过访问对象的属性(如
obj.attribute)或调用对象的方法(如 obj.method())来使用它们。需要注意的是,dir()
函数只返回对象中可见的属性和方法名称。有些属性和方法可能以双下划线开头,表示为特殊属性或私有属性,这些在列表中是不可见的。但是,您仍然可以通过直接访问这些属性和方法来使用它们。
加上下面,代码即可看到
print("对象中可用的属性和方法名称: " ,dir(stFrameData.stImageData[i]))
输出:
对象中可用的属性和方法名称:
[‘class’, ‘ctypes_from_outparam’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’, ‘eq’, ‘format’, ‘ge’, ‘getattribute’, ‘gt’, ‘hash’, ‘init’, ‘init_subclass’, ‘le’, ‘lt’, ‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘setstate’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’, ‘b_base’, ‘b_needsfree’, ‘fields’, ‘_objects’, ‘enImageType’, ‘nDataLen’, ‘nFrameNum’, ‘nHeight’, ‘nReserved’, ‘nTimeStamp’, ‘nWidth’, ‘pData’]
这里通过英文名判断大概就是,pData ,这里加上去然后调用看看是什么类型
print("en图像类型",stFrameData.stImageData[i].enImageType)print("en图像类型十六进制:", hex(stFrameData.stImageData[i].enImageType))print("n数据长度", stFrameData.stImageData[i].nDataLen)print("n帧数", stFrameData.stImageData[i].nFrameNum)print("n高度", stFrameData.stImageData[i].nHeight)print("n保留(类型)", type(stFrameData.stImageData[i].nReserved))print("n保留", stFrameData.stImageData[i].nReserved)print("n时间戳", stFrameData.stImageData[i].nTimeStamp)print("n宽度", stFrameData.stImageData[i].nWidth)print( "p数据(类型)",type(stFrameData.stImageData[i].pData))print("p数据", stFrameData.stImageData[i].pData)
输出:
en图像类型 35127329
en图像类型十六进制: 0x2180021
n数据长度 18874368
n帧数 1
n高度 2048
n保留(类型) <class 'Mv3dRgbdImport.Mv3dRgbdDefine.c_byte_Array_16'>
n保留 <Mv3dRgbdImport.Mv3dRgbdDefine.c_byte_Array_16 object at 0x000001F6F8ED8AC8>
n时间戳 1057938808
n宽度 3072
p数据(类型) <class 'Mv3dRgbdImport.Mv3dRgbdDefine.LP_c_ubyte'>
p数据 <Mv3dRgbdImport.Mv3dRgbdDefine.LP_c_ubyte object at 0x000001F6F8ED8AC8>
2.根据类型进行分析
基础知识:
C语言中有多种数据类型,以下是一些常见的C类型的定义示例:
整数类型:
int: 用于表示整数,通常为32位或64位(取决于编译器和平台)。 short: 用于表示短整数,通常为16位。 long:
用于表示长整数,通常为32位或64位。 char: 用于表示字符,通常为8位。 浮点数类型:float: 用于表示单精度浮点数,通常为32位。 double: 用于表示双精度浮点数,通常为64位。 指针类型:
int*: 用于表示指向整数的指针。 char*: 用于表示指向字符的指针。 void*: 用于表示通用指针,可以指向任意类型的数据。
结构体类型:struct: 用于定义自定义的结构体类型,可以包含多个成员变量,每个成员变量可以是任意类型。 枚举类型:
enum: 用于定义枚举类型,可以列出一组具名的常数值。
根据打印输出结果,stFrameData.stImageData[i]的成员变量(例如enImageType、nDataLen、nFrameNum等)的值和类型都表明它们是C类型的数据。C语言中的数据类型,例如整数、枚举、指针等(通常在Python中使用ctypes库进行封装和访问)
而我要获得点云图和深度图,那么根据stFrameData.stImageData[i] 对象打印的结果,以及给出的英文名来判断,深度相机返回数据最有可能出现的位置应该是 nReserved或者 pData的函数(方法)的返回值中。(有些类型的深度相机返回值有可能直接是一个很长的字符串,海康则一般是一个 C类型数据 ,反正就是一个结构体变量(一个指向储存着特定二维结构信息的指针))
print("en图像类型",stFrameData.stImageData[i].enImageType)
print("en图像类型十六进制:", hex(stFrameData.stImageData[i].enImageType))
print("n数据长度", stFrameData.stImageData[i].nDataLen)
print("n帧数", stFrameData.stImageData[i].nFrameNum)
print("n高度", stFrameData.stImageData[i].nHeight)
print("n保留(类型)", type(stFrameData.stImageData[i].nReserved))
print("n保留", stFrameData.stImageData[i].nReserved)
print("n时间戳", stFrameData.stImageData[i].nTimeStamp)
print("n宽度", stFrameData.stImageData[i].nWidth)
print( "p数据(类型)",type(stFrameData.stImageData[i].pData))
print("p数据", stFrameData.stImageData[i].pData)
现在让我们来看看这两个的返回值分别是什么
2.1nReserved:
stFrameData.stImageData[i].nReserved
n保留(类型) <class ‘Mv3dRgbdImport.Mv3dRgbdDefine.c_byte_Array_16’>
n保留 <Mv3dRgbdImport.Mv3dRgbdDefine.c_byte_Array_16 object at 0x00000253BF6A8BC8>
可观察到关键词 Array 和 16,那么可能就是 可能是一个长度为 16 的字节数组类型,至于前面的 c 和 byte,那可能是c语言开发,返回字节。
因此以解析字节的方式进行类型解析
nReserved_data = np.array(stFrameData.stImageData[i].nReserved)
print("nReserved_data:" ,nReserved_data)
nReserved_data = list(stFrameData.stImageData[i].nReserved)
print("nReserved_data2 :", nReserved_data)
输出如下
nReserved_data: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
nReserved_data2 : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
可以看见还真是16个字节的数组,但是很明显不是我要的深度图数据
2.2pData:
stFrameData.stImageData[i].pData
p数据(类型) <class ‘Mv3dRgbdImport.Mv3dRgbdDefine.LP_c_ubyte’>
p数据 <Mv3dRgbdImport.Mv3dRgbdDefine.LP_c_ubyte object at 0x00000253BF6A8BC8>
关于LP_c_ubyte 是什么类型资料如下
LP_c_ubyte 是一个指针类型,通常在与 C 语言交互的过程中使用。它表示指向 c_ubyte 类型数据的指针。
c_ubyte 是 ctypes 库中定义的一种数据类型,它对应于 C 语言中的 unsigned char 类型,即无符号字节类型。
LP_c_ubyte 是 ctypes 库中的一个别名,它表示一个指向 c_ubyte 类型数据的指针。在与 C 语言进行交互时,可以使用
LP_c_ubyte 类型来表示指向字节数组的指针。
翻译一些,说人话就是 stFrameData.stImageData[i].pData 是个指针(不了解指针的同学,可以理解成 是一个储存有目标数据储存地址号的一个特殊变量,我们可以通过该变量找到目标数据 )
于是我们可以这样写,使用 contents 方法
在Python中,contents 是ctypes库中指针对象的属性之一。contents属性用于访问指针所指向的内存区域中的值。
pData_data = np.array(stFrameData.stImageData[i].pData.contents)
print("pData_data:",pData_data)
输出:
pData_data: 0
然后很明显,0 是个屁的深度相机的返回数据,根据经验,返回的深度数据应该是一串字符有或者是一个很大的二维矩阵,然后才能处理成深度图或者点云图,所以这里应该是使用 **np.ctypeslib.as_array()**方法
我这里说下两者的区别: contents 方法只返回指针变量下的数据区第一个地址的数据,而np.ctypeslib.as_array方法会顺着第一个往下遍历,遍历的长度则由之前获得的 width 和 height 决定,如下
width = stFrameData.stImageData[i].nWidth
height = stFrameData.stImageData[i].nHeight
print("-"*20)
print(type(stFrameData.stImageData[i].pData))
print(stFrameData.stImageData[i].pData)
data = np.ctypeslib.as_array(stFrameData.stImageData[i].pData, shape=(height, width))
print("获得转换后的图像数据 data : ", data)
image = cv2.cvtColor(data, cv2.COLOR_GRAY2BGR)
# 保存图像
now = datetime.now()
timestamp = now.strftime("%Y_%m_%d_%H_%M_%S")
timestamp = timestamp + "_" + str(i)
cv2.imwrite("img_out/" + timestamp + ".jpg", image)
print("保存图像名称: ", timestamp)
print("当前图像类型(十六进制格式): ", hex(stFrameData.stImageData[i].enImageType) )print("*"*50)
输出:
深度图和rgb图还都是这个接口一起发出来的,只能说易读性很不好。
np.ctypeslib.as_array()
函数将指针转换为NumPy数组时,它会根据指针所指向的地址找到NumPy数组的起始位置,并从该地址开始遍历,将连续的内存块解释为NumPy数组的元素。而 stFrameData.stImageData[i].pData.contents 返回的是指针
stFrameData.stImageData[i].pData 指向的地址上存储的数据。它提供了指针所指向的内存位置的内容,通常是一个
C/C++ 数据类型的对象。因此,在正确配置和使用的情况下,stFrameData.stImageData[i].pData.contents
应该返回指针所指向的内存位置上存储的数据。通过使用 np.ctypeslib.as_array() 函数,我们可以将指针直接转换为NumPy数组,并正确解释指针所指向的内存数据。
四.其他
4.1 dll文件的生成
通过将C++文件或者C文件编译后获得即可,例如之前的
class A():a_num = 1111a_string = "AAAAAAAAA"def A_fun(self):print("这是A函数")def A_add_1(self, num):return num+1
等效上面的在C语言下的 A.c 文件代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT
#endiftypedef struct {int a_num;char a_string[10];
} A;DLL_EXPORT void A_fun(A* self) {printf("这是A函数\n");
}DLL_EXPORT int A_add_1(A* self, int num) {return num + 1;
}DLL_EXPORT A* A_new() {A* self = (A*)malloc(sizeof(A));self->a_num = 1111;strcpy(self->a_string, "AAAAAAAAA");return self;
}DLL_EXPORT void A_del(A* self) {free(self);
}
然后使用gcc编译成dll或者so文件
gcc -shared -o A.dll A.c
然后再调用即可
import ctypes# 加载 DLL 文件
dll = ctypes.CDLL("A.dll")# 定义函数的返回类型和参数类型
dll.A_add_1.restype = ctypes.c_int
dll.A_add_1.argtypes = [ctypes.c_void_p, ctypes.c_int]# 创建 A 类的实例
class A(ctypes.Structure):_fields_ = [("a_num", ctypes.c_int),("a_string", ctypes.c_char * 10)]# 调用 A_new 函数创建实例
dll.A_new.restype = ctypes.POINTER(A)
a_ptr = dll.A_new()
a = a_ptr.contents# 调用 A_add_1 函数
num = 5
result = dll.A_add_1(ctypes.byref(a), num)
print("Result:", result)# 获取 a_num 的值
a_num = a.a_num
print("a_num:", a_num)# 释放实例
dll.A_del(a_ptr)
4.2 海康MV-DLS600P 深度图与黑白图采集主代码
# -- coding: utf-8 --
import threading
from Mv3dRgbdImport.Mv3dRgbdApi import *
from Mv3dRgbdImport.Mv3dRgbdDefine import *
import msvcrt
import ctypes
import time
import os
import numpy as np
from Mv3dRgbdImport.Mv3dRgbdDefine import DeviceType_Ethernet, DeviceType_USB, MV3D_RGBD_FLOAT_EXPOSURETIME, \ParamType_Float, CoordinateType_Depth
import cv2
from datetime import datetimeg_bExit = False
def work_thread(camera=0,pdata=0,nDataSize=0):while True:stFrameData=MV3D_RGBD_FRAME_DATA()ret=camera.MV3D_RGBD_FetchFrame(pointer(stFrameData), 1000)if ret == 0:for i in range(0, stFrameData.nImageCount):# if stFrameData.stImageData[i].enImageType == MV3D_RGBD_ImageType.Normal:width = stFrameData.stImageData[i].nWidthheight = stFrameData.stImageData[i].nHeightprint("-"*20)print(type(stFrameData.stImageData[i].pData))print(stFrameData.stImageData[i].pData)data = np.ctypeslib.as_array(stFrameData.stImageData[i].pData, shape=(height, width))print("获得转换后的图像数据 data : ", data)image = cv2.cvtColor(data, cv2.COLOR_GRAY2BGR)# 保存图像now = datetime.now()timestamp = now.strftime("%Y_%m_%d_%H_%M_%S")timestamp = timestamp + "_" + str(i)cv2.imwrite("img_out/" + timestamp + ".jpg", image)print("保存图像名称: ", timestamp)print("当前图像类型(十六进制格式): ", hex(stFrameData.stImageData[i].enImageType) )print("*"*50)# cv2.imshow("Image", image)# cv2.waitKey(1)else:print("no data[0x%x]" % ret)if g_bExit == True:break# 触发线程 5s触发一次
def work_thread_trigger(cam=0, pData=0, nDataSize=0):while True:time.sleep(5)ret = cam.MV3D_RGBD_SoftTrigger()if 0 == ret:print ("MV3D_RGBD_SoftTrigger success")else:print ("MV3D_RGBD_SoftTrigger failed[0x%x]" % ret)if g_bExit == True:breakif __name__ == "__main__":nDeviceNum=ctypes.c_uint(0)nDeviceNum_p=byref(nDeviceNum)ret=Mv3dRgbd.MV3D_RGBD_GetDeviceNumber(DeviceType_Ethernet | DeviceType_USB, nDeviceNum_p) #获取设备数量if ret!=0:print("MV3D_RGBD_GetDeviceNumber fail! ret[0x%x]" % ret)os.system('pause')sys.exit()if nDeviceNum==0:print("find no device!")os.system('pause')sys.exit()print("Find devices numbers:", nDeviceNum.value)stDeviceList = MV3D_RGBD_DEVICE_INFO_LIST();net = Mv3dRgbd.MV3D_RGBD_GetDeviceList(DeviceType_Ethernet | DeviceType_USB, pointer(stDeviceList.DeviceInfo[0]), 20, nDeviceNum_p)for i in range(0, nDeviceNum.value):print("\ndevice: [%d]" % i)strModeName = ""for per in stDeviceList.DeviceInfo[i].chModelName:strModeName = strModeName + chr(per)print("device model name: %s" % strModeName)strSerialNumber = ""for per in stDeviceList.DeviceInfo[i].chSerialNumber:strSerialNumber = strSerialNumber + chr(per)print("device SerialNumber: %s" % strSerialNumber)# 创建相机示例camera=Mv3dRgbd()nConnectionNum = 0# 打开设备ret = camera.MV3D_RGBD_OpenDevice(pointer(stDeviceList.DeviceInfo[int(nConnectionNum)]))if ret != 0:print ("MV3D_RGBD_OpenDevice fail! ret[0x%x]" % ret)os.system('pause')sys.exit()# 开始取流ret=camera.MV3D_RGBD_Start()if ret != 0:print ("start fail! ret[0x%x]" % ret)camera.MV3D_RGBD_CloseDevice()os.system('pause')sys.exit()# 获取图像线程try:hthreadhandle=threading.Thread(target=work_thread,args=(camera,None,None))hthreadhandle.start()except:print("error: unable to start thread")try:hthreadhandle_trigger= threading.Thread(target=work_thread_trigger, args=(camera, None, None))hthreadhandle_trigger.start()except:print("error: unable to start thread")#msvcrt.getch()os.system('pause')g_bExit = Truehthreadhandle.join()hthreadhandle_trigger.join()# 停止取流ret=camera.MV3D_RGBD_Stop()if ret != 0:print ("stop fail! ret[0x%x]" % ret)os.system('pause')sys.exit()# 销毁句柄ret=camera.MV3D_RGBD_CloseDevice()if ret != 0:print ("CloseDevice fail! ret[0x%x]" % ret)os.system('pause')sys.exit()sys.exit()
相关文章:

python使用dir()函数获取对象中可用的属性和方法(看不到python源码又想知道怎么调用,DLL调用分析,SDK二次开发技巧)
有时候调用一些SDK,但是人家又是封装成dll文件形式调用的,这时没法看源码,也不想看其对应的开发文档(尤其有些开发文档写得还很难懂,或者你从某个开源社区拿过来,就根本没找到开发文档)…...

【MySQL系列】SQL语句入门(创建删除操作)、字符集和数据类型详解
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...

谈谈召回率(R值),准确率(P值)及F值
通俗解释机器学习中的召回率、精确率、准确率,一文让你一辈子忘不掉这两个词 赶时间的同学们看这里:提升精确率是为了不错报、提升召回率是为了不漏报 先说个题外话,暴击一下乱写博客的人,网络上很多地方分不清准确率和精确率&am…...

【脚本推荐】网页字体渲染插件
下图是三种网页字体增强的效果对比。 **SUM:**前面两个都是通过脚本运行,而最后一个是通过扩展插件;中间的脚本(字体渲染)效果是最好的,可惜输入框没有效果,也就意味着如果现在网页上写写学习笔…...
c++——c/c++中的static和const
C语言和c中的static关键字与const关键字 static: //改变存储区域,限制作用域 ①、改变存储区域: 在不同的上下文中,static 关键字可以用于改变变量或函数的存储区域。在函数内部,static 用于将局部变量的生存期从函数…...
解决git:‘remote-http‘ 不是一个 git 命令错误提示
Jenkins使用Maven构建工程时,设置Git源码管理时报错: Failed to connect to repository : Command “/usr/local/git/bin/git ls-remote -h – http://192.168.1.35/root/javademo.git HEAD” returned status code 128: stdout: stderr: git:…...

深度学习入门-3-计算机视觉-卷积神经网络
一、计算机视觉 1.概述 计算机视觉作为一门让机器学会如何去“看”的学科,具体的说,就是让机器去识别摄像机拍摄的图片或视频中的物体,检测出物体所在的位置,并对目标物体进行跟踪,从而理解并描述出图片或视频里的场…...
前端面试:【闭包】JavaScript世界的神秘法术
嘿,尊敬的代码探险家!欢迎来到JavaScript的奇妙世界,今天我们将探索一种神秘的魔法,那就是闭包。闭包,听起来像是一个古老的咒语,实际上,它是编程中的一个重要概念,让你能够创造出强…...

Ubuntu20 ctrl+alt+T无法打开终端
事情是这样的,某天改了下python版本,发现linux默认打开终端的快捷键ctrlaltT寄了,网上给出的都是修改快捷键不出意外肯定没用 但是幸好我们是会分析的,我看到,很多回答说新增一个快捷键运行的命令是gnome-terminal&…...

leetcode 387.字符串中第一个唯一字符
⭐️ 题目描述 🌟 leetcode链接:https://leetcode.cn/problems/first-unique-character-in-a-string/description/ 思路: 比较优的方式使用相对映射记录的方式。在 ASCII 表中小写字母 -97 就是 0 - 25。在依次从前遍历查找即可。需要注意的…...

【三次握手】TCP三次握手由入门到精通(完整版)
⬜⬜⬜ 🐰🟧🟨🟩🟦🟪(*^▽^*)欢迎光临 🟧🟨🟩🟦🟪🐰⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu &am…...
Java 异步计算
CompletableFuture(可完成的Future) 一个可完成的Future,在我们调用他的get方法的时候,他会阻塞等待这个任务完成来获取他的结果。 当然也可以为这个任务注册一些回调,类似于完成时,出现异常时,…...

【FAQ】调用视频汇聚平台EasyCVR的iframe地址,视频无法播放的原因排查
有用户反馈,在调用iframe地址后嵌入用户自己的前端页面,视频无法播放并且要求登录。 安防监控视频汇聚平台EasyCVR基于云边端一体化架构,具有强大的数据接入、处理及分发能力,可提供视频监控直播、云端录像、视频云存储、视频集中…...

⛳ TCP 协议面试题
目录 ⛳ TCP 协议面试题🐾 一、为什么关闭连接的需要四次挥⼿,⽽建⽴连接却只要三次握⼿呢?🏭 二、为什么连接建⽴的时候是三次握⼿,可以改成两次握⼿吗?👣 三、为什么主动断开⽅在TIME-WAIT状态…...
C 语言的字符串函数 puts()
属于标准库 <stdio.h> 函数原型: int puts(const char *str) str – 这是要被写入的 C 字符串. 如果成功, 该函数返回一个非负值为字符串长度 (包括末尾的 \0), 如果发生错误则返回 EOF. 作用: puts() 函数只显示字符串, 把一个字符串写入到标准输出 stdout, 直到空…...
Flutter如何知道页面/组件可见?
在以前项目中,onPageShow和onPageHide由开源框架flutter_boost提供,在此次项目中,创新性的采用了fusion框架,fusion框架同样提供了类似的方法,但在实践中发现,当flutter页面相互replace或者多次pop页面后,onPageShow不会调用,这就导致了诸多bug,于是,需要探索如何了解…...
【MySQL】如何使用Named Pipe协议(Windows)连接MySQL数据库
文章目录 【MySQL】如何使用Named Pipe协议(Windows)连接MySQL数据库连接MySQL的协议使用Named Pipe协议(Windows)连接MySQL步骤1:确认MySQL服务器已启用Named Pipe连接启动Named Pipe连接方法 步骤2:客户端使用Named Pipe连接MySQL服务器。例1ÿ…...
【c++】c++的一些技术操作
pthread_create 的第三个参数,为函数指针,指向处理线程函数的地址。该函数,要求为静态函数。如果处理线程函数为类成员函数时,需要将其设置为静态成员函数。C静态成员函数访问非静态成员 https://blog.csdn.net/yueguangmuyu/arti…...

JS中对象数组深拷贝方法
structuredClone() JavaScript 中提供了一个原生 API 来执行对象的深拷贝:structuredClone。它可以通过结构化克隆算法创建一个给定值的深拷贝,并且还可以传输原始值的可转移对象。 当对象中存在循环引用时,仍然可以通过 structuredClone()…...

2022数学建模国赛C题官网展示论文C155论文复现
2022数学建模国赛C题C155论文复现 1.内容比对2.第一问第二小问复现代码2.1 页表合并2.2 数据的正态性检验2.2.1数据的正态性检验效果图 2.3不满足正态性,进行中心化对数比变换2.3.1 核心步骤-inf用0值替换2.3.2中心化对数比变换效果图 2.4描述性统计2.5 箱线图绘制 …...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...