我正在使用Raspbian(Raspberry Pi 2)中的Python视频捕获脚本,我在使用Python绑定v4l2时遇到了麻烦,因为我没有成功地对缓冲区进行内存管理。
我需要的:
我尝试过的:
我读过的内容:
我的问题:
这是我在OpenCV上的(慢慢)工作示例:
import cv2
import time
video = cv2.VideoCapture(0)
print 'Starting video-capture test...'
t0 = time.time()
for i in xrange(100):
success, image = video.read()
ret, jpeg = cv2.imencode('.jpg',image)
t1 = time.time()
t = ( t1 - t0 ) / 100.0
fps = 1.0 / t
print 'Test finished. ' + str(t) + ' sec. per img.'
print str( fps ) + ' fps reached'
video.release()
在这里我用v4l2做了什么:
FRAME_COUNT = 5
import v4l2
import fcntl
import mmap
def xioctl( fd, request, arg):
r = 0
cond = True
while cond == True:
r = fcntl.ioctl(fd, request, arg)
cond = r == -1
#cond = cond and errno == 4
return r
class buffer_struct:
start = 0
length = 0
# Open camera driver
fd = open('/dev/video1','r+b')
BUFTYPE = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE
MEMTYPE = v4l2.V4L2_MEMORY_MMAP
# Set format
fmt = v4l2.v4l2_format()
fmt.type = BUFTYPE
fmt.fmt.pix.width = 640
fmt.fmt.pix.height = 480
fmt.fmt.pix.pixelformat = v4l2.V4L2_PIX_FMT_MJPEG
fmt.fmt.pix.field = v4l2.V4L2_FIELD_NONE # progressive
xioctl(fd, v4l2.VIDIOC_S_FMT, fmt)
buffer_size = fmt.fmt.pix.sizeimage
print "buffer_size = " + str(buffer_size)
# Request buffers
req = v4l2.v4l2_requestbuffers()
req.count = 4
req.type = BUFTYPE
req.memory = MEMTYPE
xioctl(fd, v4l2.VIDIOC_REQBUFS, req)
if req.count < 2:
print "req.count < 2"
quit()
n_buffers = req.count
buffers = list()
for i in range(req.count):
buffers.append( buffer_struct() )
# Initialize buffers. What should I do here? This doesn't work at all.
# I've tried with USRPTR (pointers) but I know no way for that in Python.
for i in range(n_buffers):
buf = v4l2.v4l2_buffer()
buf.type = BUFTYPE
buf.memory = MEMTYPE
buf.index = i
xioctl(fd, v4l2.VIDIOC_QUERYBUF, buf)
buffers[i].length = buf.length
buffers[i].start = mmap.mmap(fd.fileno(), buf.length,
flags = mmap.PROT_READ,# | mmap.PROT_WRITE,
prot = mmap.MAP_SHARED,
offset = buf.m.offset )
我将不胜感激任何帮助或建议。非常感谢!
只是为了在我刚刚发现的地方添加另一个选项,您也可以将V4L2后端与OpenCV一起使用。
您只需在VideoCapture构造函数中指定它。例如
cap = cv2.VideoCapture()
cap.open(0, apiPreference=cv2.CAP_V4L2)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 960)
cap.set(cv2.CAP_PROP_FPS, 30.0)
当没有明确指定时,OpenCV将经常使用另一个相机API(例如,gstreamer),这通常更慢且更麻烦。在这个例子中,我从限制在4-5 FPS到最高15到720p(使用Intel Atom Z8350)。
如果您希望将它与环形缓冲区(或其他内存映射缓冲区)一起使用,请查看以下资源:
为什么你不能使用Raspberry Distribution附带的python picamera lib
import io
import socket
import struct
import time
import picamera
# create socket and bind host
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('192.168.1.101', 8000))
connection = client_socket.makefile('wb')
try:
with picamera.PiCamera() as camera:
camera.resolution = (320, 240) # pi camera resolution
camera.framerate = 15 # 15 frames/sec
time.sleep(2) # give 2 secs for camera to initilize
start = time.time()
stream = io.BytesIO()
# send jpeg format video stream
for foo in camera.capture_continuous(stream, 'jpeg', use_video_port = True):
connection.write(struct.pack('<L', stream.tell()))
connection.flush()
stream.seek(0)
connection.write(stream.read())
if time.time() - start > 600:
break
stream.seek(0)
stream.truncate()
connection.write(struct.pack('<L', 0))
finally:
connection.close()
client_socket.close()
我自己找到了答案作为another question代码的一部分。这不是问题的主题,但在这个source code中你可以看到他如何在Python中使用mmap(第159行)。此外,我发现我不需要写权限。