当前位置: 首页 > news >正文

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()

相关文章:

python使用dir()函数获取对象中可用的属性和方法(看不到python源码又想知道怎么调用,DLL调用分析,SDK二次开发技巧)

有时候调用一些SDK&#xff0c;但是人家又是封装成dll文件形式调用的&#xff0c;这时没法看源码&#xff0c;也不想看其对应的开发文档&#xff08;尤其有些开发文档写得还很难懂&#xff0c;或者你从某个开源社区拿过来&#xff0c;就根本没找到开发文档&#xff09;&#xf…...

【MySQL系列】SQL语句入门(创建删除操作)、字符集和数据类型详解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

谈谈召回率(R值),准确率(P值)及F值

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

【脚本推荐】网页字体渲染插件

下图是三种网页字体增强的效果对比。 **SUM&#xff1a;**前面两个都是通过脚本运行&#xff0c;而最后一个是通过扩展插件&#xff1b;中间的脚本&#xff08;字体渲染&#xff09;效果是最好的&#xff0c;可惜输入框没有效果&#xff0c;也就意味着如果现在网页上写写学习笔…...

c++——c/c++中的static和const

C语言和c中的static关键字与const关键字 static&#xff1a; //改变存储区域&#xff0c;限制作用域 ①、改变存储区域&#xff1a; 在不同的上下文中&#xff0c;static 关键字可以用于改变变量或函数的存储区域。在函数内部&#xff0c;static 用于将局部变量的生存期从函数…...

解决git:‘remote-http‘ 不是一个 git 命令错误提示

Jenkins使用Maven构建工程时&#xff0c;设置Git源码管理时报错&#xff1a; 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&#xff1a…...

深度学习入门-3-计算机视觉-卷积神经网络

一、计算机视觉 1.概述 计算机视觉作为一门让机器学会如何去“看”的学科&#xff0c;具体的说&#xff0c;就是让机器去识别摄像机拍摄的图片或视频中的物体&#xff0c;检测出物体所在的位置&#xff0c;并对目标物体进行跟踪&#xff0c;从而理解并描述出图片或视频里的场…...

前端面试:【闭包】JavaScript世界的神秘法术

嘿&#xff0c;尊敬的代码探险家&#xff01;欢迎来到JavaScript的奇妙世界&#xff0c;今天我们将探索一种神秘的魔法&#xff0c;那就是闭包。闭包&#xff0c;听起来像是一个古老的咒语&#xff0c;实际上&#xff0c;它是编程中的一个重要概念&#xff0c;让你能够创造出强…...

Ubuntu20 ctrl+alt+T无法打开终端

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

leetcode 387.字符串中第一个唯一字符

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

【三次握手】TCP三次握手由入门到精通(完整版)

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…...

Java 异步计算

CompletableFuture&#xff08;可完成的Future&#xff09; 一个可完成的Future&#xff0c;在我们调用他的get方法的时候&#xff0c;他会阻塞等待这个任务完成来获取他的结果。 当然也可以为这个任务注册一些回调&#xff0c;类似于完成时&#xff0c;出现异常时&#xff0c;…...

【FAQ】调用视频汇聚平台EasyCVR的iframe地址,视频无法播放的原因排查

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

⛳ TCP 协议面试题

目录 ⛳ TCP 协议面试题&#x1f43e; 一、为什么关闭连接的需要四次挥⼿&#xff0c;⽽建⽴连接却只要三次握⼿呢&#xff1f;&#x1f3ed; 二、为什么连接建⽴的时候是三次握⼿&#xff0c;可以改成两次握⼿吗&#xff1f;&#x1f463; 三、为什么主动断开⽅在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&#xff1a;确认MySQL服务器已启用Named Pipe连接启动Named Pipe连接方法 步骤2&#xff1a;客户端使用Named Pipe连接MySQL服务器。例1&#xff…...

【c++】c++的一些技术操作

