在当前的 flask 项目中,我试图流式传输两个实时视频,这听起来很简单。问题是我只有一个视频源(相机)。目的是拥有两个视频流:一个不做任何修改,另一个应用人脸检测。如果用户希望进行人脸检测,则通过单击按钮将其摄像机 View 切换为应用了人脸检测的视频流。如果用户不想拥有它,那么他会看到没有它的信息流。重要的是-多个用户可以一次查看流。整个程序可在RPi 4B 4gb上运行。
我有一个CamerasPool类:
from .CameraHandler import CameraHandler
import cv2
class CamerasPool:
def __init__(self):
self.__cameras = []
def registerCamera(self, id, detection):
self.__cameras.append(CameraHandler(id, cv2.VideoCapture(0), detection))
print('Camera registered')
def getCamWithParameters(self, detection):
camera = None
for cam in self.__cameras:
if cam.getDetectionState() == detection:
camera = cam
break
return camera
和CamerasHandler类:import cv2
from time import sleep
class CameraHandler():
def __init__(self, id, cam, detectionState):
self.__id = id
self.__cam = cam
self.__current_frame = None
self.__shouldDetect = detectionState
print(f'Camera created with id {id} created')
def __del__(self):
self.__cam.release()
def getDetectionState(self):
return self.__shouldDetect
def __detectFace(self, img):
faces, confidences = cv.detect_face(img)
for face in faces:
(startX, startY) = face[0], face[1]
(endX, endY) = face[2], face[3]
cv2.rectangle(img, (startX, startY), (endX, endY), (0, 255, 0), 2)
return img
def __getFrame(self):
rval, frame = self.__cam.read()
if rval:
frame = cv2.resize(frame, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
try:
if self.__shouldDetect:
frame = self.__detectFace(frame)
except:
print('Face detection exception')
(flag, encodedImage) = cv2.imencode(".jpg", frame)
self.__current_frame = bytearray(encodedImage)
def gen(self):
while True:
self.__getFrame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + self.__current_frame + b'\r\n')
我正在尝试创建相机,如下所示:# Create two cameras
print('Before cameras creation')
camerasPool = CamerasPool()
print('After cameras pool creation')
camerasPool.registerCamera(0, False)
camerasPool.registerCamera(1, True)
print('Created both cameras')
如您在CamerasPool类中看到的那样,我正在创建像self.__cameras.append(CameraHandler(id, cv2.VideoCapture(0), detection))
这样的camera对象,该对象创建了两个想要访问同一资源的对象-camera。当我启动整个程序时,可以看到以下输出:
* Serving Flask app "server/" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://192.168.0.151:7070/ (Press CTRL+C to quit)
* Restarting with stat
Before cameras creation
After cameras pool creation
* Debugger is active!
* Debugger PIN: 196-285-435
Before cameras creation
After cameras pool creation
程序卡住,仅此而已。在输出中,我还应该看到Camera created with id 0 created
和Camera created with id 1 created
,但是据我所知,它们还没有创建-程序卡住在这个陡峭的地方。我想问题出在两个VideoCapture对象。有人可以帮我解决这个问题吗?也许还有其他解决方案,如何从一台摄像机获得两个流?
此致,
皮特
最佳答案
由于您只有一台摄像机,因此无法实例化两个CamerasPool
对象。但是您可以做的是:
CamerasPool
的实现,使其成为自己的线程,并且不会阻止python应用程序的执行。该类的目的是简单地从相机读取帧,为每个帧制作一个副本,并在两个单独的put()
对象中对其进行queue
编码。队列在程序中应该是全局的,以便其他线程可以同时访问这些线程,这些线程需要并发运行以处理数据并对其进行流传输。 VideoStream
,负责处理来自特定get()
的queue
帧,对其进行处理并进行流式处理。处理意味着您要在将帧流式传输到网络之前对其进行任何处理:转换为灰度,绘制矩形,检测面部等。此类也需要在单独的线程中运行,并且构造函数需要接收两个参数:第一个指示应该使用两个全局队列中的哪个;第二个参数指示在流传输之前是否应该处理这些帧; 如果您正在寻找有关如何使用多线程从相机中检索帧并将其存储在队列中的代码示例check this answer,特别是该部分说明:
请记住,您的应用程序将具有4个线程:
CamerasPool
的那个; VideoStream
对象;