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>

可观察到关键词 Array16,那么可能就是 可能是一个长度为 16 的字节数组类型,至于前面的 cbyte,那可能是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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/44029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记:Opencv实现图像特征提取算法SIFT

2023.8.19 为了在暑假内实现深度学习的进阶学习&#xff0c;特意学习一下传统算法&#xff0c;分享学习心得&#xff0c;记录学习日常 SIFT的百科&#xff1a; SIFT Scale Invariant Feature Transform, 尺度不变特征转换 全网最详细SIFT算法原理实现_ssift算法_Tc.小浩的博客…

2235.两整数相加:19种语言解法(力扣全解法)

【LetMeFly】2235.两整数相加&#xff1a;19种语言解法&#xff08;力扣全解法&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/add-two-integers/ 给你两个整数 num1 和 num2&#xff0c;返回这两个整数的和。 示例 1&#xff1a; 输入&#xff1a;num…

Seaborn数据可视化(一)

目录 1.seaborn简介 2.Seaborn绘图风格设置 21.参数说明&#xff1a; 2.2 示例&#xff1a; 1.seaborn简介 Seaborn是一个用于数据可视化的Python库&#xff0c;它是建立在Matplotlib之上的高级绘图库。Seaborn的目标是使绘图任务变得简单&#xff0c;同时产生美观且具有信…

【Git】分支管理

文章目录 一、理解分支二、创建、切换、合并分支三、删除分支四、合并冲突五、合并模式六、分支策略七、bug分支八、强制删除分支 努力经营当下 直至未来明朗&#xff01; 一、理解分支 HEAD指向的是master分支&#xff0c;master中指向的是最新一次的提交&#xff0c;也就是m…

Visual Studio 2019源码编译cpu版本onnxruntime

1.下载onnxruntime源码 源码地址&#xff1a;gitee 》https://gitee.com/mirrors/onnx-runtime github 》https://github.com/microsoft/onnxruntime git clone --recursive https://gitee.com/mirrors/onnx-runtime 2.安装anaconda并配置python环境 安装anaconda时记得勾选默…

CSS基础 知识点总结

一.CSS简介 1.1 CSS简介 ① CSS指的是层叠样式表&#xff0c;用来控制网页外观的一门技术 ② CSS发展至今&#xff0c;经历过CSS1.0 CSS2.0 CSS2.1 CSS3.0这几个版本&#xff0c;CSS3.0是CSS最新版本 1.2 CSS引入方式 ① 在一个页面引入CSS&#xff0c;共有三种方式 外部…

Ansible 进阶

Ansible 进阶 ⤴️Ansible 入门看这篇文章⤵️Ansible 实战看这篇文章 一.Ansible 中的 Playbook 1.1 Playbook 介绍 如下图&#xff0c;ansible 在整个管理过程中使用 playbook 的大体流程。 Playbook 中包含多个 role&#xff0c;每个 role 对应于在远程主机完成某个比较复…

2.创建小程序

创建 在开发工具中,选择小程序,点击加号 填写小程序信息,模板使用的是TS+Sass 编辑器的工作区 目录结构 项目使用的是ts的模板,目录结构和js的有一点差异,目录结构如下: miniprogram:小程序根目录 —pages:小程序页面目录 ——xxx:页面目录,一个页面对应一个目…

水果成篮(力扣)双指针滑动窗口 JAVA

你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而&#xff0c;农场的主人设定了一些严格的规矩&#xff0c;你必须按照要求采摘水果&…

华为手机Outlook手机APP无法登录邮箱,提示[2002]错误代码

近期遇到不少华为手机的Outlook APP无法登录邮箱Office365邮箱的案例&#xff0c;并且提示&#xff1a; 错误 出错了。[2002] 经测试&#xff0c;这应该是华为应用市场下载的Outlook版本有问题。 解决方法&#xff1a; 把Outlook卸载之后从微软官网重新下载官网版本去安装&am…

