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

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

MENU

Go言語での顔認識

前回Go言語用のOpenCVの環境構築を行いました。
elsammit-beginnerblg.hatenablog.com


今回はこの環境を用いてカメラ+ラズパイでストリーミング配信された映像から顔認識してみたいと思います!!
カメラ+ラズパイからストリーミング配信する方法はこちらを参照。
elsammit-beginnerblg.hatenablog.com



■顔認識方法

顔認識のサンプルが公式で展開されていたため、こちらをベースに作成。
Face Detect :: GoCV - Golang Computer Vision Using OpenCV 4

ただし、本サンプルは
 ・実行時の引数に"カメラID"と"カスケードファイルパス"を指定しなければならない
 ・カメラからの入力に対する処理になっている(ストリーミング配信ではない)
ので、今回実施したい環境に修正します。

修正箇所ですが、まずは引数を用いないため下記を削除。

if len(os.Args) < 3 {
    fmt.Println("How to run:\n\tfacedetect [camera ID] [classifier XML file]")
    return
}

deviceID, _ := strconv.Atoi(os.Args[1])

そしてカスケードファイルパスを格納する変数である"xmlFile"にカスケードファイルパスを直接記載.

xmlFile := "haarcascade_frontalface_default.xml" ← カスケードファイルパスを指定.

最後にビデオキャプチャ処理を下記に変更.

webcam, err := gocv.OpenVideoCapture("ストリーミング配信リンク")


そして、変更後のファイルを実行!!
ストリーミング配信された映像が表示された!!
けど、、、
数秒(5秒程度?)遅れて表示される。。。泣
カクカク動くし。。。泣

■顔認識処理速度改善

なぜ処理が遅いのだろう??

試しに顔認識処理を取り除いてストリーミング配信を表示させてみたところ、、、
遅延がない!!

ということは、顔認識処理が遅延させている原因だということがわかりました。
よくよく処理内容を確認すると、
カスケードファイルを用いた認識処理が、

rects := classifier.DetectMultiScale(img)

となっており、パラメータが設定されていない。
minSizeやMaxSizeを設定しないと、様々な大きさの矩形領域で顔認識を行ってしまうため処理が遅くなってしまいます。

原因はここだ!!と思い、該当箇所をこちらのように変更!!

rects := classifier.DetectMultiScaleWithParams(img,1.5,2,0,image.Point{X: 100, Y: 100}, image.Point{X:300, Y:300})

DetectMultiScale関数は、

func (c *CascadeClassifier) DetectMultiScale(img Mat) []image.Rectangle

であり、パラメータを設定できないので代わりに DetectMultiScaleWithParamsを用いました。

func (c *CascadeClassifier) DetectMultiScaleWithParams(img Mat, scale float64,
    minNeighbors, flags int, minSize, maxSize image.Point) []image.Rectangle

gocv - GoDoc

今回のパラメータでは、最大の顔認識検知領域を300×300までとし、最小を100×100としました!!

変更した結果を確認するために実行!!
遅延なくストリーミング映像が表示されることを確認!!

結果はこんな感じで、しっかり顔認識できることを確認できました。
f:id:Elsammit:20200922110451g:plain

■最後に

go言語でも顔認識させることができました。
環境さえセットアップできてしまえばpythonと同じような感覚で顔認識まで行うことができました!!

opencvを用いれば画像類似度や動体検知も行えるようです。
色々な画像処理が行えるのでとても便利!!

詳解 OpenCV 3 ?コンピュータビジョンライブラリを使った画像処理・認識

新品価格
¥7,480から
(2020/9/22 11:14時点)

もう少しopencv色々触ってみようかな??
Webもやりたいから、、、う~~んどうしよう??


Go言語へのGoCV(OpenCV)インストール手順


今回はGo言語でOpenCVを利用するための環境構築についてです。

最近OpenCVネタが続いてしまっていますが、、、
OpenCV結構面白くてハマってしまっていますww。

詳解 OpenCV 3 ?コンピュータビジョンライブラリを使った画像処理・認識

新品価格
¥7,480から
(2020/9/21 10:20時点)

そろそろWebも進めたいのですが、まぁ両方やっていこうかな?w


