長野エンジニアライフ

東京から長野に移住したエンジニアのブログです。🦒🗻⛰

Python + OpenCV4プログラミングの学習(4)〜アフィン変換〜

本記事はOpenCVによるアフィン変換を行ったときの備忘録である。

アフィン変換とは...
図形を回転させたり引き延ばしたりする変換 ja.wikipedia.org

事前準備

以下の記事で仮想環境opencvEnvを構築していることを前提とする。 kawakeee.hatenablog.com

また、任意の画像を用意しておく。今回はLenna.jpgを用意した。

Lenna

フリップ

以下のコードを写経しflip.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像を上下反転させる
  dst = cv2.flip(img, 0)
  cv2.imwrite('img/flip0.jpg', img)
  cv2.imshow('dst1', dst)

  # 画像を左右反転させる
  dst = cv2.flip(img, 1)
  cv2.imwrite('img/flip1.jpg', img)
  cv2.imshow('dst2', dst)

  # 画像を両軸反転させる
  dst = cv2.flip(img, -1)
  cv2.imwrite('img/flip2.jpg', img)
  cv2.imshow('dst3', dst)

  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))
  • cv2.flip(...):画像をフリップ(反転)させる
    使用例:cv2.flip(img, 0)
    引数は、順に(対象画像データ, フリップ方向)を表す。 以下のように、フリップ方向の値により反転軸を指定できる。
フリップ方向の値 反転方向
0に等しい 上下反転
左右反転
両軸反転

実行結果

(opencvEnv)$ python filp.py

指定フォルダ配下にフリップされた画像が生成されていることを確認。
OpenCVによるフリップ変換

リサイズ

以下のコードを写経しresize.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  SCALE = 0.5
  SCALE2 = 1.62
  # 画像の高さ・幅を取得
  height = img.shape[0]
  width = img.shape[1]

  # 画像を半分(0.5乗じる)のサイズにリサイズ
  dst = cv2.resize(img, (int(width*SCALE), int(height*SCALE)))
  cv2.imwrite('img/resize0.5.jpg', dst)
  cv2.imshow('dst1', dst)

  # 画像を1.62乗じてリサイズ
  dst = cv2.resize(img, (int(width*SCALE2), int(height*SCALE2)))
  cv2.imwrite('img/resize1.62.jpg', dst)
  cv2.imshow('dst2', dst)

  # 画像を縦を圧縮してリサイズ
  dst = cv2.resize(img, (400, 200))
  cv2.imwrite('img/resize400*200.jpg', dst)
  cv2.imshow('dst3', dst)

  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

変数SCALEを用意して半分(0.5をかける)のサイズにリサイズしている。

  • cv2.resize(...):画像をリサイズする
    使用例:cv2.resize(img, (400, 200))
    引数は、順に(対象画像,幅, 高さ)を表す。

    実行結果

(opencvEnv)$ python resize.py

指定フォルダ配下にリサイズされた画像が生成されていることを確認。
OpenCVによるリサイズ

回転

以下のコードを写経しrotate.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像の高さ・幅を取得
  height = img.shape[0]
  width = img.shape[1]
  # 回転原点座標を生成
  center = (int(width/2), int(height/2))

  # 回転変換行列の生成 (回転原点座標, 回転角度, スケーリング値)
  affin_trans = cv2.getRotationMatrix2D(center, 33.0, 1.0)
  # 回転変換処理 (対象画像, 回転変換行列, 出力配列(画像サイズの指定))
  dst = cv2.warpAffine(img, affin_trans, (width, height))
  cv2.imwrite('img/rotate033.jpg', dst)
  cv2.imshow('dst1', dst)

  affin_trans = cv2.getRotationMatrix2D(center, 110.0, 1.2)
  dst = cv2.warpAffine(img, affin_trans, (width, height), flags=cv2.INTER_CUBIC)
  cv2.imwrite('img/rotate110.jpg', dst)
  cv2.imshow('dst2', dst)

  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

