Итак, у меня есть приложение Django, которое управляет некоторыми веб-камерами USB (все Logitech C525)
Это приложение берет кадр из объекта VideoCapture
, когда запрос GET
приходит на указанную конечную точку API и отправляет этот кадр на сервер, чтобы выполнить некоторую классификацию объекта на изображении (обычно это фрукты / овощи)
Приложение получает запросы от клиентов, IP-адрес каждого клиента (приложение и клиенты находятся в одной локальной сети) привязан к уникальной веб-камере ID
Вот фрагмент, который показывает, как я ищу привязку между идентификатором камеры и логическим устройством в /dev/video*
, чтобы создать VideoCapture
объект:
import re
import subprocess
class CameraBinder(object):
def __init__(self):
self.cam = 'C525'
self.cam_id_list_in_dev_video = []
self.binding_between_udev_dev = None
def find_cam_in_dev_video(self):
cmd = ['/usr/bin/v4l2-ctl', '--list-devices']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
out, err = out.strip(), err.strip()
for line in [i.split("\n\t".encode()) for i in out.split("\n\n".encode())]:
if self.cam.encode() in line[0]:
cam_id_from_dev = re.search(r'(?<=/dev/video).*', line[1].decode('utf-8'))
self.cam_id_list_in_dev_video.append(cam_id_from_dev.group(0))
process.kill()
return self.cam_id_list_in_dev_video
def bind_cam_between_dev_udev(self, cam_id):
cmd = ['/bin/udevadm', 'info', '--attribute-walk', f'--name=/dev/video{cam_id}']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
out, err = out.strip(), err.strip()
kernel_for_udev_rules = re.search(r'(?<=KERNELS==\")[^\"]*', out.decode('utf-8')).group(0)
serial = re.search(r'(?<=ATTRS{serial}==\")[^\"]*', out.decode('utf-8')).group(0)
self.binding_between_udev_dev = f'{kernel_for_udev_rules} {serial}'
process.kill()
return self.binding_between_udev_dev
Чем, у меня есть некоторые Django команд управления, которые конфигурируют мою систему (сбор идентификаторов камер при первой настройке и привязка локальных IP-адресов к этим идентификаторам)
В моем views.py
у меня есть эта конечная точка:
from camera.utils import VideoCamera, CameraBinder
from camera.models import Binding
cam_binder = CameraBinder()
cam_list = cam_binder.find_cam_in_dev_video()
for cam_id in cam_list:
index = cam_binder.bind_cam_between_dev_udev(cam_id)
streams[index] = VideoCamera(cam_id)
print(cam_id, index)
streams[index].update_frame()
def detect(request):
if request.method == "GET":
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[-1].strip()
else:
ip = request.META.get('REMOTE_ADDR')
camera_id = Binding.objects.get(ip_address=ip).port_id
print(camera_id, streams[camera_id])
logger.info('detect method started')
s_time = time.clock()
image = streams[camera_id].get_frame()
VideoCamera
class:
from threading import Thread
import cv2
def start_new_thread(function):
def decorator(*args, **kwargs):
t = Thread(target=function, args=args, kwargs=kwargs)
t.daemon = True
t.start()
return decorator
class VideoCamera(Thread):
def __init__(self, cam_id):
Thread.__init__(self)
self.current_frame = None
self.stream = cv2.VideoCapture(cam_id)
self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, CAMERA_SETTINGS['WIDTH'])
self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, CAMERA_SETTINGS['HEIGHT'])
self.stream.set(cv2.CAP_PROP_FPS, CAMERA_SETTINGS['FPS'])
self.stream.set(cv2.CAP_PROP_AUTOFOCUS, CAMERA_SETTINGS['AUTOFOCUS'])
self.stream.set(cv2.CAP_PROP_FOCUS, CAMERA_SETTINGS['FOCUS'])
self.stream.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
@start_new_thread
def update_frame(self):
while True:
ret, self.current_frame = self.stream.read()
if self.current_frame is None:
time.sleep(0.100)
continue
def get_frame(self):
return self.current_frame
Когда я запускаю сервер разработки, кажется, что все идет хорошо, но когда я пытаюсь отправить запрос на мою конечную точку API, я получаю следующее:
Watching for file changes with StatReloader
2020-03-27 19:25:25,674 | INFO | Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
March 27, 2020 - 19:25:26
Django version 3.0.2, using settings 'sw_client.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
2020-03-27 19:25:29,941 | INFO | detect method started
Internal Server Error: /detect/
Traceback (most recent call last):
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/user/PycharmProjects/sw_client/camera/views.py", line 45, in detect
cv2.imwrite(DEBUG_PATH + f'/grabbed{camera_id}.jpg', image)
cv2.error: OpenCV(4.2.0) /io/opencv/modules/imgcodecs/src/loadsave.cpp:715: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'
2020-03-27 19:25:29,995 | ERROR | Internal Server Error: /detect/
Traceback (most recent call last):
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/user/smart_weights/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/user/PycharmProjects/sw_client/camera/views.py", line 45, in detect
cv2.imwrite(DEBUG_PATH + f'/grabbed{camera_id}.jpg', image)
cv2.error: OpenCV(4.2.0) /io/opencv/modules/imgcodecs/src/loadsave.cpp:715: error: (-215:Assertion failed) !_img.empty() in function 'imwrite'
[27/Mar/2020 19:25:29] "GET /detect/ HTTP/1.1" 500 79218
* 1 022 * Если я закомментирую эту строку кода, я получу сообщение об ошибке через 2 строки после кодирования изображения, чтобы отправить его через JSON.
Как я понял, изображение, которое приходит к
imwrite()
, пусто. Я пытался распечатать
self.stream.isOpened()
внутри
VideoCamera()
класса. И вывод был
False
. Но в то же время я могу запустить это:
import cv2
cap1 = cv2.VideoCapture(4)
cap2 = cv2.VideoCapture(2)
cap3 = cv2.VideoCapture(0)
# cap4 = cv2.VideoCapture(6)
while 1:
ret1, img1 = cap1.read()
ret2, img2 = cap2.read()
ret3, img3 = cap3.read()
# ret4, img4 = cap4.read()
if ret1 and ret2:
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
# cv2.imshow('img4', img4)
k = cv2.waitKey(100)
if k == 27: #press Esc to exit
break
cap1.release()
cap2.release()
cap3.release()
# cap4.release()
cv2.destroyAllWindows()
И это работает, выводя мне 3 windows с видеопотоком из моих камер.
Итак, как я могу локализовать проблему? Я думаю, это не из-за версий OpenCV / Python.