で、本題ですがGo言語でのOpenCV利用のための環境構築を試してみたのでそれをまとめておきます!!
今後、サーバーサイドでGo言語使っていきたいな!!と思っているのでOpenCVもGo言語で使えたらいいな!と思い、試してみました。

ただ、結構ハマってしまい苦労した。。。
いくつかのサイトで手順紹介されているのですが、全くうまくいかず、、
3~4時間溶かしてしまいました泣。
また同じところで詰まるのは避けたいので、まとめておきます!!泣

OpenCVインストール

pythonの場合には、

 pip install opencv-python

を用いればよいのですが、Go言語の場合にはOpenCVソースコードのビルドから実施しなければならないです。

gihubからソースコードをgetしてcmake、buildしてもよいのだが、、、
今回は下記の通り、シェルスクリプトを用います!!
シェルスクリプトだと少ないコマンドで実行可能なので、楽!!

まずはシェルスクリプトを取得。

wget --no-check-certificate https://raw.githubusercontent.com/milq/milq/master/scripts/bash/install-opencv.sh

その後、シェルスクリプトを実行してOpenCVをインストールまで実行!!

sudo chmod +x install-opencv.sh
sudo ./install-opencv.sh

■GoCVインストール

Go言語でのOpenCVはGoCVというようです。
https://gocv.io/

このGoCVのインストール手順です。
まずインストールですが、こちらを実行。

go get -u -d gocv.io/x/gocv

ここで、pgkconfigにopencvのパスを通さなければならないため、
こちらを実行。

export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"

また、>||/usr/local/lib/pkgconfig||<配下にopencv4.pcがない場合には新規でopencv4.pcの作成が必要です。
opencv4.pcを新規作成の上、こちらを記載。

prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: opencv4
Description: The opencv library
Version: 4.0.0
Cflags: -I${includedir}/opencv4
Libs: -L${libdir} -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_calib3d -lopencv_ccalib -lopencv_core -lopencv_datasets -lopencv_dnn -lopencv_dnn_objdetect -lopencv_dpm -lopencv_face -lopencv_features2d -lopencv_flann -lopencv_fuzzy -lopencv_gapi -lopencv_hfs -lopencv_highgui -lopencv_img_hash -lopencv_imgcodecs -lopencv_imgproc -lopencv_line_descriptor -lopencv_ml -lopencv_objdetect -lopencv_optflow -lopencv_phase_unwrapping -lopencv_photo -lopencv_plot -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_shape -lopencv_stereo -lopencv_stitching -lopencv_structured_light -lopencv_superres -lopencv_surface_matching -lopencv_text -lopencv_tracking -lopencv_video -lopencv_videoio -lopencv_videostab -lopencv_xfeatures2d -lopencv_ximgproc -lopencv_xobjdetect -lopencv_xphoto

これでOK!!と思っていた時代が私にもありました泣。

これでサンプルソースを動かせばよいよ。ってこちらの参考に書いてあったので試しに実施してみたのですが、
GoCVを試すまでのお話 - Qiita
GOCVを使ってみた - Qiita


エラー。。。
バージョンを変えて再実施してみるも、、、
エラー。。。

どうやら、gocv内のファイルも>||make install<||しなければならないようです!!
Install on Ubuntu 18.04 failed · Issue #448 · hybridgroup/gocv · GitHub

早速、

cd $GOPATH/src/gocv.io/x/gocv
make install

を実行!!
※もし$GOPATHが分からず、gocvがどこにあるか分からない場合には、

sudo find / -name "gocv"

を実行すればパスがわかります。

■サンプルプログラム実行

公式にてサンプルプログラムが用意されているのでありがたく使わせていただく。

git clone https://github.com/hybridgroup/gocv
cd gocv
go run ./cmd/version/main.go

実行した結果、gocvやopencvのバージョンが表示されればインストールは成功です!!

gocv version: 0.24.0
opencv lib version: 4.4.0

■最後に

案外苦労したけど、最後はうまくいったのでよしとします!!

サンプルプログラム内を確認すると、
こんなに種類があるので、色々試しに動かしてみようかな?と思います。
後、djangoで実施したストリーミングをgo言語版でも試してみようかな?とも考えております!!
出来れば、OpenCV使ったWebアプリとか作れたらいいな~~。何作ろうかな??