順に、対象画像を反時計周りの方向に33°、110°回転させる。

  • cv2.getRotationMatrix2D(...):回転変換行列の生成
    使用例:cv2.getRotationMatrix2D(center, 33.0, 1.0)
    引数は、順に(回転原点座標,回転角度,スケーリング値)を表す。
  • cv2.warpAffine(...):画像のアフィン変換を実行
    使用例:cv2.warpAffine(img, affin_trans, (width, height))
    引数は、順に(対象画像,変換行列,出力配列(画像サイズ))を表す。

実行結果

(opencvEnv)$ python rotate.py

指定フォルダ配下に回転された画像が生成されていることを確認。
OpenCVによる回転処理

透視投影

以下のコードを写経しperspective.pyのファイルを作成。

import cv2
import numpy as np

try:
  # (225 * 225)の画像
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像の列・行の大きさを取得
  rows,cols = img.shape[:2]
  x0 = cols/4
  x1 = (cols*3)/4
  y0 = rows/4
  y1 = (rows*3)/4

  # 入力の座標を指定
  list_srcs = np.float32([
    [x0, y0],
    [x0, y1],
    [x1, y1],
    [x1, y0]
  ])

  # pattern-0
  x_margin = cols/10
  y_margin = rows/10

  # 出力の座標を指定(台形)
  list_dsts = np.float32([
    [x0+x_margin, y0+y_margin],
    list_srcs[1],
    list_srcs[2],
    [x1-x_margin, y0+y_margin]
  ])
  # 透視変換行列の生成 (入力座標, 出力座標)
  perspective_matrix = cv2.getPerspectiveTransform(list_srcs, list_dsts)
  # 画像の透視投影処理 (対象画像, 透視変換行列, 出力配列(画像サイズの指定))
  dst = cv2.warpPerspective(img, perspective_matrix, (cols, rows))
  cv2.imwrite('img/dst0.jpg', dst)
  cv2.imshow('dst0', dst)

  #pattern-1
  x_margin = cols/8
  y_margin = rows/8
  list_dsts = np.float32([list_srcs[0],list_srcs[1],[x1-x_margin, y1-y_margin],[x1-x_margin, y0+y_margin]])
  perspective_matrix = cv2.getPerspectiveTransform(list_srcs,list_dsts)
  dst = cv2.warpPerspective(img, perspective_matrix, (cols, rows))
  cv2.imwrite('img/dst1.jpg', dst)
  cv2.imshow('dst1', dst)

  #pattern-2
  x_margin = cols/6
  y_margin = rows/6
  list_dsts = np.float32([[x0+x_margin, y0+y_margin],list_srcs[1],[x1-x_margin, y1-y_margin],list_srcs[3]])
  perspective_matrix = cv2.getPerspectiveTransform(list_srcs,list_dsts)
  dst = cv2.warpPerspective(img, perspective_matrix, (cols, rows))
  cv2.imwrite('img/dst2.jpg', dst)
  cv2.imshow('dst2', dst)

  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

list_srcsに入力座標、list_dstsに出力座標を指定し、3パターンの透視投影を実行。

  • cv2.getPerspectiveTransform(...):透視変換行列の生成
    使用例:cv2.getPerspectiveTransform(list_srcs, list_dsts)
    引数は、順に(入力座標,出力座標)を表す。返戻値は引数に対する透視変換行列。
  • cv2.warpPerspective(...):画像の透視投影を実行
    使用例:cv2.warpPerspective(img, perspective_matrix, (cols, rows))
    引数は、順に(対象画像,透視変換行列,出力配列(画像サイズ))を表す。

実行結果

(opencvEnv)$ python perspective.py

指定フォルダ配下に透視投影された画像が生成されていることを確認。
OpenCVによる透視投影

トリミング

以下のコードを写経しtrimming.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像の高さ・幅を取得
  height = img.shape[0]
  width = img.shape[1]

  # imgをスライス処理してトリミング
  dst = img[40:height, 40:width]
  cv2.imwrite('img/Trimming.jpg', dst)
  cv2.imshow('dst0', dst)
  
  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

