Python opencv2, face_detector, videoメモ


##opencvを軽くいじる

```py
import cv2

#読み込み
img = cv2.imread("galaxy.jpg",0)

print(type(img))
>>><class numpy.ndarray>

#中身
print(img)
>>>[[14 18 14 ... 20 15 16]
 [12 16 12 ... 20 15 17]
 [12 13 16 ... 14 24 21]
 ...
 [ 0  0  0 ...  5  8 14]
 [ 0  0  0 ...  2  3  9]
 [ 1  1  1 ...  1  1  3]]

#(row, column)#縦長
print(img.shape)
>>>(1485, 990)

#次元数
print(img.ndim)
>>>2
```
1. `cv2.imread()`の引数において、0はgrayscale, 1はBGR, 2はblackwhiteの形式で画像を読み込む。
2. opencv2はpandasと同様にnumpyがベースになっている。
3. `numpy`objectなので`shape`で(row, column)のそれぞれの数を得られる。


##画像をリサイズ
```py

import cv2
img = cv2.imread("galaxy.jpg", 0)

#resizeだと(width, height)の順番
#interpolateする→4,6をだったら中間の5にする。#resizeだと(width, height)の順番
resized_image = cv2.resize(img, (img.shape[1]//2, img.shape[0]//2))


#画像作成
cv2.imwrite("Galaxy_resized.jpg", resized_image)
cv2.imshow("Galaxy", resized_image)
cv2.waitKey(2000) #milisecond
cv2.destroyAllWindows()
```
1. `imread`をgray scaleで読み込んだ。
2. 画像のサイズを変更するには`cv2.resize(obj, tuple)`メソッドがある。inplaceメソッドではないので、変数を用意すること。objには変更したい画像。tupleは(width, height)の形式でpixel数を指定する。(row, column)の順番ではないので注意。どんな挙動をするのか？:指定したpixel数に合うように、interpolateしていくらしい。4 6と隣り合っていたら5にする。縦方向、横方向にそれぞれに繰り返していく。きれいに見えるよ
3. `imwrite`で新規作成できる。
4. `imshow`は画像を表示する。最初の引数は、表示されるwindowの名前。なんでもいい
5. `waitKey()`はintを受け取り、数値分のmillisecond分入力待機時間を持つ。入力されたinputのascii?unicode?の数値を返す。入力がない場合は-1を返す。例)spaceなら32が返る。`waitKey(0)`だと待機時間無限。参考元：https://stackoverflow.com/questions/14494101/using-other-keys-for-the-waitkey-function-of-opencv/20577067
6. `destroyAllWindows`でwindowを閉じる。`waitkey(2000)`なので2000ms(==2s)まってからwindowが閉じる


##ヒトの顔を検知

xmlファイル元：
https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml
`cv2.CasucadeClassifier`に様々な特徴を表記したxmlファイルを渡すことで特定の特徴を持つ情報を画像から探すことができるっぽい。
ただこのxmlファイルを試した見たけど、正面を向いてる顔じゃないと検知してくれない。横顔や下を向いてたりするともうだめ。自分の顔で実験したのは、正面顔ならヒゲやマジックペンの落書き程度は検知可能。

cascade : 情報の連続的な伝達。 

```python

import cv2
#CasucadeClassifier : xmlの情報を渡す
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")


#検知する写真。gray_scaleがいい
#imread()で数値を渡さない→BGRカラー
img=cv2.imread("myface.jpg")

#BGRcolor→grayscale。imreadするとき0指定でも可能
gray_img=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#face objectを実際に検知する
faces=face_cascade.detectMultiScale(gray_img,\
scaleFactor=1.05,\
minNeighbors=5)

print(type(faces))
>>><class numpy.ndarray>
print(faces)
>>>[[542 178 383 383]]


#検知したものを四角形で囲む
for x,y,w,h in faces:
    #2つの座標を渡す。四角形の左上、右下を指定する。(tupleは色BGR緑255),3は線の太さ
    img = cv2.rectangle(img, (x,y),(x+w,y+h),(0,255,0),3)

#(width, height)のtuple
resized=cv2.resize(img, (img.shape[1]//3, img.shape[0]//3))
cv2.imshow("face", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
```