README.md
basic-drawing
caffe-classifier
captest
capwindow
counter
cuda
dnn-detection
dnn-pose-detection
dnn-style-transfer
faceblur
facedetect
facedetect-from-url
find-chessboard
find-circles
find-lines
hand-gestures
hello
img-similarity
mjpeg-streamer
motion-detect
openvino
saveimage
savevideo
showimage
ssd-facedetect
tf-classifier
tracking
version


令和2年 10月 基本情報技術者試験 中止のお知らせ

今週末、残念なお知らせがメールで届きました泣。

今まで10月試験に向けて勉強してきた基本情報技術者試験の試験日が中止となる旨です。
f:id:Elsammit:20200920151640p:plain


状況が状況なので仕方がないですが、、、
残念です。。。泣

こちらの参考書がとても分かりやすかったので理解が深まり、
午前の部は9割方取れるようにもなってきたんだけどな。。。

キタミ式イラストIT塾 基本情報技術者 令和02年

新品価格
¥2,069から
(2020/9/20 15:21時点)

ただ、うれしい連絡もありました。
こちらです。

令和2年度中(令和2年12月~令和3年3月の複数日を予定)に、現在の出題形式、出題数(*2)のまま、CBT(Computer Based Testing)方式(*3)で実施します。詳細が決まり次第、ホームページで公表いたします。
 CBT方式の受験にあたっては、令和2年度10月試験のSG、FEに受験申込みをしていた方も、改めて受験申込みが必要となります。
 また、情報セキュリティマネジメント試験、基本情報技術者試験については、令和3年度以降も、このCBT方式での実施を継続します。
 なお、新型コロナウイルス感染症対策を前提とした「新たな日常」を踏まえた試験の在り方を抜本的に再検討し、2年後を目途に、新方式への移行を目指します。


試験会場へ行くことが不要になることを意味していそうです!!
自宅で受けること出来るようになることはかなりうれしい!!


自分かなりの方向音痴でいつも会場に行けるのかヒヤヒヤするんですよね(-_-;)
1度行ったことがある場所でも道が覚えられないですし、、、
最近はGoogle Mapがあるので、スマホ片手にいつも会場に向かっていました。

後、心配性な性格で、
 ・電車に乗り遅れたらどうしよう?
 ・電車が止まって遅くなったらどうしよう?
 ・Google Mapで駅から**分と出たけど本当につけるのかな?
 ...etc
といつも考えてしまい、
早めに家から出てしまうため試験開始よりも大幅に早い時間に到着してしまい無駄に待たなければならないのです。。。


こんな自分はCBT方式の試験はかなりウェルカムです!!
余計な心配しなくていいので、かなりありがたいです!!


前回受験したG検定は自宅での受験が可能だったので、移動の心配がなく平常心で受験することができました。


基本情報技術者試験も同じように自宅で受けられるととてもうれしいな!!


だけど、中止となった今これからどうしようかな??
一応、令和2年度中に再試験が行えるようですが、今から勉強するのもつらいし。。。

英語でも勉強していこうかな??
近々TOEICも受けなきゃならなくなりそうですし。
以前会社の先輩からこちらの単語帳進められたのでまずはこの本を読みたいと思います!!

速読速聴・英単語 Core1900 ver.5 (速読速聴・英単語シリーズ)

新品価格
¥2,090から
(2020/9/20 15:54時点)


OpenCVでの顔へのモザイク処理

最近、久々に触ったOpenCVにハマっていますww。
f:id:Elsammit:20200916224647p:plain

顔認識ができたので顔にモザイクでもつけてみようかな?と思い実施。
合わせて目にのみもモザイクを付けてみたのでそちらも報告!!
使用しているプログラミング言語pythonです。


■モザイク処理方法

特定領域のモザイク処理はこちらで実行できます。

import cv2

ratio = 0.05
def mosaic(src):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

srcにはモザイクをかけたい画像領域を渡します。
渡されたsrcに対して、ratioの値でモザイク処理を行います。
ratioの値は高いほどモザイクが細かく、低いほどモザイクが荒くなります。


