今回は、OpenCVとpythonを使って画像内にいる人の検出をしてみましょう。
1.環境
言語:python
エディタ:spyder
2.処理の流れ
①”opencv”ライブラリのインポート
②画像の読み込みグレースケール化
③読み込んだ画像の二値化
④対象物の輪郭の抽出
⑤輪郭の面積を計算
⑥算出面積でフィルタリング
⑦外接矩形を求める
⑧処理後の画像を保存
⑨処理終了
3.ソースコード
# -*- coding: utf-8 -*- #ライブラリのインポート import cv2 path = r"C:\Users\ユーザー名\ディレクトリ名" #元画像の読み込み img = cv2.imread("sample_video_img_000.jpg") #読み込んだ画像をグレースケールに変換 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #画像を二値化する R, binary = cv2.threshold(gray,10,255,cv2.THRESH_BINARY) #輪郭を算出 contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) k = 0 for i in range(0, len(contours)): #各輪郭の処理:輪郭の面積を計算 area = cv2.contourArea(contours[i]) #ノイズ等を除去するために面積でフィルタ if area < 1e2 or 1e5 < area: continue #外接矩形 if len(contours[i]) > 0: rect = contours[i] x,y,w,h = cv2.boundingRect(rect) cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) k = k + 1 cv2.imwrite(path + "/" + str(k) +".jpg",img[y:y + h, x:x + w]) #処理後の画像を表示 cv2.imshow('out_picture', img) cv2.imwrite(path + "/" + "save_pic.jpg", img) cv2.waitKey(0) #処理終了 cv2.destroyAllWindows()
3.ソースコード詳細
#ライブラリのインポート import cv2 path = r"C:\Users\ユーザー名\ディレクトリ名"
いつも通りライブラリのインポートしましょう。
import モジュール名
from モジュール名 import オブジェクト名
#元画像の読み込み img = cv2.imread("sample_video_img_000.jpg") #読み込んだ画像をグレースケールに変換 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imread()関数を使用して今回使用する画像を読み込む
cv2.imread(“引数1:使用する画像のファイルパスを指定する”)
引数1:使用する画像パス
読み込んだ画像をグレースケールに変換するには、cv2.cvtColor()関数を使用します。
cv2.cvtColor()関数は、BGRやRGB、HSVなどの色空間を変換することができます。
cv2.cvtColor(引数1:画像, 引数2:code)
引数1:読み込んだ画像
引数2:色空間を変換方法を指定
引数2の詳細コードは以下のURLを参照してください。
読み込んだ画像とグレースケール化した画像は以下の通りです。
#画像を二値化する R, binary = cv2.threshold(gray,10,255,cv2.THRESH_BINARY)
二値化するにはcv2.threshold()関数を使用します。
out1,out2 = cv2.threshold(引数1:入力画像,引数2:しきい値の最小値,引数3:しきい値の最大値,引数4:しきい値処理法)
引数1:入力画像(グレースケール化した画像)
引数2:しきい値の最小値
引数3:しきい値の最大値
引数4:しきい値処理法を指定(詳細は下の表を参照)
二値化した画像は以下の通りです。
#輪郭を算出 contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
二値化した画像から黒い部分の輪郭を抽出します。
そこで、cv2.findContours()関数を使用して、輪郭を抽出します。
contours, hierarchy = cv2.findContours(引数1:入力画像(二値化した画像), 引数2:輪郭の検出方法, 引数3:輪郭の近似法)
引数1:入力画像(二値化した画像)
引数2:輪郭の検出方法(以下の4つ)
・RETR_LIST
・RETR_EXTERNAL
・RETR_CCOMP
・RETR_TREE
引数3:輪郭の近似方法(輪郭を抽出するには、すべての輪郭の点は必要なく、輪郭を描画するのに最低限必要な点を以外を除き輪郭の情報を圧縮する方法)
出力される結果は、contours:抽出された輪郭, hierarchy:輪郭の階層情報の2つになります。
今回の画像と条件でコードを実行した場合、抽出された輪郭情報が186個となったため、次の段階で精査していきます。
k = 0 for i in range(0, len(contours)): #各輪郭の処理:輪郭の面積を計算 area = cv2.contourArea(contours[i]) #ノイズ等を除去するために面積でフィルタ if area < 1e2 or 1e5 < area: continue #外接矩形 if len(contours[i]) > 0: rect = contours[i] x,y,w,h = cv2.boundingRect(rect) cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) k = k + 1 #画像の保存 cv2.imwrite(path + "/" + str(k) +".jpg",img[y:y + h, x:x + w]) #処理後の画像を表示 cv2.imshow('out_picture', img) cv2.imwrite(path + "/" + "save_pic.jpg", img) cv2.waitKey(0)
処理の流れとしては、まず必要な輪郭だけを残すために、輪郭の面積を算出しフィルタリングしていきます。
輪郭の面積の算出は、cv2.contourArea()関数を使用します。引数には、抽出した輪郭contoursを使用します。
area = cv2.contourArea(引数:面積を求めたい領域の入力)
その後、外接矩形作成し表示をしていきます。
cv2.boundingRect()関数を使用すると、輪郭に外接する長方形を取得できます。
x, y, w, h = cv2.boundingRect(引数:輪郭)
引数:輪郭は先程、上記で求めた輪郭:contoursを使用します。
出力される情報は、(x, y)座標、さらに輪郭の幅(w)と高さ(h)情報も取得します。
最後に、cv2.rectangle()関数を使用して輪郭から取得した情報から矩形を作成していきます。
cv2.rectangle()関数は、左上と右下の角の座標を指定して長方形を描画する関数です。
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
引数1:適用画像(ここはオリジナル画像を指定)
引数2:左上の座標を指定(今回は輪郭から抽出した点)
引数3:右上の座標を指定(左上の座標に幅と高さ情報を追加した点)
以下の画像が矩形画像+オリジナル画像結果を表示します。
今回の抽出結果は、建物や車等の黒くなった部分が抽出されてしましました。やはり二値化の段階でうまく人物だけを抽出できるようにしなければ、なかなか人だけの抽出は難しそうですね。
#処理終了 cv2.destroyAllWindows()
最後は終了処理になります。
4.最後に
今回は静止画を使用して人物を外接矩形で検出するという作業をしました。
次回は、前回記事にしたフレーム間差分を使用して、動画の人物を検出し矩形で囲みトレースする処理に挑戦してみます。
[adchord]
コメント