トリミングはimgに対してスライスする事で可能。元画像の上部、左側の40pxを除去させる。

実行結果

(opencvEnv)$ python trimming.py

指定フォルダ配下にトリミングされた画像が生成されていることを確認。
OpenCVによるトリミング処理

まとめ

  • cv2.flip(...):画像をフリップ(反転)させる
  • cv2.getRotationMatrix2D(...):回転変換行列の生成
  • cv2.warpAffine(...):画像のアフィン変換を実行
  • cv2.getPerspectiveTransform(...):透視変換行列の生成
  • cv2.warpPerspective(...):画像の透視投影を実行

ソースコード

github.com

Python + OpenCV4プログラミングの学習(3)〜グラフィックス〜

本記事はOpenCVによるグラフィックスを行ったときの備忘録である。

事前準備

以下の記事で仮想環境opencvEnvを構築していることを前提とする。 kawakeee.hatenablog.com

円を描く

以下のコードを写経しcircle.pyのファイルを作成。

import numpy as np
import cv2

# 画像データ(400×400 px)の生成
img = np.zeros((400, 400, 3), np.uint8)
# 円の描写 (対象画像データ, 中心座標, 半径, 色情報, 円の太さ)
cv2.circle(img, (200, 200), 50, (255, 0, 0) ,1)
cv2.imwrite('img/circle1.jpg', img)
cv2.imshow('img1', img)

img = np.zeros((400, 400, 3), np.uint8)
# 半径 色 太さ を変更 
cv2.circle(img, (200, 200), 100, (0, 255, 0) ,3)
cv2.imwrite('img/circle2.jpg', img)
cv2.imshow('img2', img)

img = np.zeros((400, 400, 3), np.uint8)
# 半径 色 太さ を変更
cv2.circle(img, (200, 200), 150, (0, 0, 255) ,-1)
cv2.imwrite('img/circle3.jpg', img)
cv2.imshow('img3', img)

cv2.waitKey(0)
cv2.destroyAllWindows()
  • cv2.circle(...):円の描写
    使用例:cv2.circle(img, (200, 200), 50, (255, 0, 0) ,1)
    引数は、順に(対象画像データ, 中心座標, 半径, 色情報, 円の太さ)を表す。

cv2.waitKey(0)によってキーが押されるまで以降のコードは実行されない。何かのキーが押されるとcv2.destroyAllWindows()で全てのウィンドウが閉じられてプログラムが終了する。

実行確認

(opencvEnv)$ python circle.py

指定フォルダ配下に画像が生成されていることを確認。
OpenCV4による円の描写

また、cv2.imshowによってウィンドウで画像が表示される事を確認。
ウィンドウで表示される事を確認

線を描く

次に、任意の画像に対して線を描く。今回はLenna.jpgを用意した。

Lenna

以下のコードを写経しlines_on_image.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像に対して線を描く (対象画像, 始点, 終点, 色)
  cv2.line(img, (50, 50), (200, 50), (255, 0, 0))
  # 追加して太さも指定
  cv2.line(img, (50, 100), (200, 100), (0, 255, 0), 5)
  cv2.imwrite('img/LinesOnImage.jpg', img)
  cv2.imshow('img', img)
  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))
  • cv2.line(...):線の描写
    使用例:cv2.line(img, (50, 50), (200, 50), (255, 0, 0)) 引数は、順に(対象画像, 始点, 終点, 色)を表す。

実行結果

(opencvEnv)$ python lines_on_image.py

指定フォルダ配下にLinesOnImage.jpg生成され、線が描写された画像がウィンドウに表示される事を確認。
OpenCVによって画像に線が描写されている事を確認

画像上に円を描く