pthread_create 的第三个参数&#xff0c;为函数指针&#xff0c;指向处理线程函数的地址。该函数&#xff0c;要求为静态函数。如果处理线程函数为类成员函数时&#xff0c;需要将其设置为静态成员函数。C静态成员函数访问非静态成员 https://blog.csdn.net/yueguangmuyu/arti…...

JS中对象数组深拷贝方法

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

2022数学建模国赛C题官网展示论文C155论文复现

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

阿里云 K8s PVC 绑定 StorageClass 申领 PV 失败

错误场景: 因为阿里云没有默认的 StorageClass 我也懒得更新&#xff0c;所以就创建了一个类型是云盘的 StorageClass。 但是在创建 PVC 之后发现一直是 Pending 状态就查询了一下日志&#xff0c;然后看到很多下面这种错误 liuduiMacBookM1Pro ~ % kubectl describe pvc graf…...

php数组

php数组是什么&#xff1f; 可以使用单个变量名存储多个不同类型的数据的特殊变量&#xff0c;这就是php数组。 php数组就是一个特殊的变量&#xff0c;它允许存储多个任意类型的数据。 创建数组 php数组有两种类型&#xff0c;分为索引数组和关联数组。 创建数组的方法有三种…...

构造不包含字母和数字的webshell

构造不包含字母和数字的webshell <?php echo "A"^""; ?> 输出的结果是字符"!“。之所以会得到这样的结果&#xff0c;是因为代码中对字符"A"和字符”"进行了异或操作。在PHP中&#xff0c;两个变量进行异或时&#xff0c;…...

中国大学生服务外包创新创业大赛丨借 AI 之力,助“记账”难题

一、中国大学生服务外包创新创业大赛 赛事介绍 中国大学生服务外包创新创业大赛&#xff0c;是响应国家关于鼓励服务外包产业发展、加强服务外包人才培养的相关战略举措与号召&#xff0c;举办的每年一届的全国性竞赛。 大赛均由中华人民共和国教育部、中华人民共和国商务部…...

MacOS 安装Redis并设置密码

在开发过程中&#xff0c;需要本地进行安装Redis进行测试&#xff0c;记录了下MacOS环境下安装Redis&#xff0c;以及设置密码。 Brew 安装 $ brew install redis启动服务 # 启动服务 brew services start redis # 关闭服务 brew services stop redis # 重启服务 brew servic…...

函数的参数作为引用

文章目录 1. num,list ,tuple2. list 作为默认值导致共享同一列表3. 防御可变参数4. 结论 1. num,list ,tuple 结论&#xff1a;num ,tuple 作为参数&#xff0c;自身不会因为函数的原因而改变&#xff0c;list 为可变量&#xff0c;会因为函数变而变。 测试 def f(a, b):a …...

【文化课学习笔记】【化学】非金属及其化合物

【化学】必修一&#xff1a;非金属及其化合物 硅及其化合物 硅单质 物理性质 单晶硅的结构与金刚石类似&#xff0c;为正四面体的立体网状结构。晶体中每个硅原子与其他四个硅原子相连接。\(1\mathrm{mol}\) 硅单质还有 \(\mathrm{2N_A}\) 个 \(\mathrm{Si-Si}\) 键&#xff1b…...

Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)

文章目录 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)前情提要客户端部分 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三) 前情提要 单例泛型类 using System.Collections; using System.Collections.Generic; …...

步步向前,曙光已现:百度的大模型之路

大模型&#xff0c;是今年全球科技界最火热&#xff0c;最耀眼的关键词。在几个月的狂飙突进中&#xff0c;全球主要科技公司纷纷加入了大模型领域。中国AI产业更是开启了被戏称为“百模大战”的盛况。 但喧嚣与热闹之后&#xff0c;新的问题也随之而来&#xff1a;大模型的力量…...

常见的 Python 错误及其解决方案

此文整理了一些常见的 Python 错误及其解决方案。 1、SyntaxError: invalid syntax 说明&#xff1a;无效的语法是最常见的错误之一&#xff0c;通常是由于编写代码时违反了 Python 的语法规则。可能的原因&#xff1a; 忘记在 if、while、for 等语句后写冒号&#xff0c;或者…...

