こんにちは!スタビジ編集部です!
この記事では画像認識の領域で非常によく使われるライブラリ”OpenCV“について解説していきます!
いろんなサービスで利用されていて、機械学習の中では一番イメージしやすいと思う!
ただ、すごい便利な分、中身は難しそうという偏見も多いはず、、、
今回は実際に手を動かしながら、OpenCVを通して画像認識に触れていきましょう!
OpenCVとは
“OpenCV“とは正式名称を「Open Source Computer Vision Library」と言う、コンピュータービジョン・画像認識の領域でよく使われるライブラリです!
Pythonで利用されることが多いですが、C+やJavaといった他の言語でも利用できます。
OpenCVを使うことで
- 画像の読み取り
- 画像の編集
- 特徴量の抽出
- 画像の識別
といったことが出来るようになります!
またこの他にも様々な機能がOpenCVには用意されているので、気になる方は公式HPにアクセスしてみてください!
OpenCVをPythonで使ってみる
実際にOpenCVを使って画像を表示したり加工したりしましょう!
今回は図示化を簡単に行うため”Python環境“で実装していきます。
そこで事前にOpenCVをインストールしておきましょう!
“Windows“の方はコマンドプロンプトから
pip install opencv-python
を実行してインストールします!
“Mac“の方はパッケージ管理ツールの”Homebrew”をインストールしてターミナルから
brew install opencv
を実行してインストールします!
画像を読み込む
まずは画像を読み込んでみましょう!
サンプルで猫の画像を用意して読み込んでみようと思います!
Pythonファイルを作成し、エディタを開いて必要なライブラリを読み込みます!
import matplotlib.pyplot as plt
import glob
import cv2
img = cv2.imread('./sample/cat1.jpg')
画像の読み込みには”cv2.imread関数“を使います!
読み込んだ画像の情報を見ていきましょう!
img.shape
>>(1136, 640, 3)
これは1136×640のピクセルの面がRGB(赤緑青)の3次元で重なっていることを表します!
array([[[255, 255, 255],[255, 255, 255],[255, 255, 255],..., ..., [ 64, 80, 92],[ 38, 54, 66]]], dtype=uint8)
通常、どんな画像もこのようにRGBの3次元で色を重ねて様々なカラーを表現しています!
そして各ピクセルに対してRGBの画素値を0~255で指定して、そのピクセルの色が決定します!
では、読み込んだ画像を見ていきましょう!
plt.imshow(img)
何か色がおかしいですね、、、
これはOpenCVで画像を読み込むとBGR(青緑赤)の順番で画像情報を保存します
ただ、Matplotlibでは画像をRGB(赤緑青)の順番で画像情報を読み込むため、色の不一致が起こってしまいます、、、
そこで、OpenCVで取り込んだ画像情報をBGRからRGBに変換しましょう!
img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_RGB)
“cv2.cvtColor関数“を使って画像の色情報を変更していきます!
画像の描画
次にOpenCVを用いて「画像の描画」をしていきましょう!
まずは準備段階として真っ黒の画像を用意します。
import numpy as np
import cv2
img_black = np.zeros((512,512,3), np.uint8)
plt.imshow(img_black)
np.zeros関数を用いて512×512×3の3次元配列を作成します。
そうすることで、疑似的に512×512のピクセルに色の三要素を含んだデータを表現することが出来ます。
各要素にはすべて0が入るので黒の画像が出力されます!
続いてOpenCVの関数を使って、この画像に左上から右下にかけて青の直線を引いてみます。
img_line = cv2.line(img_black,(0,0),(511,511),(255,0,0),5)
img_line = cv2.cvtColor(img_line, cv2.COLOR_BGR2RGB)
plt.imshow(img_line)
cv2.line関数を使うことで直線を引くことができます!
関数の中身はcv2.line(画像,始点,終点,色,太さ)となっていて、追加の引数で線のタイプなども選択できます!
また直線以外にも円などの他の図形や文字を描画することも出来ます!
img_circle = cv2.circle(img_line,(447,63), 63, (0,0,255), -1)
font = cv2.FONT_HERSHEY_SIMPLEX
img_text = cv2.putText(img_circle,'Python',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA)
img_draw = cv2.cvtColor(img_text, cv2.COLOR_BGR2RGB)
plt.imshow(img_draw)
いろんな描画の関数があるので調べて使ってみましょう!
画像の加工
次は「画像の加工」をやっていきましょう!
画像のスケーリングには”cv2.resize関数“を使います!
猫の画像の大きさは「1136×640」でしたが、今回は縦横ともに半分にしてみましょう
img_resize = cv2.resize(img, dsize=None, fx=0.5, fy=0.5, interpolation = cv2.INTER_CUBIC)
img_resize.shape
>>(568, 320, 3)
cv2.resize(画像,リサイズ後の大きさ,x方向の倍率,y方向の倍率,補完方法)を指定しており、画像の大きさが「568×640」と縮小したのがわかります
他にも画像の加工として、画像をぼかす方法も見ていきましょう!
画像をぼかすとは画素値の変化を滑らかにすることで平滑化とも呼び、画像のノイズ除去に使われます!
OpenCVにはいろいろなぼかし方がありますが、今回は”cv2.blur関数“を使っていきます
img_blur = cv2.blur(img,(20,20))
関数の中身はcv2.blur(画像,カーネル)となっています
このカーネルは画像の1点を決めた時のその範囲を表します!上の例だと20×20です!
そしてcv2.blur関数ではこのカーネル内の画素の平均値で、カーネル内を上書きします!
実行結果を見てみましょう!左が元の画像、右がぼかした画像です!
特徴量抽出
ここでは顔や輪郭といった「特徴量の抽出」をOpenCVでやっていきたいと思います!
輪郭の検出
まずは輪郭の抽出をしていきましょう!
輪郭の抽出の際に前処理を行っていきます!
img_contour = cv2.imread('./sample/sample4.jpg')
gray = cv2.cvtColor(img_contour, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 170, 255, cv2.THRESH_BINARY)
前処理では「画像を白と黒の2値化」します!
まず対象の画像を読み込んだ後、その画像をグレースケールし、画像をRGBの3原色からグレーの単一色に変換します!
画像の各ピクセルはグレーの画素値(0~255)で濃淡が表現されます!
その後”cv2.threshold関数“を用いて各ピクセルを白か黒かに変換します!
この関数の中身はcv2threshold(画像,閾値,最大値,2値化の方法)となっており、”ret”には閾値、”thresh”には2値化した画像を返します
今回は2値化の方法に「cv2.THRESH_BINARY」を設定しており、これは閾値以下の値を「0」それ以外の値を「最大値」として変換する方法です!
では画像を白と黒の2値化したところで輪郭の抽出を行っていきます
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = list(filter(lambda x: cv2.contourArea(x) > 100, contours))
輪郭の抽出には”cv2.findContours関数“を使用します!
関数の中身はcv2.findContours(入力画像,輪郭の抽出方法,輪郭を近似する方法)となっており、”contours”に抽出した輪郭のリスト、”hierarchy”に階層構造のリストを返します
今回、輪郭の抽出方法は最も外側の輪郭のみを抽出する「cv2.RETR_EXTERNAL」を設定しています
輪郭を近似する方法に関しては基本的に「cv2.CHAIN_APPROX_SIMPLE」を選択すればよいです
また、小さな箇所も輪郭として判定されてしまうので、小さな輪郭はフィルターで削除しておきましょう!
最後に輪郭を元の画像に書き込んでいきましょう!
output = cv2.drawContours(img_contour, contours, -1, (0,0,255),15)
output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
plt.imshow(output)
検出した輪郭を画像に描画するのは”cv2.drawContours“関数を使います
関数の中身はcv2.drawContours(画像,検出した輪郭のリスト,描画したい輪郭のインデックス,輪郭線の色,輪郭線の太さ)となっています
今回は検出した輪郭のリストをすべて描画したいので、その時は「描画したい輪郭のインデックス」に”-1″を指定します!
実行結果がこちらになります!左が元画像、右が輪郭を描画した画像です!
顔検出
続いて顔検出を見ていきましょう
OpenCVではあらかじめいくつかの事前に学習を済ませた学習機を提供しており,顔,目,笑顔などの検出を事前に学習データを用意せずとも実行できます!
これらの学習データはダウンロードしたcv2パッケージのdataフォルダ(例⇒C:\Users\ユーザ名\anaconda3\Lib\site-packages\cv2\data)にXMLファイルとして保存されています
まずはXMLファイルから顔検出器を読み込みます
face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_default.xml')
img_face = cv2.imread('./sample/face4.jpg')
img_face_gray = cv2.cvtColor(img_face, cv2.COLOR_BGR2GRAY)
検出器の読み込みには”cv2.CascadeClassifier関数“を使います!今回は正面の顔のデータを利用しています!
img_face_gray = cv2.cvtColor(img_face, cv2.COLOR_BGR2GRAY)
ここでは判別したい画像データをグレースケールしています!
顔検出ではかなりざっくりいうとある領域とある領域の画素数の総和の差を特徴量として算出し、それをあらゆるサイズ・位置で計測して顔の特徴を決定しています
なので、顔検出の精度をよくするために判別したい画像を白と黒の濃淡であらわすグレーに変換する処理を行っています!
では顔検出をしていきます!
faces = face_cascade.detectMultiScale(img_face_gray)
for (x,y,w,h) in faces:
img_face = cv2.rectangle(img_face,(x,y),(x+w,y+h),(255,0,0),2)
img_face = cv2.cvtColor(img_face, cv2.COLOR_BGR2RGB)
plt.imshow(img_face)
“face_cascade.detectMultiScale()関数“で顔判定された部分の座標が格納されています!
for文ではその情報を用いて顔と判定された箇所それぞれに対して枠線をつけています!
実行結果がこちらになります!
Pythonで実践するOpenCVの使い方まとめ
ここまでOpenCVとは?~実際の使い方まで解説していきました!
Pythonの環境で手軽に「画像の読み込み」から「顔検出」まで画像に関していろんなことを確認できたと思います!
ただ、今回紹介したことの他にもまだまだOpenCVを使って出来ることはたくさんあるのでぜひ試してみてください!
OpenCVを使って画像認識をやってみたいという方は以下の記事でまとめておりますので、是非チェックしてみてください!
また、Pythonで出来ることに興味がある方は是非以下の記事も見てみてください!