次に、Lenna.jpgに対してを描く。 以下のコードを写経しcircles_on_image.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像に対して円を描く
  cv2.circle(img, (50, 50), 40, (0, 255, 0), 2)
  cv2.circle(img, (150, 150), 80, (255, 255, 0), 6)
  cv2.circle(img, (200, 200), 50, (0, 255, 255), -1)
  cv2.imwrite('img/CirclesOnImage.jpg', img)
  cv2.imshow('img', img)
  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))

円・線の描写で学んだ関数を使用し画像上に3つの円を描くよう記述。

実行結果

(opencvEnv)$ python circles_on_image.py

指定フォルダ配下にCirclesOnImage.jpg生成され、円が描写された画像がウィンドウに表示される事を確認。
OpenCVを利用した円描写

画像上に文字を描く

次に、Lenna.jpgに対して文字を描く。
以下のコードを写経しdraw_text.pyのファイルを作成。

import cv2

try:
  img = cv2.imread('img/Lenna.jpg')
  if img is None:
    print('ファイルを読み込めません')
    import sys
    sys.exit()
  
  # 画像に対して文字を描く
  cv2.putText(img, 'Hello OpenCV', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
     (150, 60, 80), 2)
  cv2.imwrite('img/puttext.jpg', img)
  cv2.imshow('img', img)
  cv2.waitKey(0)
  cv2.destroyAllWindows()

except:
  import sys
  print("Error:", sys.exc_info()[0])
  print(sys.exc_info()[1])
  import traceback
  print(traceback.format_tb(sys.exc_info()[2]))
  • cv2.putText(...):文字の描写
    使用例:cv2.putText(img, 'Hello OpenCV', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (150, 60, 80), 2) 引数は、順に(対象画像,文字列,表示位置, フォント,サイズ,色,太さ)を表す。

実行結果

(opencvEnv)$ python draw_text.py

指定フォルダ配下にputtext.jpg生成され、文字が描写された画像がウィンドウに表示される事を確認。
OpenCVによる文字描写

まとめ

  • cv2.circle(...):円の描写
  • cv2.line(...):線の描写
  • cv2.putText(...):文字の描写

ソースコード

github.com

Python + OpenCV4プログラミングの学習(2)〜画像生成・読み込み・書き込み〜

本記事はOpenCVによる画像生成・読込・書込を行ったときの備忘録である。

事前準備

以下の記事で仮想環境opencvEnvを構築していることを前提とする。 kawakeee.hatenablog.com

画像を生成する

以下のコードを写経しcreate_img.pyのファイルを作成。

import numpy as np
import cv2

# 画像情報(3次元配列)の生成 (行、列、色)
img = np.zeros((400, 400, 3), np.uint8)

img[:,:] = [255, 0, 0]
# 生成したimgを指定ファイルとして保存
cv2.imwrite('img/blueImage.jpg', img)
# imgを表示
cv2.imshow('img1', img)

img[:,:] = [0, 255, 0]
cv2.imwrite('img/greenImage.jpg', img)
cv2.imshow('img2', img)

img[:,:] = [0, 0, 255]
cv2.imwrite('img/redImage.jpg', img)
cv2.imshow('img3', img)

cv2.waitKey(0)
cv2.destroyAllWindows()
  • cv2.imwrite(...):画像情報の保存(書き込み)
  • cv2.imshow(...):画像情報の表示

実行確認

(opencvEnv)$ python create_img.py

指定フォルダ配下に画像が生成されていることを確認。 画像情報が生成されていることを確認

また、cv2.imshowによってウィンドウで画像が表示される事を確認。 画像表示の確認

画像の読み込み・書き込み

任意の画像ファイルを用意する。今回はLenna.jpgを用意した。

Lenna

以下のコードを写経しread_write.pyのファイルを作成。

import cv2

# 画像情報の読み込み
img = cv2.imread('img/Lenna.jpg')
# 画像情報の保存(書き込み)
cv2.imwrite('img/ReadWrite.jpg', img)
  • cv2.imread(...):画像情報の読み込み

実行結果

(opencvEnv)$ python read_write.py

