我试图用opencv捕获两个rtsp流,然后将它们提供给一个简单的flask服务器。当只使用opencv时,我可以同时显示两个流,但是当我尝试通过烧瓶显示它时,它只会选择其中一个流并将其显示两次。
这是原始创作者blog
这是我的烧瓶代码:
<table border="1">
<tbody>
<tr>
<th>model</th>
<td>XS</td>
<td>X </td>
</tr>
<tr>
<th>Memory size</th>
<td>256gb</td>
<td>125gb</td>
</tr>
<tr>
<th>ram</th>
<td> 4GB</td>
<td> 3GB</td>
</tr>
<tr>
<th>price</th>
<td> 499</td>
<td>999 </td>
</tr>
<tr>
<th> store</th>
<td> switch</td>
<td> machine</td>
</tr>
</tbody>
</table>
这是camera_opencv文件
#!/usr/bin/env python
from importlib import import_module
import os
from flask import Flask, render_template, Response
# import camera driver
'''
if os.environ.get('CAMERA'):
Camera = import_module('camera_' + os.environ['CAMERA']).Camera
else:
from camera import Camera
'''
#
from camera_opencv import Camera1, Camera2
app = Flask(__name__)
@app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
def gen(camera):
"""Video streaming generator function."""
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed1')
def video_feed1():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera1()),
mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/video_feed2')
def video_feed2():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera2()),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', threaded=True, port=8888)
基本相机文件
import cv2
from base_camera import BaseCamera
class Camera1(BaseCamera):
video_source = 0
@staticmethod
def set_video_source(source):
Camera1.video_source = source
@staticmethod
def frames():
camera = cv2.VideoCapture(Camera1.video_source)
if not camera.isOpened():
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img = camera.read()
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
class Camera2(BaseCamera):
video_source = 1
@staticmethod
def set_video_source(source):
Camera2.video_source = source
@staticmethod
def frames():
camera = cv2.VideoCapture(Camera2.video_source)
if not camera.isOpened():
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img = camera.read()
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
Index.html
import time
import threading
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
class CameraEvent(object):
"""An Event-like class that signals all active clients when a new frame is
available.
"""
def __init__(self):
self.events = {}
def wait(self):
"""Invoked from each client's thread to wait for the next frame."""
ident = get_ident()
if ident not in self.events:
# this is a new client
# add an entry for it in the self.events dict
# each entry has two elements, a threading.Event() and a timestamp
self.events[ident] = [threading.Event(), time.time()]
return self.events[ident][0].wait()
def set(self):
"""Invoked by the camera thread when a new frame is available."""
now = time.time()
remove = None
for ident, event in self.events.items():
if not event[0].isSet():
# if this client's event is not set, then set it
# also update the last set timestamp to now
event[0].set()
event[1] = now
else:
# if the client's event is already set, it means the client
# did not process a previous frame
# if the event stays set for more than 5 seconds, then assume
# the client is gone and remove it
if now - event[1] > 5:
remove = ident
if remove:
del self.events[remove]
def clear(self):
"""Invoked from each client's thread after a frame was processed."""
self.events[get_ident()][0].clear()
class BaseCamera(object):
thread = None # background thread that reads frames from camera
frame = None # current frame is stored here by background thread
last_access = 0 # time of last client access to the camera
event = CameraEvent()
def __init__(self):
"""Start the background camera thread if it isn't running yet."""
if BaseCamera.thread is None:
BaseCamera.last_access = time.time()
# start background frame thread
BaseCamera.thread = threading.Thread(target=self._thread)
BaseCamera.thread.start()
# wait until frames are available
while self.get_frame() is None:
time.sleep(0)
def get_frame(self):
"""Return the current camera frame."""
BaseCamera.last_access = time.time()
# wait for a signal from the camera thread
BaseCamera.event.wait()
BaseCamera.event.clear()
return BaseCamera.frame
@staticmethod
def frames():
""""Generator that returns frames from the camera."""
raise RuntimeError('Must be implemented by subclasses.')
@classmethod
def _thread(cls):
"""Camera background thread."""
print('Starting camera thread.')
frames_iterator = cls.frames()
for frame in frames_iterator:
BaseCamera.frame = frame
BaseCamera.event.set() # send signal to clients
time.sleep(0)
# if there hasn't been any clients asking for frames in
# the last 10 seconds then stop the thread
if time.time() - BaseCamera.last_access > 10:
frames_iterator.close()
print('Stopping camera thread due to inactivity.')
break
BaseCamera.thread = None
答案 0 :(得分:0)
所以我设法设法解决了。无论出于什么原因,我都无法解决,该应用无法单独处理多个流。
因此,我更改了相机类,并向其中添加了多个源,并使用numpy.hstack(())将两个帧合并在一起,从而返回了一个唯一的流。
如果有人可以在这里提供帮助,将不胜感激,因为我的方法根本无法扩展。
import cv2
from base_camera import BaseCamera
import numpy as np
class Camera(BaseCamera):
video_source1 = 0
video_source2 = 1
@staticmethod
def set_video_source(sources):
Camera.video_source1 = sources[0]
Camera.video_source2 = sources[1]
@staticmethod
def frames():
camera1 = cv2.VideoCapture(Camera.video_source1)
camera2 = cv2.VideoCapture(Camera.video_source2)
if not (camera1.isOpened() or camera2.isOpened()):
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img1 = camera1.read()
_, img2 = camera2.read()
img1 = cv2.resize(img1, (704, 396))
img2 = cv2.resize(img2, (704, 396))
img = np.hstack((img1, img2))
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
答案 1 :(得分:0)
根据博客,我使用两个生成器并将图像发送到index.html。而且我可以看到两个流。
def generate2():
# it is a generator
global outputFrame2, lock
while True:
with lock:
if outputFrame is None:
continue
(flag, encodedImage2) = cv2.imencode(".jpg", outputFrame2)
if not flag:
continue
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encodedImage2) + b'\r\n')
这是videofeed2
@app.route("/video_feed2")
def video_feed2():
return Response(generate2(),
mimetype = "multipart/x-mixed-replace; boundary=frame")