我使用pyuvc访问uvc摄像头,但是发现pyuvc只支持了MJPEG的格式和GRAY格式。我在linux下通过v4l2-ctl查看,发现摄像头本身还支持YUV的格式,但是pyuvc解析出的帧格式则没有。后面通过阅读pyuvc的代码,发现libuvc本身没有限制YUV的格式,是pyuvc限制的。修改代码后重新编译whl,重新安装就可以了。
要修改的内容都在uvc_bindings.pyx中。
首先修改_supported_formats,增加对uvc.UVC_FRAME_FORMAT_YUYV和uvc.UVC_FRAME_FORMAT_ANY的支持。修改前后的对比如下:
然后在class Frame中增加一个获取原始buffer的接口:
@property
def data_buffer(self):
cdef np.uint8_t[::1] view = <np.uint8_t[:self._uvc_frame.data_bytes]>self._uvc_frame.data
return view
最后修改class Capture的get_frame()成员函数,让其在读取到MJPEG、GRAY之外的格式时,使用Frame类来存放帧数据:
if uvc_frame.frame_format == uvc.UVC_COLOR_FORMAT_MJPEG:
##check jpeg header
header_ok = turbojpeg.tjDecompressHeader2(
self.tj_context,
<unsigned char *>uvc_frame.data,
uvc_frame.data_bytes,
&j_width,
&j_height,
&jpegSubsamp
)
if not (
header_ok >= 0 and
uvc_frame.width == j_width and
uvc_frame.height == j_height
):
raise StreamError("JPEG header corrupt.")
out_frame_mjpeg = MJPEGFrame()
out_frame_mjpeg.tj_context = self.tj_context
out_frame_mjpeg.attach_uvcframe(uvc_frame=uvc_frame, copy=True)
frame = out_frame_mjpeg
elif uvc_frame.frame_format == uvc.UVC_COLOR_FORMAT_GRAY8:
# if uvc_frame.width * uvc_frame.height > uvc_frame.data_bytes:
# raise StreamError(
# f"Received too few bytes to fill {uvc_frame.width}x"
# f"{uvc_frame.height} GRAY8 image"
# )
out_frame_gray = Frame()
out_frame_gray.attach_uvcframe(uvc_frame=uvc_frame, copy=True)
frame = out_frame_gray
else:
# 这个分支是新增的
out_frame_gray = Frame()
out_frame_gray.attach_uvcframe(uvc_frame=uvc_frame, copy=True)
frame = out_frame_gray
代码变化如下:
else:
- raise NotImplementedError(f"Unsupported frame format {uvc_frame.frame_format}")
+ out_frame_gray = Frame()
+ out_frame_gray.attach_uvcframe(uvc_frame=uvc_frame, copy=True)
+ frame = out_frame_gray
在windows下编译pyuvc需要提前安装vsstudio,我装的是vsstudio2015,具体命令参考源码中的README.rst文件的描述:
pip install build delvewheel
git clone https://github.com/pupil-labs/pyuvc --recursive
cd pyuvc
scripts/download-deps-win.ps1 -DEPS_TMP_PATH tmp
$Env:DEPS_PATHS_LOC = "tmp/dep_paths.json"
python -m build -w # will create a wheel in dist/ folder; insert the wheel path below
python scripts/repair-wheels-win.py $Env:DEPS_PATHS_LOC <wheel location> wheelhouse
pip install wheelhouse/<wheel name>
在编译中我遇到的问题在delvewheel进行repair时报Unable to find library: msvcr100.dll【已解决】这篇文章中有介绍。
编译生成新的whl文件在源码的wheelhouse/目录下。在本地安装或者复制到其它环境下安装均可。
我的摄像头返回的是packaged格式的YUV420数据,我直接保存到磁盘文件中。
frame = cam.get_frame(timeout=0.001)
data_buffer = frame.data_buffer
with open(f"data_buffer{i}.yuy2",'wb') as f:
f.write(data_buffer)
也可以用opencv来转码。
delvewheel进行repair时报Unable to find library: msvcr100.dll【已解决】