Правильный способ закрыть поток opencv, используя ответ Flask - PullRequest
0 голосов
/ 11 марта 2020

У меня есть пара потоков RTSP, которые мне нужно отобразить в браузере. В настоящее время я использую OpenCV cv2.VideoCapture, чтобы сделать это. Это делает свое дело, но когда клиентская сторона перестает получать поток (то есть закрывает окно браузера), похоже, что даже когда захват видео прекращается, экземпляр объекта CameraStream все еще находится в памяти. У меня нет внешних ссылок на это.

Как правильно закрыть их?

Вот мой код:


    class Stream(Resource):

        def get(self, id):

            self.id = id
            response = Response(Stream.gen_frame(self),
                            mimetype='multipart/x-mixed-replace; boundary=frame')
            return response


        def gen_frame(self):
            """
            Video stream generator
            """
            self.cap = CameraStream(cameras[self.id]).start()

            while self.cap:

                frame = self.cap.read()
                convert = cv2.imencode('.jpg', frame)[1].tobytes()

                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + convert + b'\r\n')  # concate frame one by one and show result

                time.sleep(0.05)

            self.cap.stop()
            cv2.destroyAllWindows()
            self.cap.stream.release()
            print("done")

И класс CameraStream:


class CameraStream(object):
    thread = None
    frame = None
    last_access = 0

    def __init__(self, stream, src=0):
        self.stream = cv2.VideoCapture(stream)

        (self.grabbed, self.frame) = self.stream.read()
        self.started = False
        self.read_lock = Lock()

    def start(self):
        if self.started:
            print("already started!!")
            return None
        self.started = True
        self.thread = Thread(target=self.update, args=())
        self.thread.start()
        return self

    def update(self):
        while self.started:

            (grabbed, frame) = self.stream.read()
            self.read_lock.acquire()
            self.grabbed, self.frame = grabbed, frame
            self.read_lock.release()

    def read(self):
        self.read_lock.acquire()
        if not isinstance(self.frame, (numpy.ndarray)):
            # debugging stuff
            print('achtung', type(self.frame))
            return 0

        frame = self.frame.copy()

        self.read_lock.release()
        return frame

    def stop(self):
        self.started = False
        self.thread.join()

    def __exit__(self, exc_type, exc_value, traceback):
        self.stream.release()

Только идея у меня было, что работало (вроде) использование глобальной переменной для проверки ее значения в каждой итерации l oop. Так что я могу изменить его глобально, чтобы остановить все потоки одновременно

ps Я проверяю объекты, используя этот код:

for x in gc.get_objects():
                if isinstance(x, CameraStream):
                    print(x)

1 Ответ

0 голосов
/ 12 марта 2020

Я разобрался.

блок вне генератора l oop никогда не выполнялся, потому что объект ответа был удален до этого.

Так что в качестве решения я просто переписал del функция такая:

def __del__(self):
        try: 
            self.cap.stop()
            self.cap.stream.release()
        except:
            print('probably there\'s no cap yet :(')
        cv2.destroyAllWindows()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...