Sử dụng Django/Flask và Opencv để stream video từ webcam!
Bài đăng này đã không được cập nhật trong 6 năm
Giới thiệu
Nhân có một số người bạn hỏi về sử dụng opencv để stream và hiển thị nó trên web mình sẽ viết bài chia sẻ cơ bản nhất để làm việc đó. Bài chia sẻ sẽ sử dụng 2 web framework phổ biến nhất của Python là Flask và Django
Cài đặt
Trên hệ điều hành Ubuntu 16.04
mình cài các library trên virtualenv
. Cụ thể thông tin các gói:
(venv) % python --version
Python 3.6.1
(venv) % pip freeze
Django==2.0.2
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
numpy==1.14.1
opencv-python==3.4.0.12
pytz==2018.3
Werkzeug==0.14.1
Thực hiện
Django
Tạo một project django
Sử dụng CLI của django tạo một project tên là stream
và app là webcam
:
(venv) % django-admin startproject stream # Tạo project lấy tên là "stream"
(venv) % cd stream && django-admin startapp webcam # Tạo app lấy lên là "webcam"
Chạy thử nào:
(venv) % python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
February 26, 2018 - 03:45:01
Django version 2.0.2, using settings 'stream.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Xử lý stream
Mở browser vào địa chỉ: http://127.0.0.1:8000/ và đây là kết quả: Giao diện của Django 2.0 có vẻ nhìn sáng sủa hơn các phiên bản cũ
Tiếp tục, mình sẽ tạo một app in ra "Hello Word!":
Setup app webcam
vào trong settings.py
của project stream
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'webcam'
]
Trong thư mục app webcam
, mình tạo một thư mục templates
. Sau đó, tạo một file tên là index.html
Nội dung của file html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stream</title>
</head>
<body>
<h1>Hello Word!</h1>
</body>
</html>
Back lại, trong thư mục app webcam
, trong file views.py
. Bạn định nghĩa view:
from django.http import HttpResponse
def index(request):
template = loader.get_template('index.html')
return HttpResponse(template.render({}, request))
Cuối cùng, định nghĩa URL trong stream/urls.py
:
from django.contrib import admin
from django.urls import path
from webcam.views import index
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', index),
]
Chạy lại web django, sau đó vào địa chỉ: http://127.0.0.1:8000/index/. Và đây là kết quả: Tiếp theo mình sẽ cài đặt stream Trở lại file html mình thay đổi lại một chút:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stream</title>
</head>
<body>
<h1>Video Streaming Django</h1>
<img src="{% url 'video-feed' %}" alt="">
</body>
</html>
Tiếp theo, mình thêm function xử lý stream ở view.
def stream():
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
print("Error: failed to capture image")
break
cv2.imwrite('demo.jpg', frame)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + open('demo.jpg', 'rb').read() + b'\r\n')
def video_feed(request):
return StreamingHttpResponse(stream(), content_type='multipart/x-mixed-replace; boundary=frame')
Nhìn code bạn cũng đã thấy luồng xử lý stream rồi. Rất đơn giản:
- Đọc capture từ webcam sử dụng opencv
- Từ capture đó, get ra các frame.
- Từ các frame đó bạn có thể làm rất nhiều điều: ví dụ như nhận dạng khuôn mặt, đoán tuổi, giới tính, blabla..
- Cuối cùng là ghi cái frame đó ra file và yield cái frame đó hiển thị trên html
Vậy đó!! Cuối cùng, ta cũng định nghĩa lại URL stream:
from django.contrib import admin
from django.urls import path
from webcam.views import index, video_feed
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', index),
path('video_feed/', video_feed, name="video-feed")
]
Reload lại URL: http://127.0.0.1:8000/index/ xem kết quả . Thứ lỗi vì mình hơi xấu trai
Flask
Với Flask, mình cũng làm tương tự:
Tạo một project với cấu trúc:
Trong file index.html
<html>
<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('video_feed') }}">
</body>
</html>
Flask sử dụng url_for
trong template tương tự như url
của Django vậy.
Trong file server app.py
from flask import Flask, render_template, Response
import cv2
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
def gen():
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
print("Error: failed to capture image")
break
cv2.imwrite('demo.jpg', frame)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + open('demo.jpg', 'rb').read() + b'\r\n')
@app.route('/video_feed')
def video_feed():
return Response(gen(),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(debug=True)
Luồng xử lý stream của Flask và Django đều giống nhau nên mình cũng không giải thích thêm. Chạy thử code:
(venv) % python app.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 720-880-471
Mở browser lên vào địa chỉ: http://127.0.0.1:5000/ ta sẽ được kết quả y hệt như khi sử dụng Django
Nếu bạn còn vướng mắc về Django và Flask bạn có thể contact với mình qua Skype hoangminh.dev
Thanks for reading!
All rights reserved