抓取帧 NTSC转USB加密狗,opencv2,python封装
背景:
我最近在玩Python和OpenCV2的结合。我想尝试一些想法,使用一个类似于汽车后视镜的广角摄像头。我从一辆报废的事故车上拆下了一个(它有四根线),根据线的颜色我做了一些猜测,把它连接起来,用USB A口给电源和接地线供电,并通过RCA接口传输NTSC复合信号。
我还买了一个NTSC转USB的转换器,像这个。
这个转换器附带了驱动程序和一些现成的VHS转DVD软件。
问题:
我使用网上常见的示例来测试它,像这样:
import numpy as np
import cv2
cam_index=0
cap=cv2.VideoCapture(cam_index)
print cap.isOpened()
ret, frame=cap.read()
#print frame.shape[0]
#print frame.shape[1]
while (cap.isOpened()):
ret, frame=cap.read()
#gray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
#release and close
cap.release()
cv2.destroyAllWindows()
这是命令行的输出:
True
Traceback (most recent call last):
File "C:/../cam_capture_.py", line 19, in <module>
cv2.imshow('frame', frame)
error: ..\..\..\..\opencv\modules\highgui\src\window.cpp:261: error: (-215) size.width>0 && size.height>0 in function cv::imshow
>>>
关键观察:
在控制面板中,USB设备显示为“OEM捕获”,在“声音、视频和游戏控制器”下。因此,它并没有被识别为简单的即插即用网络摄像头,没在“成像设备”下显示。
如果我打开VHS转DVD软件,我需要配置两个方面:
- 设置为复合信号
- 设置编码为NTSC 这样模拟摄像头的画面就能在VHS转DVD应用中正常显示。
当我在FLV(设备捕获)中打开设备视频通道时,设备流只是黑屏,但如果我在FLV流媒体播放的同时打开VHS转DVD软件,我就能在FLV中看到摄像头的画面,而VHS转DVD的画面仍然是黑屏。另一个重要的区别是,当在FLV中流媒体播放时,延迟大约有0.5秒,而在VHS转DVD中则没有。
当我运行“cam_capture.py”这个示例代码时,在某个运行时刻,我最终会遇到停止错误代码0x0000008e:
详细信息:
stop: 0x0000008E (0xC0000005, 0xB8B5F417, 0X9DC979F4, 0X00000000 )
ks.sys - Address B8B5F417 base at B8B5900, Datestamp...
beg mem dump
phy mem dump complete
5.如果我尝试打印frame.shape[0]或frame.shape[1],我会得到一个类型错误,提示我无法打印类型为None的内容。
6.如果我尝试其他的cam_index,结果总是为false。
总结:
在“控制面板”中,摄像头设备在“声音、视频和游戏控制器”下,而不是在“成像设备”下;
cam_index==零;
capture.isOpened()=真;
帧大小为None;
如果VHS转DVD正在运行并配置为复合NTSC,摄像头就能工作,虽然你不能通过截图看到图像,但相信我!;)
有没有什么方法可以初始化与这个设备的通信,比如模拟VHS转DVD的设置(复合+NTSC)?我本以为这只是一个简单的解决方案,但现在感觉我在做一些超出预期的事情。
任何建设性的见解、建议或纠正都非常欢迎!
谢谢
祝好
3 个回答
我也遇到了同样的问题。作为解决办法,我首先尝试了@user3380927提出的方案,结果确实有效。不过因为我不想依赖外部软件,所以我开始用Python中的opencv调整参数。
这段代码效果很好(你需要在第一次读取画面之前插入这些代码):
cam.set(cv2.CAP_FFMPEG,True)
cam.set(cv2.CAP_PROP_FPS,30)
所以,基本的摄像头读取完整代码如下:
import cv2
cam = cv2.VideoCapture(1)
cam.set(cv2.CAP_FFMPEG,True)
cam.set(cv2.CAP_PROP_FPS,30)
while(True):
ret,frame = cam.read()
cv2.imshow('frame',frame)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
cam.release()
cv2.destroyAllWindows()
之后你就可以像往常一样进行图像处理了。顺便提一下,这是我的配置:
- Opencv 3.1.0
- Python 2.7.5
- Windows 8.1
- Elgato视频捕捉设备(在设备管理器中也显示为声音、视频和游戏控制器)
虽然这个回答晚了几个月,但可能对你有帮助。我在一台Windows电脑上工作,安装了设备自带的驱动程序。我用和你问题里一样的代码,尝试了Somagic的Ezcap,结果也遇到了同样的错误。因为出现了“frame is None”的情况,我决定在这段代码周围加一个if语句,想看看是不是初始化出错了。把它放进循环里:
if frame is None:
print 0
else:
print 1
结果是:01110111111111111111111111111...
如果把frame = cap.read()放在循环上面,并注释掉,得到的结果是:00111111111111111...
所以对于我的捕捉设备来说,似乎从第5帧开始的所有帧都能正常捕捉。我不太清楚为什么会这样,但现在这可能是一个有用的解决办法。
免责声明:不幸的是,我的摄像头输入目前在一个辐射场里,所以我得等几周才能确认它是否真的能正常工作。不过,现在的图像是黑色的框(没有正确输入是正常的)。
好的,经过深入调查,最初的怀疑得到了确认。也就是说,因为NTSC的接收器并不是被当作一个图像设备来处理(它被视为一个视频控制器,类似于电视调谐器卡的模拟),所以虽然我们可以用cam_index=0来调用cv2.VideoCapture,但视频通道本身并没有传输,因为我们需要定义一堆参数。
- 编码方式
- 帧大小
- 每秒帧数等
问题在于,由于这个设备不被支持为图像设备,调用cv2.VideoCapture.set(parameter, value)似乎对原始视频流没有任何影响。
我没有找到解决方案,但我找到了一种变通办法。网上似乎有很多选项。可以搜索关键词“DV转网络摄像头”或者“摄像机作为网络摄像头”。
我使用了DVdriver(http://www.trackerpod.com/TCamWeb/download.htm),我用的是试用版,因为我比较节省!
为什么它有效?
据我了解,DVdriver从被设置为视频控制器的设备中接收数据(类似于从“Windows Movie Maker”或ffmpeg捕获),然后通过“fairydust”将帧输出到cam_index=0(假设没有其他摄像头连接),作为一个“图像设备”的网络摄像头。
总结
简单来说,使用DVdriver或类似的软件。
我找到了一种变通办法,但我真的想从基本原理理解它,并可能在Python中生成类似的NTSC接收器初始化,而不依赖其他软件。不过在那之前,希望这能帮助到那些也在苦苦挣扎或者认为这是硬件问题的人。
最后留给你们一些贝克特的话:尝试过。失败过。没关系。再试一次。再失败一次。失败得更好。(!)