Creating a document in Overleaf

1、Uploading a project上传项目 This artcle provides a step-by-step guide showing how to create an Overleaf project by uploading a .zip file containing LaTeX files stored on your local computer 1、Create a .zip file containing your local files (images, bib…

redux的介绍、安装、三大核心与执行流程

redux的介绍、安装、三大核心与执行流程 一、redux的基本介绍二、redux的安装三、redux核心概念3.1 action3.2 reducer3.3 store 四、Redux代码执行流程五、加减案例练习 一、redux的基本介绍 redux中文官网Redux 是 React 中最常用的状态管理工具&#xff08;状态容器&#x…

基于深度学习创建-表情符号--附源码

表情符号深度学习概述 如今,我们使用多种表情符号或头像来表达我们的心情或感受。它们充当人类的非语言线索。它们成为情感识别、在线聊天、品牌情感、产品评论等的关键部分。针对表情符号驱动的故事讲述的数据科学研究不断增加。 从图像中检测人类情绪非常流行,这可能是由…

【数据结构】 单链表面试题讲解

文章目录 引言反转单链表题目描述示例&#xff1a;题解思路代码实现&#xff1a; 移除链表元素题目描述&#xff1a;示例思路解析&#xff1a; 链表的中间结点题目描述&#xff1a;示例&#xff1a;思路解析代码实现如下&#xff1a; 链表中倒数第k个结点题目描述示例思路解析&…

腾讯大佬用了8小时讲完的Python,整整315集,拿走不谢!

Python在近几年越来越受追捧&#xff0c;很多童鞋或者职场小伙伴想要提升技能-学习Python。 这是非常好的事情&#xff0c;但问题在于很多人不知道学Python做什么&#xff0c;所以什么零碎细末、艰难晦涩、长篇大论的都去看&#xff0c;很容易陷入学不下去的困境。必须要有针对…

小程序-uni-app:hbuildx uni-app 安装 uni-icons 及使用

一、官方文档找到uni-icons uni-app官网 二、下载插件 三、点击“打开HBuildX” 四、选择要安装的项目 五、勾选要安装的插件 六、安装后&#xff0c;项目插件目录 根目录uni_modules目录下增加uni-icons、uni-scss 七、引入组件&#xff0c;使用组件 <uni-icons type&qu…

十、Linux的root用户、用户和用户组的问题

目录 1、Linux的root用户 &#xff08;1&#xff09;基础 &#xff08;2&#xff09;如何进入root模式 &#xff08;3&#xff09;如何给普通用户配置root权限&#xff1f; 注意点&#xff1a; 配置方法&#xff1a; 2、用户/用户组问题 &#xff08;1&#xff09;用户/用…

pdf怎么合并在一起?这几个合并方法了解一下

pdf怎么合并在一起&#xff1f;在日常工作、学习和生活中&#xff0c;我们常常会遇到需要将多个PDF文件合并成一个文件的情况。比如&#xff0c;在学术论文写作中&#xff0c;我们可能需要将多篇论文合并成一个文件进行打印和提交。在工作中&#xff0c;我们可能需要将多个报告…

深入竞品:解读竞品分析的艺术与策略

引言&#xff1a;为何竞品分析至关重要&#xff1f; 在当今的产品环境中&#xff0c;市场变得越来越拥挤。每个角落都有新的创业公司试图创造下一个行业的颠覆者&#xff0c;同时也有成熟的巨头在不断地迭代和优化他们的产品。在这样的环境中&#xff0c;不了解您的竞争对手是…

学习笔记十七:node节点选择器,亲和性

node节点选择器&#xff0c;污点、容忍度、亲和性 node节点选择器nodeName&#xff0c;指定pod节点运行在哪个具体node上nodeSelector&#xff1a;指定pod调度到具有哪些标签的node节点上 亲和性node节点亲和性使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性使用…