文章评论以及回复评论邮件通知(Go 搭建 qiucode.cn 之八)

要说到评论。无疑是博客应用的灵魂所在了,它也正是站长与博友、博友与博友之间互相交流的桥梁,倘若少了它,博客应用将变得暗淡无关,索然无味,恍如一具躺在床榻上的植物人,终究是无法与周边人言语的。 也正是有了评论,站长在该博客应用所发表的博文,博友才得以通过评论,…...

java面试基础 -- ArrayList 和 LinkedList有什么区别, ArrayList和Vector呢?

目录 基本介绍 有什么不同?? ArrayList的扩容机制 ArrayLIst的基本使用 ArrayList和Vector 基本介绍 还记得我们的java集合框架吗, 我们来复习一下, 如图: 可以看出来 ArrayList和LinkedList 都是具体类, 他们都是接口List的实现类. 但是他们底层的逻辑是不同的, 相信…...

matlab 点云最小二乘拟合空间直线(方法一)

目录 一、算法原理1、空间直线2、最小二乘法拟合二、代码实现三、结果展示四、可视化参考本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、空间直线 x...

详解junit

目录 1.概述 2.断言 3.常用注解 3.1.Test 3.2.Before 3.3.After 3.4.BeforeClass 3.5.AfterClass 4.异常测试 5.超时测试 6.参数化测试 1.概述 什么是单元测试&#xff1a; 单元测试&#xff0c;是针对最小的功能单元编写测试代码&#xff0c;在JAVA中最小的功能单…...

Nginx的安装及负载均衡搭建

一.Nginx的安装 1&#xff09;准备安装环境 yum install -y make gcc gcc-c pcre-devel pcre zlib zlib-devel openssl openssl-develPERE PCRE(Perl Compatible Regular Expressions)是一个Perl库&#xff0c;包括 perl 兼容的正则表达式库。 nginx的http模块使用pcre来解…...

JVM学习笔记(一)

1. JVM快速入门 从面试开始&#xff1a; 请谈谈你对JVM 的理解&#xff1f;java8 的虚拟机有什么更新&#xff1f; 什么是OOM &#xff1f;什么是StackOverflowError&#xff1f;有哪些方法分析&#xff1f; JVM 的常用参数调优你知道哪些&#xff1f; 内存快照抓取和MAT分…...

fastjson 序列化问题:Comparison method violates its general contract

fastjson 序列化问题&#xff1a;Comparison method violates its general contract 问题重现 今天在测试接口的时候&#xff0c;调用了Mybatis Plus 分页查询的接口&#xff0c;然后将查询的结果转换成 Json字符串的形式&#xff0c;结果报了这个错误&#xff1a; java.lang.…...

Angular安全专辑之二——‘unsafe-eval’不是以下内容安全策略中允许的脚本源

一&#xff1a;错误出现 这个错误的意思是&#xff0c;拒绝将字符串评估为 JavaScript&#xff0c;因为‘unsafe-eval’不是以下内容安全策略中允许的脚本源。 二&#xff1a;错误场景 testEval() {const data eval("var sum2 new Function(a, b, return a b); sum2(em…...

十一、Linux用户及用户组的权限信息如何查看?如何修改?什么是权限的数字序号?

目录&#xff1a; 1、认知权限信息 2、rwx&#xff1f; &#xff08;1&#xff09;总括&#xff1a; &#xff08;2&#xff09;r权限&#xff1a; &#xff08;3&#xff09;w权限&#xff1a; &#xff08;4&#xff09;x权限&#xff1a; 3、修改权限 &#xff08;1&a…...

ahooks.js:一款强大的React Hooks库及其API使用教程(二)