1. `face_cascade`は`cv2.CasucadeClassifier`のインスタンス。xmlファイルを渡す。xmlファイル自体は違うソフトウェア間で情報を交換するためのものらしい。詳しくは知らん。少なくともこのxmlファイルに人間の顔についての情報が記載されている
2. 顔検出をする画像を読み込む。gray scaleだと精度が上がる。が、元画像に検知した顔を書き込みたいのでBGRも変数へ保存。色に関する引数なしだとBGR。
3. 顔検知のためのgrayscale imageを作る。`cv2.cvtColor(img, 色の形式)`で色の形式を変更できる。`cv2.COLOR_BGR2GRAY`でgray→BGRカラーへ。`imread(img, 0)`で読み込んだものと同じオブジェクトが返ってくる。
4. `face_cascade.detectMultiScale`で実際に特徴検知を行う。`face_cascade`はxmlファイルを読み込んだやつ。`detectMultiScale`に検索したい画像を渡す。引数の`scaleFactor`は画像を何％の倍率で拡大検索するか。1.05なら徐々に5％ずつ拡大した画像に対して精査していく。1→1.05→1.10→1.15倍...てこと。1.5なら50％ずつ画像が拡大されて再精査されていく。引数の`minNeighbors`は数値が低いほど精度があまい＝多くの可能性が検知される。高いと可能性が絞られる。
5. `faces`は2次元でリストを要素に持つ。`numpay.ndarray`型。`[542 178 383 383]`は`[画像左辺からのx軸上の位置, 画像上辺からのy軸の位置, 四角形の横の長さ, 四角形の縦の長さ]`。つまり四角形を表現できるパーツが`faces`に入ってる。
6. `cv2.rectangle()`で上記の数値群を使い四角形の元の画像に描写する。`rectangle(対象img, (四角形左上のx座標, y座標),(四角形右下のx座標,y座標),(色),四角形の線の太さ)`。(x,y)が四角形の左上座標。w, hは前述の通り横と縦の線分の長さ。つまり足せば(x+w,y+h)は四角形右下座標。(0,255,0)は色。BGRゆえに(Blue, Green, Red)。Green255なので緑。つぎの3は四角形の線の太さ。


##PCのカメラを起動させる
要はvideo。動画ってのは画像の連続体。テレビだったらfps24とか30とか。fpsはframe per second。1秒間に何枚の画像が表示されるか。高機能紙芝居ってこと。画像を扱えれば動画も描写できる。fpsが現実の目の認識限界まで技術が発展したら、文字通りの意味で現実との区別が曖昧になる1歩になんか？

```py
#video
import cv2, time

#open camera
#videofileを渡すか、cameraのindex(pccamera,connected camera, webcameraなどのリストの)
video=cv2.VideoCapture(0)

a=0
while True:
    #反復回数。画像の枚数
    a+=1
    
    #video.read()は(boolean,実画像の形式)で返ってくる
    check, frame=video.read()
    print(check)#bool
    print(frame)#実画像 1frame
    
    #convert BGRcolor to Gray
    gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    
    #show window
    cv2.imshow("Captureing", gray)
    #1milsecondごと表示
    key=cv2.waitKey(1)
    
    if key==ord("q"):
        break

#何回繰り返したか
print(a)
video.relese()
cv2.destoryAllWindows
    
```
1. `cv2.VideoCapture(0)`でカメラと接続できる。自分はmacだからスクリーン上部の上についてるカメラが緑色にピカーひかる。USB接続されてたり、webカメラの場合はindex番号を指定すれば接続できるっぽい。
2. whileで画像を連続させる
3. `video.read()`を行うと画像を得られる。(bool値, numpy.ndarray)の形式で返る。実行してから一番最初にprint()されたnumpyオブジェクトが1frame目。
4. カメラは通常状態でBGRカラーである。灰色に画像を変更できる。
5. `cv2.imshow("Captureing", gray)`でgray scaleの画像が連続で表示され、動画になる。
6. `cv2.waitKey(1)`で1millisecondごとにwhileを繰り返す。(実際は遅延とかあるんだと思う)。"q"が入力されたらwhileの繰り返しをやめる。`ord()`は組み込み関数asciiコードで入力値の数値を返す。参考元：https://stackoverflow.com/questions/14494101/using-other-keys-for-the-waitkey-function-of-opencv/20577067
7. `video.release`でカメラ開放


##あとが
動画っておもろい。動いてるものがいい。人間の脳は止まってるものより、動いているものに集中する性質があって。記憶にも残りやすいのだとか。アニメや映画が勉強の効率にいいのは科学的な裏付けがあるんね。文字それ自体は情報の発信として非効率的なのか。教科書がうごイラだったらなぁ。