数据采集
- 首先主板接入电脑后,自动识别成usb打印支持,usb应用很常见,但是想把这个数据读出来还是有点难度的。通过网上方法我们通过python的第三方库pyusb来实现读取。第三方库及其环境的安装自行搜索吧,这边就不加赘述了。
- 安装好之后需要用zadig修改我们的驱动软件,使用winusb这个Windows通用的驱动来让我们的python代码对接。这个软件也自行查找吧。
- 一切准备就绪后,我们就可以开始编程了。直接上代码
import usb.core
import usb.util
import sys
import threading
import time
#这俩ID记得改成自己的
VID=0x05a9
PID=0x8065
all_devs=usb.core.find(find_all=True)
for dev in all_devs:
print(dev)
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
print(intf)
write_ep = usb.util.find_descriptor(
intf,
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT
)
read_ep = usb.util.find_descriptor(
intf,
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN
)
def write_endpoint_thread():
while True:
try:
write_ep.write("123")
except:
print("write error")
def read_endpoint_thread():
count=[]
for i in range(200):
data = read_ep.read(643807)
size = len(data)
if size > 640000: #加个判断防止传输失败的包被读取
count.append(size)
with open('test'+str(i)+'.txt', 'wb') as f:
data.tofile(f) #写入到txt文件夹
def main():
r = threading.Thread(target=read_endpoint_thread)
w = threading.Thread(target=write_endpoint_thread)
r.start()
#w.start()#不需要写
r.join()
#w.join()#不需要写
dev.reset()
if __name__ == '__main__':
main()
- 这样我们就得到了许多的txt文件当然你也可以修改代码只读取一帧数据。
- 像这样直接打开TXT文件肯定是不能看的,这时我们需要把它用十六进制的格式打开。像我使用的是VSC中一个叫hexdump for VSCode的插件。打开后是这个样子的:
- 这样我们就可以对数据进行分析了。
数据分析
- 首先根据原本图形的大小为800400,所以如果是bmp格式的图像的话应该是800400*3个字节,此处只有640000个字节,所以平均每个像素仅有2个字节。由此我们可以查找常用的一些图片的存储格式,对比占用字节数来判断暂且(就是)推断为yuv中的UYVY。但是我们需要的只有640000个字节,但是他给了我们643780个字节,其中肯定有蹊跷。但是我们只能硬着头皮上。开头的那12个字节肯定有问题,去掉!然后从13个字节开始,将其转为rgb格式。得到了一个很奇怪的图。
- 可以看到上面有很多的点,可以怀疑一下这里有点东西。我们打开它,然后看一下这些点对应的像素位置。对应的大概位置是第1024个像素,对应的字节是第2048个字节。找到hex中的位置,可以看到
这里看到了一个有意思的地方,这12个字节和开头的12个字节有一定的相似,查找后面的每2048个字节,发现这些都很相似。那么我们可以推断一下这边的数据结构为12个字节的头带上2036个字节的图像数据。那么我们算一下他的数据量是否正确.
>>> 640000+640000//(2048-12)*12+12
643780
完美!那么接下来就是还原图片了。
还原成图
from numpy import *
from PIL import Image
def xianfu(x):
if(x>=0 and x<=255):
return x
elif(x<0):
return 0
else:
return 255
def readYuvFile(filename, width, height):
fp = open(filename, 'rb')
Y1 = zeros((height, width//2), uint8, 'C')
Y2 = zeros((height, width//2), uint8, 'C')
U = zeros((height, width//2), uint8, 'C')
V = zeros((height, width//2), uint8, 'C')
fp.read(12)
count=12
RGBarray=zeros((height, width,3), uint8, 'C')
for m in range(height):
for n in range(width//2):
# U[m, n] = ord(fp.read(1))
# Y1[m, n] = ord(fp.read(1))
# V[m, n] = ord(fp.read(1))
# Y2[m, n] = ord(fp.read(1))
y1 = ord(fp.read(1))
u = ord(fp.read(1))
y2 = ord(fp.read(1))
v = ord(fp.read(1))
count+=4
if(count%2048==0):
fp.read(12)
count+=12
r = (y1 + (u - 128) + ((104*(u - 128))>>8))
g = (y1 - (89*(v - 128)>>8) - ((183*(u - 128))>>8))
b = (y1 + (v - 128) + ((199*(v - 128))>>8))
RGBarray[m,n*2,0]=xianfu(r)
RGBarray[m,n*2,1]=xianfu(g)
RGBarray[m,n*2,2]=xianfu(b)
r = (y2 + (u - 128) + ((104*(u - 128))>>8))
g = (y2 - (89*(v - 128)>>8) - ((183*(u - 128))>>8))
b = (y2 + (v - 128) + ((199*(v - 128))>>8))
RGBarray[m,n*2+1,0]=xianfu(r)
RGBarray[m,n*2+1,1]=xianfu(g)
RGBarray[m,n*2+1,2]=xianfu(b)
fp.close()
return RGBarray
if __name__ == '__main__':
width = 800
height = 400
data = readYuvFile('test100.txt', width,
height)
print(data.shape)
im = Image.fromarray(data)
im.save('300.jpg')
- 使用以上代码,将之前的txt数据输入,转成rgb格式输出为图片。
- 由于是双目摄像头,每个摄像头像素为400*400所以图片分辨率较低但是图像基本看的清楚。解决这个问题花了好几天特此记录。(吐槽一下卖家不给资料。)
- 后面代码进行整合图片按帧组成视频输出显示。