一、ahooks.js简介二、ahooks.js安装三、继续ahooks.js API的介绍与使用教程21. useLocalStorageState22. useSessionStorageState23. useClickAway24. usePersistFn25. useCreation26. useFullscreen27. useInViewport28. useInfiniteScroll29. usePagination30. useDynamicLi…...

ARM 配置晶振频率

文章目录 前言串口乱码问题定位内核修改晶振频率uboot 修改晶振频率番外篇 前言 上篇文章《ARM DIY 硬件调试》介绍了 DIY ARM 板的基础硬件焊接&#xff0c;包括电源、SOC、SD 卡座等&#xff0c;板子已经可以跑起来了。 但是发现串口乱码&#xff0c;今天就来解决串口乱码问…...

最强自动化测试框架Playwright(37)-网络

介绍 Playwright 提供 API 来监控和修改浏览器网络流量&#xff0c;包括 HTTP 和 HTTPS。页面执行的任何请求&#xff0c;包括 XHR 和获取请求&#xff0c;都可以被跟踪、修改和处理。 模拟接口 查看我们的 API 模拟指南&#xff0c;了解有关如何 模拟 API 请求&#xff0c…...

Ant Design Pro 前端脚手架 配置混合导航

Ant Design Pro脚手架 点击查看阅读 混合导航&#xff1a; 顶部导航和侧边栏导航实现联动效果&#xff0c;点击不同的顶部导航按钮会显示对应的子菜单项。 实现点&#xff1a; 1. 路由的配置 菜单展示 我们可以在 route 中进行 menu 相关配置&#xff0c;来决定当前路由是否…...

tcl学习之路(五)(Vivado时序约束)

1.主时钟约束 主时钟通常是FPGA器件外部的板机时钟或FPGA的高速收发器输出数据的同步恢复时钟信号等。下面这句语法大家一定不会陌生。该语句用于对主时钟的名称、周期、占空比以及对应物理引脚进行约束。 create_clock -name <clock_name> -periood <period> -wa…...

Hlang-中英双语言编程语言使用手册

文章目录 介绍Hlang基本使用下载配置环境变量特性中文关键字支持中文符号混合编程中文错误提示终端多行输入基本数据类型整数浮点数列表字符串基本操作变量定义逻辑判断基本运算条件判断循环函数介绍 Hlang是一款基于Python编写的支持中英文混合编程的动态语言。其简单易上手,…...

centos 7 安装docker

系统配置&#xff1a; CentOS关闭selinux sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config关闭防火墙(可选)或者放行相应端口 systemctl stop firewalld.service && systemctl disable firewalld.service配置内核IP 转发 net.ipv4.ip_forward1 dock…...

Spring环境搭建、SpringIOC容器基础、SpringDI基础

文章目录 Spring环境搭建、SpringIOC容器基础、SpringDI基础一、SpringIOC核心思想二、搭建Spring环境步骤三、SpringIOC容器使用步骤四、SpringIOC 总结五、SpringDI&#xff08;依赖注入&#xff09;1、基本概念2、实现方式&#xff08;1&#xff09;set 注入&#xff08;2&a…...

CentOS7.9手工配置静态网络流程

进入网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 配置 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" //static 配置静态网络 DEFROUTE"yes" IPV4_FAILURE_FATAL"no…...

JVM面试题-1

1、什么是JVM内存结构&#xff1f; jvm将虚拟机分为5大区域&#xff0c;程序计数器、虚拟机栈、本地方法栈、java堆、方法区&#xff1b; 程序计数器&#xff1a;线程私有的&#xff0c;是一块很小的内存空间&#xff0c;作为当前线程的行号指示器&#xff0c;用于记录当前虚拟…...

漫谈红黑树:红黑树的奇妙演化

漫谈红黑树&#xff1a;红黑树的奇妙演化 一、红黑树的提出二、红黑树性质的简单推导三、结论 博主简介 &#x1f4a1;一个热爱分享高性能服务器后台开发知识的博主&#xff0c;目标是通过理论与代码实践的结合&#xff0c;让世界上看似难以掌握的技术变得易于理解与掌握。技能…...