例えば顔の領域全体にモザイク処理を行う場合にはこんな感じで実行すればよいです。

import cv2

ratio = 0.08

def mosaic(src):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

cascade_path = "haarcascade_frontalface_default.xml"

img1 = cv2.imread('lena.jpg')
img1 = cv2.resize(img1,(500,500))

# RGBからGray画像に変換.
gry_img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    
# カスケードファイル読み込み.
cascade = cv2.CascadeClassifier(cascade_path)

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

if len(facerect) > 0:    
    x = facerect[0][0]
    y = facerect[0][1]
    w = facerect[0][2]
    h = facerect[0][3]


    face = img1[y:y+h,x:x+w]
    msc = mosaic(face)
    img1[y:y+h,x:x+w] = msc

# フレームを表示する
cv2.imshow("test", img1)
    

# escキーが押されたらループ終了
cv2.waitKey(0)

モザイク処理を行う上で重要なのはこちらで、

facerect = cascade.detectMultiScale(gry_img,scaleFactor=1.5,minNeighbors=2,minSize=(30,30))
if len(facerect) > 0:    
    x = facerect[0][0]
    y = facerect[0][1]
    w = facerect[0][2]
    h = facerect[0][3]

    face = img1[y:y+h,x:x+w]
    msc = mosaic(face)
    img1[y:y+h,x:x+w] = msc

facerectで顔だと判定した領域を取得し、
顔判定した始点をx,yに格納すると同時に画像の幅や高さをw,hに格納。
顔領域のみをface変数に格納し、先ほどのmosaic関数に突っ込むとモザイクした結果が得られます。
最後に、モザイク結果を元画像に代入します。

ratioを切り替えた時のモザイク画像はこちらになります。
【元画像】
f:id:Elsammit:20200919164938j:plain


【ratio = 0.2】
f:id:Elsammit:20200919165126p:plain


【ratio = 0.08】
f:id:Elsammit:20200919165153p:plain

【ratio = 0.03】
f:id:Elsammit:20200919165217p:plain


ついでに、、、
ratioを小さくしすぎると荒いモザイクが作成できずエラーとなります。

error: (-215:Assertion failed) !dsize.empty() in function 'cv::resize'


■目にだけモザイク処理

OpenCVには顔のみでなく目のみを検知するカスケードファイルが存在します。
haarcascade_eye.xml
です。
目に対してのみモザイク処理を実施する場合には、

import cv2

ratio = 0.08

def mosaic(src):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

cascade_path = "haarcascade_frontalface_default.xml"

img1 = cv2.imread('lena.jpg')
img1 = cv2.resize(img1,(500,500))

# RGBからGray画像に変換.
gry_img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    
# カスケードファイル読み込み.
cascade = cv2.CascadeClassifier(cascade_path)

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

if len(eyerect) > 0:
    ex_left = eyerect[0][0]
    ey_left = eyerect[0][1]
    ew_left = eyerect[0][2]
    eh_left = eyerect[0][3]
    ex_right = eyerect[1][0]
    ey_right = eyerect[1][1]
    ew_right = eyerect[1][2]
    eh_right = eyerect[1][3]

    eyes_left = img1[ey_left:ey_left+eh_left,ex_left:ex_right+ew_left]
    msc_left = mosaic(eyes_left)

    eyes_right = img1[ey_right:ey_right+eh_right,ex_right:ex_right+ew_right]
    msc_right = mosaic(eyes_right)

    img1[ey_left:ey_left+eh_left,ex_left:ex_right+ew_left] = msc_left

# フレームを表示する
cv2.imshow("test", img1)
    

# escキーが押されたらループ終了
cv2.waitKey(0)

とすればOKです。

下記パラメータの意味ですが、

    ex_left = eyerect[0][0]
    ey_left = eyerect[0][1]
    ew_left = eyerect[0][2]
    eh_left = eyerect[0][3]
    ex_right = eyerect[1][0]
    ey_right = eyerect[1][1]
    ew_right = eyerect[1][2]
    eh_right = eyerect[1][3]

こちらのような関係となっております。
f:id:Elsammit:20200919171200p:plain

