Flask (работает сервер REST) ​​конфликтует с OpenCV при чтении веб-камеры в Ubuntu - PullRequest
0 голосов
/ 06 марта 2020

Я делаю большую программу, которая должна использовать веб-камеру через OpenCV, а также должна действовать как REST сервер. Функциональность этих двух не связана, то есть я не спрашиваю, как отправить сообщение через REST, это совершенно другая топи c полностью.

Меня беспокоит, если я запустите приложение Flask, выполняющее роль REST-сервера, и веб-камера не сможет подключиться. Вот небольшой пример, который демонстрирует проблему:

# test.py

import numpy as np
import cv2
from flask import Flask, jsonify, request

cap = cv2.VideoCapture(0)

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

flaskApp = Flask(__name__)

def main():

    flaskApp.run(debug=True)

    while True:
        # Capture frame-by-frame
        ret, frame = cap.read()

        # Display the resulting frame
        cv2.imshow('frame', frame)

        keyPress = cv2.waitKey(10)
        if keyPress == ord('q'):
            break
        # end if

    # end while

    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()
# end function

@flaskApp.route('/post_number', methods=['POST'])
def post_number():
    if not request.json or not 'data' in request.json:
        print('error')
    # end if

    if request.json is None:
        print('error, request.json is None')
    # end if

    if not 'data' in request.json:
        print('error, \'data\' is not in request.json')
    # end if

    data = request.json['data']
    print('data = ' + str(data))

    return jsonify({'data': data}), 201
# end function

if __name__ == '__main__':
    main()

Если я закомментирую строку flaskApp.run(debug=True), тогда веб-камера подключится и покажет потоковые кадры в окне OpenCV, как и ожидалось. Однако при включенном flaskApp.run(debug=True), как указано выше, окно OpenCV никогда не появляется, и я получаю такой вывод:

$ python3 test.py 
 * Serving Flask app "cam_test" (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://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
[ WARN:0] global /io/opencv/modules/videoio/src/cap_v4l.cpp (887) open VIDEOIO(V4L2:/dev/video0): can't open camera by index
 * Debugger is active!
 * Debugger PIN: 297-109-197

Итак, приложение Flask запускается успешно (я даже могу успешно отправлять POST-сообщения через тестовый клиент ) но OpenCV windows никогда не появляется, и обратите внимание на строку [ WARN:0] global /io/opencv/modules/videoio/src/cap_v4l.cpp (887) open VIDEOIO(V4L2:/dev/video0): can't open camera by index в приведенном выше выводе.

Я использую Ubuntu 18.04, если это имеет значение. Видео для linux (4VL) является стандартным способом (возможно, единственным?) Для чтения с веб-камер в Ubuntu.

Кажется, существует конфликт между Flask и OpenCV / V4L для какого-то ресурса, однако я не уверен, что это за ресурс. Есть ли способ настроить Flask, чтобы он не использовал те же ресурсы, что и веб-камера OpenCV, или каким-либо другим способом решить эту проблему, чтобы приложение в этом примере могло получать канал веб-камеры и одновременно работать как сервер REST?

--- Edit ---

@ dt c только что указал на упущение, которое я сделал в комментариях, что выполнение никогда не выходит за пределы строки flaskApp.run(debug=True), так что даже если веб-камера, подключенная к окну OpenCV, никогда не будет отображаться. В связи с этим возникает вопрос о том, как создать небольшой пример. Я не могу запустить flaskApp как отдельный многопроцессный процесс, потому что мне нужно получить полученное сообщение REST и получить информацию об изображении, а порождение многопроцессорного процесса приведет к разделению памяти.

1 Ответ

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

Как указал @ dt c, основная проблема заключалась в том, что я пропускал остановку выполнения в строке flaskApp.run(). Из этого поста

Запустите приложение flask в отдельном потоке

. Простое решение - использовать отдельный поток.

Полный рабочий пример:

сервер:

# server_and_cam.py

import numpy as np
import cv2
from flask import Flask, jsonify, request
import threading

cap = cv2.VideoCapture(0)

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

flaskApp = Flask(__name__)

def main():

    threading.Thread(target=flaskApp.run).start()

    while True:
        # Capture frame-by-frame
        ret, frame = cap.read()

        # Display the resulting frame
        cv2.imshow('frame', frame)

        keyPress = cv2.waitKey(10)
        if keyPress == ord('q'):
            break
        # end if

    # end while

    # When everything done, release the capture
    cap.release()
    cv2.destroyAllWindows()
# end function

@flaskApp.route('/post_number', methods=['POST'])
def post_number():
    if request.json is None:
        print('error, request.json is None')
    # end if

    if not 'number' in request.json:
        print('error, \'number\' is not in request.json')
    # end if

    numReceived = request.json['number']
    print('numReceived = ' + str(numReceived))

    return jsonify({'number': numReceived}), 201
# end function

if __name__ == '__main__':
    main()

клиент:

# client.py

import requests
import json
import time

numToSend = 0

while True:
    time.sleep(1)

    # set the url
    url = 'http://localhost:5000/post_number'

    # configure headers
    headers = {'Content-type': 'application/json'}

    # build the data and put into json format
    data = {'number': str(numToSend)}
    data_json = json.dumps(data)

    # send message to server via POST
    response = requests.post(url, headers=headers, data=data_json)
    # print response code
    print('response = ' + str(response))

    numToSend += 1
# end while
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...