Ищите решение для отображения результатов обнаружения объектов живого видео с использованием HTML - PullRequest
0 голосов
/ 22 января 2019

Я ищу эффективный способ добавления ограничивающих рамок к живому видео, отображаемому на веб-странице.

Проект состоит в том, чтобы обнаруживать автомобили в захваченном видеопотоке (1080p 30fps)с помощью встроенной функции rtsp и отображения результатов на веб-странице.

Мое текущее решение:

Изображение кадра извлекается с использованием OpenCV.Я запускаю алгоритмы обнаружения кадр за кадром в режиме реального времени.Изображение кадра сначала сжимается в JPEG, а затем кодируется в строку Base64.Затем строка изображения Base64 вместе с ограничивающими прямоугольниками инкапсулируется в JSON.Я передаю строку JSON внешнему интерфейсу с помощью WebSocket.

На внешнем интерфейсе я использую canvas для рисования изображения кадра при каждом получении сообщения.

Теперь проблемы заключаются в следующем:

  1. Процесс сжатия JPEG (OpenCV imencode) + Base64 (base64.b64encode) занимает слишком много времени, пропускная способность составляет около 20FPS (без обнаружения).
  2. Изображенияотображение в браузере происходит медленно и не плавно, частота кадров не может даже достичь 20FPS (без обнаружения).И веб-страница занимает много памяти и может перестать отвечать .

Интересно, есть ли решение моих проблем (достигнуть 30FPS) или естьлюбые другие способы достижения моей цели (синхронизировать результаты обнаружения бэкэнда и живого видео внешнего интерфейса) .

PS Ограничительные рамки не отображаются на изображении на бэкэнде, поскольку могут быть некоторыенеобходимо выполнить операции с ограничивающими рамками на внешнем интерфейсе, например, определить, показывать ли ограничивающие рамки или нет.

РЕДАКТИРОВАТЬ: коды на python (без обнаружения) на серверной части имеют вид:

Main.py

from multiprocessing import Process, Queue    
import base64
import json
import cv2
import WSServer

def capture(path, outq):
    cap = cv2.VideoCapture(path)
    while True:
        ret, image = cap.read()
        outq.put(image)

def conv2jpg(inq, outq):
    while True:
        image = inq.get()
        imgEnc = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 75])[1].tostring()
        outq.put(imgEnc)

def conv2b64(inq, outq):
    while True:
        imgEnc = inq.get()
        strEnc = str(base64.b64encode(imgEnc), 'utf-8')
        outq.put(strEnc)

if __name__ == '__main__':
    # After arg parsing
    ws = WSServer.WSServer(args.ip, args.port)

    capQ = Queue(2)
    jpgQ = Queue(2)
    b64Q = Queue(2)

    capP = Process(target=capture, args=(args.input, capQ, )) 
    # args.input is the rtsp address of the camera
    jpgP = Process(target=conv2jpg, args=(capQ, jpgQ, ))
    b64P = Process(target=conv2b64, args=(jpgQ, b64Q, ))

    b64P.start()
    jpgP.start()
    capP.start()

    while True:
        strEnc = b64Q.get()

        msg = {'image': strEnc}
        msgJson = json.dumps(msg)

        # Send the json string over Websocket
        USERS = ws.getUSERS()            
        for user in USERS:
            user.put(msgJson)

WSServer.py

import threading
from queue import Queue
import asyncio
import websockets

class WSServer:
    def __init__(self, ip="localhost", port="11000", interval=1.0/60):
        self.ip = ip
        self.port = port
        self.interval = interval

        self.USERS = set()
        self.USERS_Lock = threading.Lock()
        self.P = threading.Thread(target=self.proc)
        self.P.setDaemon(True)
        self.P.start()

    async def get(self, q):
        if q.empty():
            return None
        return q.get()

    async def register(self, q):
        with self.USERS_Lock:
            self.USERS.add(q)

    async def unregister(self, q):
        with self.USERS_Lock:
            self.USERS.remove(q)

    async def serve(self, websocket, path):
        q = Queue()
        await self.register(q)
        try:
            while True:
                while True:
                    msg = await self.get(q)
                    if type(msg) == type(None):
                        break
                    await websocket.send(msg)
                await asyncio.sleep(self.interval)
        finally:
            await self.unregister(q)

    def getUSERS(self):
        with self.USERS_Lock:
            return self.USERS.copy()

    def proc(self):
        print('Listening...')   
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(websockets.serve(self.serve, self.ip, self.port))
        loop.run_forever()

EDIT2: упрощенные коды на внешнем интерфейсе:

<!DOCTYPE html>
<html>
    <head>
        <title>demo</title>
    </head>
    <body>
        <img id="myImg" style="display: None;"></img>
        <canvas id="myCanvas">
        <script>
            var img = document.getElementById('myImg')
            var cvs = document.getElementById('myCanvas')
            cvs.width = 1920
            cvs.height = 1080
            var ctx = cvs.getContext('2d')
            var ws = new WebSocket("ws://127.0.0.1:11000/");
            ws.onmessage = function (event) {
                var msg = JSON.parse(event.data)
                img.src = 'data:image/jpg;base64,' + msg.image
            };
            function render () {
                ctx.drawImage(img, 0, 0)
                window.requestAnimationFrame(render)
            }
            window.requestAnimationFrame(render)
        </script>
    </body>
</html>
...