上記を実行させた結果はこんな感じになっており、
目の領域を長方形でモザイク処理しております。
f:id:Elsammit:20200919171433p:plain

■カメラモジュールからストリーミング配信された画像に対するモザイク処理

今までは画像に対してモザイク処理を行ってきましたが、今度はストリーミング配信された画像に対するモザイク処理です。
ソースはこんな感じ。

import cv2

ratio = 0.05

def mosaic(src):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

# ストリーミング配信されるリンクを指定.
cap = cv2.VideoCapture("リンクパス")
cascade_path = "haarcascade_frontalface_default.xml"

img = cv2.imread('hat.png', cv2.COLOR_BGR2RGB)
img = cv2.resize(img,(100,100))

# リンクが開けなかった場合
if not cap.isOpened():
    print("Cannot open a video capture.")
    exit(-1)


while True:
    # 送られてくる映像のフレームを取得.
    ret, frame = cap.read()

    frame_mosaic = mosaic(frame)

    # RGBからGray画像に変換.
    gry_mosaic = cv2.cvtColor(frame_mosaic,cv2.COLOR_BGR2GRAY)
    gry_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    
    # カスケードファイル読み込み.
    cascade = cv2.CascadeClassifier(cascade_path)

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

    # 顔認証部分を囲う色の指定.
    rectange_color = (255,0,0)

    # 顔認識部分を四角で囲う.
    if len(facerect) > 0:    
        x = facerect[0][0]
        y = facerect[0][1]
        w = facerect[0][2]
        h = facerect[0][3]

        face = frame[y:y+h,x:x+w]
        msc = mosaic(face)
        frame[y:y+h,x:x+w] = msc
        
    # もしフレームが取得できなかった場合
    if not ret:
        continue

    # フレームを表示する
    cv2.imshow("EV3 Streaming", gry_mosaic)
    cv2.imshow("test", frame)
    

    # escキーが押されたらループ終了
    k = cv2.waitKey(1)

    if k == 27:
        break

# キャプチャーの開放&ウィンドウ閉じる
cap.release()
cv2.destroyAllWindows()

実行した結果はこんな感じ!!
f:id:Elsammit:20200919172458g:plain


ちゃんと顔領域のみがモザイクかかってますね。
精度もまぁ、こんなもんかな?って感じです。

■最後に

結構しっかりとモザイク処理が出来ていて結構楽しかったです!!
AIを用いるとモザイク処理した結果を復元できるようなので、今度調べてみようかな??
写真のモザイクを除去して“ほぼ”復元させるAIが登場 | Ledge.ai

python3.8にOpenCVをインストール

新しくラズパイを購入したのでOpenCVをインストールしてみたところ躓いたので備忘録残しておこうと思います!!泣
。。。いつもこんなに苦労しないのに!!
f:id:Elsammit:20200916224647p:plain



■環境

 raspberryPi4
 

【国内正規代理店品】Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品

新品価格
¥6,875から
(2020/9/16 22:41時点)


 OS:rasbian 10.1
 

■通常パターン

下記コマンドを実行してあげればOKです!!

pip isntall opencv-python

いつもはたったこれだけなのです。

■今回のパターン

一旦pyenvを用いてpython3.8.0にアップデートしてみました。
pyenvのインストール方法や使い方はこちらを参照のこと。
elsammit-beginnerblg.hatenablog.com


そうしたところ、、、

ImportError: No module named '_ctypes' when using Value from module multiprocessing

といったエラーが発生。。


調べてみたところ、pyenvでインストールしたpython3.8をアンインストールしてからlibffi-devをインストールし、
再度python3.8.0をインストールするとよさそう!!
ということで、

pyenv uninstall 3.8.0
sudo apt-get install -y libffi-dev
pyenv install 3.8.0

を実行してから再度opencv-pythonをインストール!!

。。。ダメです泣。
今度は、

ModuleNotFoundError: No module named 'skbuild'

といったエラーが発生。

どうやらscikit-buildとcmakeが足りないことが理由らしい。
ダメ元で実行!!

pip install scikit-build
pip install cmake

こちらは問題なくインストール完了。

そして再度、

pip install opencv-python

を実行!!

動け。動け。動け!!!!

。。。

エラーなくインストール成功!!
やりました!!