指定フォルダ配下にReadWrite.jpg生成されていることを確認する。
ReadWriteが生成されている事を確認

まとめ

  • cv2.imwrite(...):画像情報の保存(書き込み)
  • cv2.imread(...):画像情報の読み込み
  • cv2.imshow(...):画像情報の表示

ソースコード

github.com

Python + OpenCV4プログラミングの学習(1)〜開発環境の準備〜

本記事ではOpenCVが動作する開発環境構築の備忘録である。

事前確認

参考書籍ではAnacondaを使って学習を進めていくようだが、面倒なのでサクッとOpenCVが正常に動作する仮想環境を作る。

仮想環境の準備

仮想環境opencvEnvをvenvで作成

$ python3 -m venv opencvEnv

# activate しておく
$ source opencvEnv/bin/activate

(opencvEnv)$  ...

OpenCVのインストール

pip installOpenCVをイントール

(opencvEnv)$ pip install opencv-python

Collecting opencv-python
  Downloading https://files.pythonhosted.org/packages/e2/a9/cd3912ca0576ea6588095dce55e54c5f0efeb3d63fb88f16f4c06c0fac8d/opencv_python-4.1.2.30-cp36-cp36m-macosx_10_9_x86_64.whl (45.2MB)
    100% |████████████████████████████████| 45.2MB 721kB/s
Collecting numpy>=1.11.3 (from opencv-python)
  Using cached https://files.pythonhosted.org/packages/22/99/36e3408ae2cb8b72260de4e538196d17736d7fb82a1086cb2c21ee156ddc/numpy-1.17.4-cp36-cp36m-macosx_10_9_x86_64.whl
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.17.4 opencv-python-4.1.2.30
import cv2

pip freezeでOpenCV4以上がインストールされた事を確認。

(opencvEnv)$ pip freeze
numpy==1.18.1
opencv-python==4.1.2.30

実行確認

以下のコードを写経しhello_opencv.pyのファイルを作成。

import cv2

print(cv2.__version__)

hello_opencv.pyを実行し4.1.2が表示されれば開発環境の準備は完了。

(opencvEnv)$ python hellow_opencv.py
4.1.2

(実行結果はOpenCVのバージョンによって変わる)

ソースコード

github.com

Python + OpenCVで顔検出(3)〜検出箇所のみに画像トリミング〜

こちらの記事で、リアルタイムカメラから顔検出→画像生成するところまでできた。 kawakeee.hatenablog.com

今回は、顔検出したタイミングで顔検出部分の画像ファイル(jpg)を生成させる。

顔検出箇所をトリミング

顔検出時に黒枠で囲む際の座標情報を用いて、フレームをトリミングする。 【一部抜粋】

# 検出した顔に印を付ける
for (x, y, w, h) in face_list:
    color = (0, 0, 225)
    pen_w = 3
    cv2.rectangle(img_gray, (x, y), (x+w, y+h), color, thickness = pen_w)
    # face_image:顔検出した部分だけにトリミングする
    face_image = img_gray[y:y+h, x:x+w]

【全文】

import cv2

