Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

djangoを用いた顔認識結果をフロントエンドへのストリーミング配信

前回はラズパイ+カメラモジュールからストリーミング配信された画像からサーバ上で顔認識を行いました。
今回は、サーバ上で顔認証した結果をフロントエンドにストリーミング配信したいと思います!!
elsammit-beginnerblg.hatenablog.com

■実行環境

・Raspberry Pi4

ラズベリーパイ 4 コンピューターモデルB 2GB Raspberry Pi 4 ラズパイ 4 TELEC認定取得済み 技適マーク入り

価格:7,478円
(2020/9/13 23:19時点)
感想(0件)


・カメラモジュール(LOGICOOL HDプロ ウェブカム C920)
   

【エントリーでポイント10倍!(9月11日01:59まで!)】【中古】PCハード ロジクール HDプロ ウェブカム C920n

価格:10,070円
(2020/9/13 23:14時点)
感想(0件)


・PC(サーバとして利用)
 ※windows10かつpython3とOpenCV、anacondaがインストール済みであること

・PC(Web上でのストリーミング配信閲覧用)



構成はこんな感じです。
f:id:Elsammit:20200915211137p:plain

■サーバーサイドセットアップ

今回サーバサイドとしてdjangoを用いました。
理由は前回の顔認証制御を流用するため、です。

anacondaでのdjango立ち上げ手順はこちらをご参照いただくとして、
今回はdjangoが立ち上がった状態から進めたいと思います!!
elsammit-beginnerblg.hatenablog.com


まず、下記を実行して新規アプリケーションを追加いたします。

python manage.py startapp myapp

そして、setting.pyを下記のように追記。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'otherapps',
    'myapp', #←今回追加
]

さらにurl.pyを下記の通り修正。

urlpatterns = [
    path('admin/', admin.site.urls),
    url('myapp1/', include('myapp1.urls'))
    #url(@'admin/', admin.site.urls),
]

さらにさらに、新規作成したmyappアプリのフォルダ内にurl.pyを作成し下記を追記。

from django.conf.urls import url
from . import views

urlpatterns = [
    url('', views.index, name='index'),
]

ふぅ~~。これでセットアップは完了です。

■サーバサイドからのストリーミング配信

さて、ここからメインのサーバサイドにてラズパイからのストリーミング配信を受け取り、顔認識を行う制御をまとめます!!

myappフォルダ内のview.pyを下記の通り記載。

from django.shortcuts import render
from django.http import HttpResponse
import cv2
from django.http import StreamingHttpResponse
from testProject.settings import BASE_DIR

class VideoCamera(object):
    def __init__(self):
        self.video = cv2.VideoCapture(ラズパイからのストリーミング配信url)

    def __del__(self):
        self.video.release()

    def get_frame(self):
        cascade_path = BASE_DIR + "\haarcascade_frontalface_default.xml"

        success, image = self.video.read()

        gry_img = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        cascade = cv2.CascadeClassifier(cascade_path)

        facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(60,60))

        rectange_color = (255,0,0)

        if len(facerect) > 0:
            for rect in facerect:
                cv2.rectangle(image,tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]),rectange_color,thickness=2)
        
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

def gen(camera):
    while True:
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

def index(request):
    return StreamingHttpResponse(gen(VideoCamera()), content_type='multipart/x-mixed-replace; boundary=frame')

VideoCameraクラスでは前回の顔認証と同様にOpenCVでの顔認証コードになります。
前回と異なる点は、

ret, jpeg = cv2.imencode('.jpg', image)
return jpeg.tobytes()

で、フロントサイドに送信するためにjpgにエンコードするために入れております。

そして、

def gen(camera):
    while True:
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

ですが、OpenCVを用いて得られた顔認証結果を小出しにして返す関数となっております。
今回送信するデータはjpgにエンコードしたデータですので、Content-Typeをimage/jpegとしております。


最後に、

def index(request):
    return StreamingHttpResponse(gen(VideoCamera()), content_type='multipart/x-mixed-replace; boundary=frame')

です。
djangoでストリーミング配信を行う場合、StreamingHttpResponseという便利な関数がありますので、
StreamingHttpResponseに先ほどのjpgエンコード結果を送信データとして与えてます。

■動作確認

下記を実行しdjangoを起動し、

python manage.py runserver

フロントサイドとして用意したPCからブラウザ上で
http://サーバIPアドレス:8000/myapp
を実行。
そうするとストリーミング画面が表示されるかと思います!!


■最後に
前回のフロントサイドは簡単にできたのですが、今回のサーバサイドからの送信はかなり苦労しました。。。
分からないことだらけで、どうすればよいか分からず。。。
だけど、こういうやり方が分からない機能が分かった時の達成感は何とも言えない気持ちよさがあって好きです!!

今回はサーバサイドでOpenCVで顔認識を行いましたが、
サーバサイドでの処理(VideoCameraクラス内処理)を変更してjpgでエンコードすれば色々なことができますね!!

こちらにソースコードをアップしましたのでぜひ!!
https://github.com/Elsammit/CameraStreming.git