念のため、

python
import cv2

を実行。
エラー発生せず!!

何とかOpenCVインストールできました。
良かった。

■最後に

思いのほか苦労してしまいました。。。
pyenvでpythonをインストールするとOpenCVに必要なパッケージが足りないためなのでしょうが、、、
う~~ん。難しいですね。



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

raspberry Pi + カメラモジュールでストリーミング配信と顔認識

今回はラズパイとカメラモジュールを用いてストリーミング配信を行う方法についてまとめたいと思います!!
また、ストリーミング配信をサーバーに送りそこで顔認識とその結果を表示する部分についてもまとめます!!

■実行環境

 <ストリーミング配信>
・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)
  ※PCにはpython3とOpenCVがインストール済みであること

簡単な構成はこちら。
f:id:Elsammit:20200913222309p:plain

■ラズパイでのストリーミング配信

ラズパイでストリーミング配信を行うにあたり、
カメラの映像をストリーミング配信するためのライブラリである「mjpeg_streamer」を用いました。

まずはインストールです。
こちらを実行。

mkdir ~/mjpg-streamer
cd ~/mjpg-streamer
sudo apt-get install 
sudo apt-get install cmake libjpeg8-dev
sudo git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
sudo make
sudo make install

やっていることは、githubに上がっているソースコードをcloneしてコンパイルとインストールを行っているだけです。

次にこちらを実行!!

mjpg_streamer -o "/usr/local/lib/mjpg-streamer/output_http.so -w ./www -p 8080" -i "/usr/local/lib/mjpg-streamer/input_uvc.so -d /dev/video0 -r 640x480 -fps 30 -q 10 -y -n"

実行した結果、こちらのようなログが表示されたら、

 i: Using V4L2 device.: /dev/video0
 i: Desired Resolution: 640 x 480
 i: Frames Per Second.: 30
 i: Format............: YUYV
 i: JPEG Quality......: 10
 i: TV-Norm...........: DEFAULT
 o: www-folder-path......: ./www/
 o: HTTP TCP port........: 8080
 o: HTTP Listen Address..: (null)
 o: username:password....: disabled
 o: commands.............: enabled

ブラウザ上でhttp://ラズパイのIPアドレス:8080/?action=streamにアクセスすると、
ストリーミング配信の確認が行えます。

■ストリーミング配信された動画から顔認識

ストリーミング配信を受けて、顔認証するソースはこちら。
※カスケードファイル(haarcascade_frontalface_default.xml)は下記ソースと同フォルダに格納しておいてください。

import cv2

# ストリーミング配信されるリンクを指定.
cap = cv2.VideoCapture("リンクパス")
cascade_path = "haarcascade_frontalface_default.xml"


# リンクが開けなかった場合
if not cap.isOpened():
    print("Cannot open a video capture.")
    exit(-1)


while True:
    # 送られてくる映像のフレームを取得.
    ret, frame = cap.read()

    # RGBからGray画像に変換.
    gry_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    
    # カスケードファイル読み込み.
    cascade = cv2.CascadeClassifier(cascade_path)

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

    # 顔認証部分を囲う色の指定.
    rectange_color = (255,0,0)

    # 顔認識部分を四角で囲う.
    if len(facerect) > 0:
        for rect in facerect:
            cv2.rectangle(frame,tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]),rectange_color,thickness=2)


    # もしフレームが取得できなかった場合
    if not ret:
        continue

    # フレームを表示する
    cv2.imshow("EV3 Streaming", frame)

    # escキーが押されたらループ終了
    k = cv2.waitKey(1)

    if k == 27:
        break

# キャプチャーの開放&ウィンドウ閉じる
cap.release()
cv2.destroyAllWindows()

■最後に

ラズパイからのカメラモジュールから取得した映像をストリーミング配信を行う方法と、
ストリーミング結果を受けたサーバが顔認識結果をimshowでサーバ上に表示する方法をまとめました。

ただ、、、サーバ上で見れるのではなく顔認識等の結果をフロントエンドで見れるようにしたほうが汎用性高いですね。
ということで、近いうちにサーバにて顔認識した結果をフロントエンドへの送信方法についてもまとめたいと思います!!