if __name__ == '__main__':
    # 定数定義
    ESC_KEY = 27     # Escキー
    INTERVAL= 33     # 待ち時間
    FRAME_RATE = 30  # fps

    ORG_WINDOW_NAME = "org"
    GAUSSIAN_WINDOW_NAME = "gaussian"

    DEVICE_ID = 0

    # 分類器の指定
    cascade_file = "../xml/haarcascade_frontalface_alt2.xml"
    cascade = cv2.CascadeClassifier(cascade_file)

    # カメラ映像取得
    cap = cv2.VideoCapture(DEVICE_ID)

    # 初期フレームの読込
    end_flag, c_frame = cap.read()
    height, width, channels = c_frame.shape

    # ウィンドウの準備
    cv2.namedWindow(ORG_WINDOW_NAME)
    cv2.namedWindow(GAUSSIAN_WINDOW_NAME)

    # 連番の生成
    n = 0

    # 変換処理ループ
    while end_flag == True:

        # 画像の取得と顔の検出
        img = c_frame
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

        # 検出した顔に印を付ける
        for (x, y, w, h) in face_list:
            color = (0, 0, 225)
            pen_w = 3
            cv2.rectangle(img_gray, (x, y), (x+w, y+h), color, thickness = pen_w)
            # face_image:顔検出した部分だけにトリミングする
            face_image = img_gray[y:y+h, x:x+w]

        # フレーム表示
        cv2.imshow(ORG_WINDOW_NAME, c_frame)
        cv2.imshow(GAUSSIAN_WINDOW_NAME, img_gray)

        # 顔が検出されたらjpgファイルを生成する
        if type(face_list) is not tuple :
            # face_imageを画像ファイルとして生成する
            cv2.imwrite('{}_{}.{}'.format('../images/trim/face', n, 'jpg'), face_image)
            n += 1
        
        # Escキーで終了
        key = cv2.waitKey(INTERVAL)
        if key == ESC_KEY:
            break

        # 次のフレーム読み込み
        end_flag, c_frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()

実行

pictureフォルダ(画面右)に、顔検出がされる度に顔検出箇所部分のみにトリミングされた画像ファイルが生成される事を確認。
トリミングされた顔画像

ソースコード

今回のソースコードは以下のリポジトリface_detect_trim.pyから転載。
github.com

参考記事

OpenCVの画像トリミングについての参考記事
www.pynote.info

Python + OpenCVで顔検出(2)〜検出時のフレーム画像をキャプチャ〜

こちらの記事で、リアルタイムカメラから顔検出するところまでできた。 kawakeee.hatenablog.com

今回は、顔検出したタイミングで画像ファイル(jpg)を生成させる。

顔検出時に条件分岐を追加

前回のface_detect.pyにてface_listに顔検出情報が格納されると、型がtupleからndarrayに変更されるため、型を条件に画像ファイルを保存するかしないか判定する。
【一部抜粋】

# 顔が検出されたらjpgファイルを生成する
if type(face_list) is not tuple :
    cv2.imwrite('{}_{}.{}'.format('../images/capture/face', n, 'jpg'), c_frame)

【全文】

import cv2

if __name__ == '__main__':
    # 定数定義
    ESC_KEY = 27     # Escキー
    INTERVAL= 33     # 待ち時間
    FRAME_RATE = 30  # fps

    ORG_WINDOW_NAME = "org"
    GAUSSIAN_WINDOW_NAME = "gaussian"

    DEVICE_ID = 0

    # 分類器の指定
    cascade_file = "../xml/haarcascade_frontalface_alt2.xml"
    cascade = cv2.CascadeClassifier(cascade_file)

    # カメラ映像取得
    cap = cv2.VideoCapture(DEVICE_ID)

    # 初期フレームの読込
    end_flag, c_frame = cap.read()
    height, width, channels = c_frame.shape

    # ウィンドウの準備
    cv2.namedWindow(ORG_WINDOW_NAME)
    cv2.namedWindow(GAUSSIAN_WINDOW_NAME)

    # 連番の生成
    n = 0
    
    # 変換処理ループ
    while end_flag == True:

        # 画像の取得と顔の検出
        img = c_frame
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

        # 検出した顔に印を付ける
        for (x, y, w, h) in face_list:
            color = (0, 0, 225)
            pen_w = 3
            cv2.rectangle(img_gray, (x, y), (x+w, y+h), color, thickness = pen_w)

        # フレーム表示
        cv2.imshow(ORG_WINDOW_NAME, c_frame)
        cv2.imshow(GAUSSIAN_WINDOW_NAME, img_gray)

        # 顔が検出されたらjpgファイルを生成する
        if type(face_list) is not tuple :
            cv2.imwrite('{}_{}.{}'.format('../images/capture/face', n, 'jpg'), c_frame)
            n += 1
        
        # Escキーで終了
        key = cv2.waitKey(INTERVAL)
        if key == ESC_KEY:
            break

        # 次のフレーム読み込み
        end_flag, c_frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()

