Python 烧瓶用OpenCV冷冻

Python 烧瓶用OpenCV冷冻,python,python-3.x,opencv,flask,raspberry-pi,Python,Python 3.x,Opencv,Flask,Raspberry Pi,在我目前的flask项目中,我尝试流式传输两个现场视频,这听起来很简单。问题是我只有一个视频源(摄像头)。目的是有两个视频流:一个没有任何修改,另一个应用了人脸检测。如果用户希望进行人脸检测,则通过单击按钮,将为他设置的摄像头视图更改为流,该流应用了人脸检测。若用户不想拥有它,那个么他将看到并没有它的流。非常重要的是,多个用户可以同时查看流。整个程序在RPI4B4GB上工作 我有一门摄影课: from .CameraHandler import CameraHandler import cv2

在我目前的flask项目中,我尝试流式传输两个现场视频,这听起来很简单。问题是我只有一个视频源(摄像头)。目的是有两个视频流:一个没有任何修改,另一个应用了人脸检测。如果用户希望进行人脸检测,则通过单击按钮,将为他设置的摄像头视图更改为流,该流应用了人脸检测。若用户不想拥有它,那个么他将看到并没有它的流。非常重要的是,多个用户可以同时查看流。整个程序在RPI4B4GB上工作

我有一门摄影课:

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类中看到的,我正在创建这样的cameras对象
self.\uu cameras.append(CameraHandler(id,cv2.VideoCapture(0),detection))
,它创建了两个想要访问同一资源的对象-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
程序冻结,仅此而已。在输出中,我还应该看到创建了id为0的
摄像头
和创建了id为1的
摄像头,但据我所知,它们还没有创建-程序冻结在这个陡峭的位置。
我猜问题是因为两个视频捕获对象。有人能帮我解决这个问题吗?也许有其他的解决方案,如何从一个摄像头获得两个流

致以最良好的祝愿,
Piotr

您不能实例化两个
CamerasPool
对象,因为您只有一个摄影机。但你能做的是:

  • 更改
    CamerasPool
    的实现,使其成为自己的线程,并且不会阻止python应用程序的执行。该类的目的是简单地从相机读取帧,制作每个帧的副本,并将它们放入两个单独的
    队列
    对象中。队列在程序中应该是全局的,以便其他线程可以访问它们,这些线程将需要并发运行以处理数据并流式传输它们
  • 创建一个新类
    VideoStream
    ,负责从特定的
    队列
    获取()
    帧,对其进行处理并流式传输。处理意味着在帧流传输到网络之前,您希望对其执行的任何操作:转换为灰度、绘制矩形、检测面等。该类还需要在单独的线程中运行,构造函数需要接收两个参数:第一个参数指示应使用的两个全局队列中的哪一个;第二个参数,用于指示帧在流传输之前是否应进行处理
如果您正在寻找有关如何使用多线程从相机检索帧并将其存储在队列中的代码示例,特别是以下部分:

如何以相机支持的最接近的最大fps拍摄?线程和队列示例

请记住,您的应用程序将有4个线程:

  • 主线
  • 属于
    摄像机池的摄像机
  • 另外2个线程来自将被实例化的
    视频流
    对象中的每一个
您试过使用这个吗?链接中的示例似乎与您的用例非常相似?不此外,由于捕获和识别是通过JS完成的,因此您将繁重的工作负载卸载到客户机上,而不是尝试在4gb raspiHi Akib上完成!抱歉耽搁了。。。非常喜欢将识别转移到客户端的想法,它肯定会卸载raspberry。我在这里只看到一个问题:如何访问pi上的摄像头?我猜不可能从前端直接访问摄像头?我想说的是:将捕获帧和处理/流的责任划分为两个独立的类。这就是你要征服的方式!