OpenCVで映像処理


OpenCVで人間を画像認識してみた。

# 1.環境

作業環境としては、いつもお世話になっているGoogle Colabratoryを今回も使う。

# 2.画像データ表示

書籍を参考にとりあえず画像をGoogle Colaboratoryで表示するコードを書いてみたが、
```Python
import cv2  # OpenCV

img = cv2.imread("img/img01.jpg")
cv2.imshow("img", img)   
```

いきなりエラーが発生した。
cv2.imshowはだめだから、代わりのライブラリを使えとのこと。


```Python
DisabledFunctionError: cv2.imshow() is disabled in Colab, because it causes Jupyter sessions
to crash; see https://github.com/jupyter/notebook/issues/3935.
As a substitution, consider using
  from google.colab.patches import cv2_imshow
```

指示に従ってコード修正すると正常に画像が表示された。☺
いきなり躓くとは思わなった。

```Python
import cv2  # OpenCV
from google.colab.patches import cv2_imshow  # OpenCVの一部問題回避用

img = cv2.imread("img/img01.jpg")
cv2_imshow(img)
```

# 3.動画データ表示

次に動画データも表示できるようにしておく。

ここでも書籍を参考にしてaviデータを表示するコードを書いてみた。同じミスをしないようにcv2.imshowの代わりにcv2_imshowを使ってみた。
結果は、動画ではなく画像が連続で表示されつづけるという結果になった。さらに、Colaboratoryの切断、接続を繰り返し、暴走状態みたいになってしまった。

```Python
import cv2  # OpenCV
from google.colab.patches import cv2_imshow  # OpenCVの一部問題回避用

# 動画ファイル読み込み
cap = cv2.VideoCapture("mov/mov01.avi")

# 動画出力
while(cap.isOpened()):
  ret, frame = cap.read()
  if ret:
    cv2_imshow(frame)
  if cv2.waitKey(1) & 0xFF == ord("q"):
    break

cap.release()
cv2.destroyAllWindows()
```

調べてみると同じように困っている人は結構いるらしく、情報がたくさんあった。
下記のサイトを参考にして、OpenCVではなく、HTMLで動画表示する方式に変更した。しかしこのコードだとMP4対象だったので、事前にaviからmp4への変換も仕込んでおくと、正常に動画ウィンドウが表示されて、再生ボタンまでついてきた。
しかしOpenCVを使いたかったのにいきなりOpenCVからHTMLへ変わってしまった。

https://androidkt.com/how-to-capture-and-play-video-in-google-colab/

```Python
# 動画フォーマット変換
!ffmpeg -i mov/mov01.avi mov/mov01.mp4

# 動画データmp4の再生
from IPython.display import HTML　# jupyter notebook内にHTMLを出力するためのモジュール
from base64 import b64encode

def show_video( video_path, video_width = 600):

  video_file = open(video_path, "r+b").read()
  video_url = f"data:video/mp4;base64,{b64encode(video_file).decode()}"
  return HTML(f"""<video width={video_width} controls>
                    <source src="{video_url}">
                  </video>""")

show_video("mov/mov01.mp4")
```

# 4.動画データの画像ファイル化

次に動画データをフレームごとに画像ファイル化をしてみる。今度は正常に動作してくれた。

~~~python
while(cap.isOpened()):
  ret, frame = cap.read()
  if ret:
    filepath = "snapshot/snapshot_" + str(num) + ".jpg"
    cv2.imwrite(filepath,frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
      break
    num = num +1
  else :
    break

cap.release()
cv2.destroyAllWindows()
~~~

## 補足VideoCaptureクラス

https://docs.opencv.org/4.0.1/d8/dfe/classcv_1_1VideoCapture.html

# 5. 人間検出＿画像版

OpenCVのHOGDescriptorという学習済みモデルを使って画像中の人間を検出してみる。
結果はちょっとひどいが、一応動いてはいる。

~~~python
import cv2
from google.colab.patches import cv2_imshow

# 人間検出モデル準備
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
hogParams = {'winStride':(8,8), 'padding':(32,32), 'scale':1.05,'hitThreshold':0,'finalThreshold':5}

# 人間検出実施
img = cv2.imread("img/img01.jpg")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)         # imreadの出力はBGR形式である。BGR形式→グレースケールへ変換
human, r = hog.detectMultiScale(gray, **hogParams)  # 人間を検出

# 検出結果の四角を画像へ重ね書き
if (len(human)>0):
  for (x, y , w, h) in human:
    cv2.rectangle(img, (x,y), (x+w,y+h), (255,255,255),3)

cv2_imshow(img)
cv2.waitKey(0)
~~~


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1436941/4325cd85-48a7-d8d9-272c-d4ad92a1b43b.png)

参考
http://opencv.jp/opencv-2.1/cpp/miscellaneous_image_transformations.html

https://qiita.com/yoya/items/dba7c40b31f832e9bc2a

https://note.nkmk.me/python-opencv-bgr-rgb-cvtcolor/


# 6.人間の顔を検出＿画像版

今度は人間の顔のみを検出する。
こんどは、OpenCVのCascadeClassifier　モデルを使ってみる。
このモデル、人間の顔がどこを向いているかまで細かく設定ができる。ひとまず正面を向いている人間を検出してみると、見事に成功！！
正面ではなく多少顔を傾けている人間は検出していない。


~~~python
# 検出モデル準備
cascade_file = "haarcascade_frontalface_alt.xml"  # 正面を向いている顔の特徴ファイル
cascade = cv2.CascadeClassifier(cascade_file)

#　顔検出
img = cv2.imread("img/people-face.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face_list = cascade.detectMultiScale(gray, minSize=(50,50))

# 検出結果を描画
for (x, y , w, h) in face_list:
  color = (0,0,255)
  pen_w = 3
  cv2.rectangle(img, (x,y), (x+w,y+h), color, thickness = pen_w)

cv2_imshow(img)
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1436941/589fb29f-177a-9724-3bce-38d97948be1f.png)

下記を参考にさせて頂きますた。

https://qiita.com/tnoce/items/c819c85a85c16d246be8


# 終わり

静止画がなんとか出来たので次は動画の人検出をしてみよう。