実行

pictureフォルダ(画面右)に、顔検出がされる度に画像ファイルが生成される事を確認。
デモ

ソースコード

今回のソースコードは以下のリポジトリface_detect_cap.pyから転載。
github.com

参考記事

この記事ではボタン押下時に画像ファイルを生成している。 note.nkmk.me

Python + OpenCVで顔検出(1)〜リアルタイムカメラから検出〜

qiita.com 上の記事を参考にOpenCVで顔検出したときのメモ

仮想環境の準備

opencvEnvの環境をvenvで作成

$ python3 -m venv opencvEnv

# activate しておく
$ source opencvEnv/bin/activate

(opencvEnv)$  ...

openCVのインストール

pipでopenCVをイントール

(opencvEnv)$ pip install opencv-python

Collecting opencv-python
  Downloading https://files.pythonhosted.org/packages/e2/a9/cd3912ca0576ea6588095dce55e54c5f0efeb3d63fb88f16f4c06c0fac8d/opencv_python-4.1.2.30-cp36-cp36m-macosx_10_9_x86_64.whl (45.2MB)
    100% |████████████████████████████████| 45.2MB 721kB/s
Collecting numpy>=1.11.3 (from opencv-python)
  Using cached https://files.pythonhosted.org/packages/22/99/36e3408ae2cb8b72260de4e538196d17736d7fb82a1086cb2c21ee156ddc/numpy-1.17.4-cp36-cp36m-macosx_10_9_x86_64.whl
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.17.4 opencv-python-4.1.2.30
import cv2

顔検出のプログラム準備

face_ detect.pyを作成する

【face_ detect.py】

import cv2

if __name__ == '__main__':
    # 定数定義
    ESC_KEY = 27     # Escキー
    INTERVAL= 33     # 待ち時間
    FRAME_RATE = 30  # fps

    ORG_WINDOW_NAME = "org"
    GAUSSIAN_WINDOW_NAME = "gaussian"

    DEVICE_ID = 0

    # 分類器の指定
    cascade_file = "../xml/haarcascade_frontalface_alt2.xml"
    cascade = cv2.CascadeClassifier(cascade_file)

    # カメラ映像取得
    cap = cv2.VideoCapture(DEVICE_ID)

    # 初期フレームの読込
    end_flag, c_frame = cap.read()
    height, width, channels = c_frame.shape

    # ウィンドウの準備
    cv2.namedWindow(ORG_WINDOW_NAME)
    cv2.namedWindow(GAUSSIAN_WINDOW_NAME)

    # 変換処理ループ
    while end_flag == True:

        # 画像の取得と顔の検出
        img = c_frame
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

        # 検出した顔に印を付ける
        for (x, y, w, h) in face_list:
            color = (0, 0, 225)
            pen_w = 3
            cv2.rectangle(img_gray, (x, y), (x+w, y+h), color, thickness = pen_w)

        # フレーム表示
        cv2.imshow(ORG_WINDOW_NAME, c_frame)
        cv2.imshow(GAUSSIAN_WINDOW_NAME, img_gray)

        # Escキーで終了
        key = cv2.waitKey(INTERVAL)
        if key == ESC_KEY:
            break

        # 次のフレーム読み込み
        end_flag, c_frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()

分類器のファイルを取得

顔検出に使用するhaarcascade_frontalface_alt2.xmlを以下のサイトから取得し、任意の場所にファイルをダウンロードする。 ja.osdn.net

実行

face_ detect.pyを実行する。ターミナルからカメラのアクセス許可を求めらるので許可する。

(opencvEnv)$ python face_ detect.py

カメラで取得できる映像から顔検出することができる。カメラは[Esc]で強制終了できる。 opencv_動作確認

ソースコード

今回のソースコードは以下のリポジトリface_detect.pyから転載。

github.com