Python + OpenCVで顔認識
OpenCVで画像処理を試してみたついでに、ドキュメントを斜め読みしていたら、顔認識に関するチュートリアル(OpenCV: Face Detection using Haar Cascades)があった。最近、人の顔を覚えられなくなってきているオレを助けてくれそ うなテクノロジーではある。
Haar Cascadesを用いた顔認識
この辺りの機械学習のことは詳しくは良く分からないんだけれど、簡単に言うと顔じゃない画像と顔画像を使ってHaar特徴量から顔を判別できるように訓練する。その結果として識別データができるんだけれど、識別データを効率的に使って識別する方法として、Cascade識別器というのが考案されていて、OpenCVの配布物の中に含まれているようだ。
MacのAnacondaの場合は「~/anaconda3/share/OpenCV/haarcascades」に、Windows版のAnacondaの場合には「Anaconda3\Library\etc\haarcascades」の中に入っている。
- haarcascade_eye.xml ... 眼認識
- haarcascade_frontalface_default.xml ... 顔認識
- haarcascade_smile.xml ... 笑顔認識
とりあえず、これをコピーしておくか、コードの中でFullPathで明示的に指定する。今回はコピーしといた。
face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml')
次に画像ファイルを読み込む。cv2.imread()は、第二引数に0を指定するとグレースケールモードで読み込んでくれるんだけれど、その機能は使わないで、imgとしてカラーで読み込んだ後で、cv2.cvtColor()を使ってグレースケールに変換したコピーを持つ。
グレースケール画像(gray)で顔認識をして座標を取得して、元のカラー画像(img)に加工するため、それぞれの形式の画像データが必要ということだ。
img = cv2.imread(file)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
画像の中で顔を探して、その顔の位置の座標を戻す。もう訓練済みの識別データに基づいて識別器を使うだけなので、たったの一行。
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
顔を探すのはグレースケールに変換した画像(gray)の中で行なうんだけれど、その顔座標の位置に基づいて元のカラー画像(img)に、顔を囲む矩形を描画する。
x,yが矩形の左上のそれぞれx,y座標を示していて、w,hはそれぞれ幅と高さを示しているんだけれど、OpenCVで画像(img)中に長方形を描画する時には、左上のx,y座標と右下のx,y座標がそれぞれ必要なので、(x,y), (x+w,y+h)というように指定している。
for (x, y, w, h) in faces: cv2.rectangle(img, (x,y), (x+w, y+h), (255,0,0), 2)
最後に矩形を書きこんだ画像を表示するんだけれど、OpenCVのimread()で読み込んだカラー画像は何故かBGRの順にデータが保持されているが、今回、画像表示のために使うmatplotlibのpyplotではRGBの順にデータが保持されているという前提になっているので、plt.imshow()にデータを渡す際に、cv2.cvtColor(img, cv2.COLOR_BGR2RGB)で変換している。
plt.imshow( cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.show()
ちなみに、顔は複数あってもOKなように、for (x,y,w,h) in faces: のように受けているんだけれど、ちょうどいい感じの著作権とか肖像権がウヤムヤな集合写真みたいなのが無いので、試せないな。
眼認識もできる
さて、チュートリアルには、顔認識の後で眼認識をするサンプルも載っている。顔があったら眼があるよね、顔じゃないところには眼は無いよね、ということで、顔認識した矩形の中を対象に眼認識を走らせるように工夫されている。なるほどな。
faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = img[y:y+h, x:x+w] eyes = eye_cascade.detectMultiScale(roi_gray) for (ex,ey,ew,eh) in eyes: cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
問題は、「Haar特徴量に基づくCascade識別器」に関して、何も分からなくて、detectMultiScale()メソッドの引数の説明が全然理解できないことだったりする。
さらに問題なのは、自分でCascade識別器を作れるようになる気がしないことだな。
修正するなど
Excelのデータを読み込む( http://d.hatena.ne.jp/fukuit/20160828/1472395613 )として書いていた記事に間違いがあったので、修正。間違えてたのは、t検定のメソッド。
t,p = stats.ttest_rel(tokyo, kyoto)
と書いていたけれど、 ttest_rel() は対応のあるt検定だった。ここは、対応のないt検定をしなければならない。その場合は、ttest_ind()を使う。
t,p = stats.ttest_ind(tokyo, kyoto)
ちなみに、studentのt検定とWelchのt検定では、Welchの方法のほうがrobustだし、正規分布を仮定しなくてもいいので、この場合はWelchの方法で良いだろうと思う。
t,p = stats.ttest_ind(tokyo, kyoto, equal_var=False)
さて、ttest_ind()には、片側検定をするためのオプションがない。東京の方が低いという仮説を検定するので、まあこれは、t値が負の値になってp値が0.025以下になればOKだろう。OKだよね?
結果は、t値が-4.09874 で、 p値が0.00014なので、「東京のほうが低いとはいえない」という帰無仮説を棄却できることになった。
グラフ描画
せっかく、数値データをExcelで読み込んだので、グラフを描画したい。R ならggplot2を使うところで、もちろんpythonでもggplot2を使えるようなんだけれど、matplotlibを使うのが一般的なようだ。
以下のように修正する。
import xlrd import os.path import pandas as pd import numpy as np from scipy import stats from matplotlib import pyplot as plt %matplotlib inline xlfile = "data.xlsx" if os.path.exists(xlfile): xls = xlrd.open_workbook(xlfile) sheet1 = xls.sheet_by_index(0) nrows = sheet1.nrows - 1 ncols = sheet1.ncols data = np.zeros(ncols*nrows).reshape((nrows, ncols)) date = [] for r in range(1, nrows+1): for c in range(0, ncols): if c==0: d = xlrd.xldate.xldate_as_datetime(sheet1.cell(r,c).value, xls.datemode) date.append(d) else: data[r-1,c] = sheet1.cell(r,c).value tokyo = data[:,1] kyoto = data[:,2] plt.plot(date, tokyo, label="Tokyo") plt.plot(date, kyoto, label="Kyoto") plt.legend() plt.show()
日付が重なっちゃって読みづらいな。
Excelデータを読み込む
ExcelデータをPythonで読み込みたい。anaconda search -t conda xls とかすると、いろんなパッケージがヒットするんだけれど、ソコではヒットしなかったxlrdというパッケージをまずは conda でインストールする
Excelデータの準備
京都に単身赴任中、「京都は暑いでしょう?」と何度も言われたので、ソレを検証してみよう。気象庁のサイトから、2016年7月の東京の最高気温と京都の最高気温のデータを取得して、Excelでまとめた。
Excelデータを読み込むコード
というワケで、見よう見まねで書いてみたコードがコレで、東京と京都の平均気温を計算して、表示する。numpyを使っているので、mean()するだけで、平均値を求められる。
import xlrd import os.path import numpy as np xlfile = "test.xlsx" if os.path.exists(xlfile): xls = xlrd.open_workbook(xlfile) sheet1 = xls.sheet_by_index(0) nrows = sheet1.nrows-1 ncols = sheet1.ncols data = np.zeros(ncols*nrows).reshape((nrows, ncols)) for r in range(1, nrows): for c in range(0, ncols): data[r-1,c] = sheet1.cell(r,c).value tokyo = data[:,1] kyoto = data[:,2] msg = "Tokyo(mean): %.2f\nKyoto(mean): %.2f" % (tokyo.mean(), kyoto.mean()) print(msg)
とりあえず画像を読み込んでみるなど
画像ファイルの用意
まずは画像ファイルを用意しよう。こういう時は、Tiger.psかlenna.tiffを使うもんだと聞いたことがある。
というわけで、http://sipi.usc.edu/database/database.php?volume=misc からLennaの画像をダウンロードしておく。ちなみに「Scans of magazine pictures. Copyright belongs to original publisher or photographer.」となってるので、ホントは使用許諾は個別に取る必要があるみたいだぞ。
画像を読み込んで表示する
http://docs.opencv.org/3.1.0/d6/d00/tutorial_py_root.html を見よう見まねでやってみよう。
import numpy as np import cv2 import os.path lenna = "4.2.04.tiff" if os.path.exists(lenna): img = cv2.imread("4.2.04.tiff") cv2.imshow("Lenna", img) cv2.waitKey(0) cv2.destroyAllWindows()
画像表示するだけなんだけれど、numpy要るんスかね。
画像の2値化してみる
http://docs.opencv.org/trunk/d7/d4d/tutorial_py_thresholding.html を見ながら、Lennaの2値化をやってみる。コードの意味は、イマイチ分からない。
import cv2 import numpy as np import os.path from matplotlib import pyplot as plt lenna = "4.2.04.tiff" if os.path.exists(lenna): img = cv2.imread(lenna,0) img = cv2.medianBlur(img,5) ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY) th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2) th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2) titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] images = [img, th1, th2, th3] for i in range(0,4): plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
さらに、大津の2値化。
import cv2 import numpy as np import os.path from matplotlib import pyplot as plt lenna = "4.2.04.tiff" if os.path.exists(lenna): img = cv2.imread(lenna,0) img = cv2.medianBlur(img,5) ret,th1 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) blur = cv2.GaussianBlur(img,(5,5),0) ret2,th2 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) titles = ['Original Image', 'Otsu Method', 'OTSU Method(w Gaussian Blur)'] images = [img, th1, th2] for i in range(0,3): plt.subplot(1,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
これらのコードの意味を理解するのが、次の課題だ。
Anacondaをインストールする
とりあえず、Cygwin上でPython3を使えるようにして、さて、numpyだ、scipyだ、matplotだと思っていたんだけれど、同僚から「環境を統一しよう」と至極もっともな提案があり、彼がインストールしていたAnacondaをインストールすることになった。
というワケで、chocolateyでanaconda3をインストールした。
自宅でも学習できるように、自宅MacにもAnacondaをインストールすることにしよう。
brew を使えば簡単
Windows環境でchocolateyを使ったように、MacではHomeBrewのお世話になる。
% brew search anaconda Caskroom/cask/anaconda Caskroom/versions/anaconda2 % brew cask install anaconda ==> Migrating cached files to /Users/toshi/Library/Caches/Homebrew/Cask... ==> Caveats To use anaconda, you may need to add the ~/anaconda3/bin directory to your PATH environment variable, eg (for bash shell): export PATH=~/anaconda3/bin:"$PATH" ==> Satisfying dependencies complete ==> Downloading https://repo.continuum.io/archive/Anaconda3-4.1.1-MacOSX-x86_64.sh
というワケで、export PATH=~/anaconda3/bin:$PATH を.zshrcに書いて、source ~/.zshrc しておく。
pyenv ? virtualenv ?
とりあえず、仮想環境を作る必要性って感じないんだよな。コレ、要るかな?要らないよね?ってことにする。
OpenCVのインストール
OpenCVをひとまず使えるようにする。pipを使うのかとおもいきや、condaを使うのな。
% anaconda search opencv Using Anaconda Cloud api site https://api.anaconda.org Run 'anaconda show <USER/PACKAGE>' to get more details: Packages: Name | Version | Package Types | Platforms ------------------------- | ------ | --------------- | --------------- ???/opencv | 2.4.7 | conda | win-64 : http://opencv.org/ Changxu/opencv3 | 3.1.0_dev | conda | linux-64 Definiter/opencv | 2.4.12 | conda | linux-64 FlyEM/opencv | 2.4.10.1 | conda | linux-64, osx-64 : Open source computer vision C++ library JaimeIvanCervantes/opencv | 2.4.9.99 | conda | linux-64 Nike/opencv-python | 3.0.0 | pypi | : OpenCV (Open Source Computer Vision) is a library of programming functions for real time computer vision. Nutastray/opencv | | [] | RahulJain/opencv | 2.4.12 | conda | linux-64, win-64, osx-64 anaconda/opencv | 2.4.10 | conda | linux-64, linux-32, osx-64 andywocky/opencv | 2.4.9 | conda | osx-64 asmeurer/opencv | 2.4.9 | conda | osx-64 bgreen-litl/opencv | 2.4.9 | conda | osx-64 bwsprague/opencv | 2.4.9.1 | conda | osx-64 clinicalgraphics/opencv | 2.4.9.1 | conda | linux-64, win-32, win-64, linux-32, osx-64 conda-forge/opencv | 2.4.12 | conda | linux-64, win-32, win-64, osx-64 : Computer vision and machine learning software library. conda-team/protoci-opencv | | [] | csfoo/opencv | 2.4.10 | conda | linux-64 derickl/opencv | 2.4.10 | conda | osx-64 dhaneshr/opencv | 2.4.13 | conda | linux-64 erik/opencv | 2.4.9 | conda | linux-64, osx-64 hadim/opencv | 3.0.0 | conda | linux-64 hovren/opencv | 3.0.0 | conda | linux-64 hyperion/opencv | 2.4.10.1 | conda | linux-64 : Llibrary for computer vision ijstokes/opencv | 2.4.11 | conda | osx-64 jakirkham/opencv | 3.1.0 | conda | osx-64 janc/opencv | 2.4.12 | conda | osx-64 : with ffmpeg janc/opencv3 | 3.1.0 | conda | osx-64 : with ffmpeg and opencl jjhelmus/opencv | 2.4.12 | conda | osx-64 : http://opencv.org/ jlaura/OpenCV3 | 3.1.0 | conda | linux-64, osx-64 : OpenCV 3.0.0 with the optional contrib modules jmargeta/opencv | 2.4.7 | conda | win-64 : http://opencv.org/ joschka_zj/opencv | 2.4.11 | conda | win-64 : OpenCV library jqscali/opencv3 | 3.0.0 | conda | linux-64 kangyounglee87/opencv | 2.4.11 | conda | linux-64 lbernard/opencv3 | 3.1.0 | conda | linux-64 lebedov/opencv | 2.4.11 | conda | linux-64 litl-rnd/opencv | 2.4.9 | conda | osx-64 memex/opencv | 3.0.0 | conda | linux-64, win-64, osx-64 menpo/opencv | 2.4.11 | conda | linux-64, win-32, win-64, linux-32, osx-64 menpo/opencv3 | 3.1.0 | conda | linux-64, win-32, win-64, osx-64 mizvladimir/opencvtutorial_imageprocessinginopencv | 2016.01.03.2031 | ipynb | : IPython notebook msarahan/opencv | 3.1.0 | conda | linux-64, win-32, win-64, linux-32, osx-64 onlyjus/opencv | 2.4.7 | conda | win-64 : http://opencv.org/ osgeo/opencv | 2.4.7 | conda | linux-64, osx-64 patricksnape/opencv | 2.4.11 | conda | linux-64, osx-64 patricksnape/opencv-gpu | 2.4.9.1 | conda | linux-64 phhuang/opencv | 2.4.10 | conda | linux-64 : OpenCV compiled with ffmpeg. poppy-project/opencv | 3.1.0 | conda | linux-armv7l poppy-project/opencv3 | 3.1.0 | conda | linux-armv7l prkrekel/opencv | 2.4.9.1 | conda | linux-64, win-32, win-64, linux-32, osx-64 pypi/ctypes-opencv | | [] | : ctypes-opencv - A Python wrapper for OpenCV using ctypes pypi/opencv-cython | | [] | : An alternative OpenCV wrapper pypi/opencv_engine | 1.0.0 | pypi | : OpenCV imaging engine for thumbor. pypi/opencv_helpers | 0.1 | pypi | : Helper functions for opencv pypi/pyopencv | 2.1.0.wr1.0.0 | pypi | : PyOpenCV - A Python wrapper for OpenCV 2.x using Boost.Python and NumPy rsignell/opencv-python | 2.4.9 | conda | win-32 salilab/opencv-nopython | 2.4.9 | conda | linux-64, win-32, win-64, linux-32, osx-64 : opencv package built without Python (for Python 3) santiavenda2/opencv | 2016.05.08.2120 | conda, env | linux-32 sean/opencv | | [] | shariqiqbal2810/opencv | 2.4.11 | conda | osx-64 shiquanwang/opencv | 3.0.0beta_28_g3234860 | conda | linux-64 sotera/opencv | 2.4.11 | conda | linux-64 sotte/opencv_gtk | 2.4.9 | conda | linux-64 stuarteberg/opencv | | conda | linux-64 : Open source computer vision C++ library tianzhou2011/opencv3 | 3.1.0 | conda | linux-64 timurbagautdinov/opencv | 2.4.11 | conda | linux-64 tofighi/opencv3 | 3.1.0 | conda | osx-64 trax/numpy_for_opencv | 1.9.3 | conda | linux-64 trax/opencv3 | 3.0.0 | conda | linux-64 trax/opencv3_gtk | 3.0.0 | conda | linux-64 trax/opencv_gtk_numpy_1_8 | 2.4.10 | conda | linux-64 trung/opencv | 2.4.11 | conda | linux-64, osx-64 trung/opencv3 | 3.1.0 | conda | linux-64, osx-64 tsc/opencv | 2.4.9 | conda | osx-64 ver228/opencv | 2.4.9 | conda | osx-64 ver228/opencv3 | 3.1.0 | conda | linux-64, win-64 wheeler-microfluidics/opencv-helpers | 1.1 | conda | win-32 willyd/opencv | 3.1.0 | conda | win-64 Found 77 packages
めっちゃあるやん。この中から、osx-64になってて、比較的バージョンが新しそうなヤツを選ぶんやな。
よく分からないけれど、どこかのWebサイトで見たmenpo/opencv3をインストールすることにしよう。
% anaconda show menpo/opencv3 Using Anaconda Cloud api site https://api.anaconda.org Name: opencv3 Summary: Access: public Package Types: conda Versions: + 3.0.0 + 3.1.0 To install this package with conda run: conda install --channel https://conda.anaconda.org/menpo opencv3 % % conda install --channel https://conda.anaconda.org/menpo opencv3 Fetching package metadata ......... Solving package specifications: .......... Package plan for installation in environment /Users/toshi/anaconda3: The following packages will be downloaded: package | build ---------------------------|----------------- tbb-4.3_20141023 | 0 1.6 MB menpo conda-env-2.5.2 | py35_0 27 KB conda-4.1.11 | py35_0 204 KB opencv3-3.1.0 | py35_0 37.3 MB menpo ------------------------------------------------------------ Total: 39.1 MB The following NEW packages will be INSTALLED: opencv3: 3.1.0-py35_0 menpo tbb: 4.3_20141023-0 menpo The following packages will be UPDATED: conda: 4.1.6-py35_0 --> 4.1.11-py35_0 conda-env: 2.5.1-py35_0 --> 2.5.2-py35_0 Proceed ([y]/n)?
さて、opencvを使えるようになってみるのは、明日のことだな。
ところで、こういうのって、qiita.comとかに書いとくと良いんだろうか。
Cygwin環境にPythonをインストールしてみる
仕事の関係で画処理をすることになったので、ImageJのマクロで頑張ってきた。
でも、なんだかんだでPythonで画処理をすることになった。仕事で使っているのはWindowsなので、まずはCygwin上で環境を整えようと思う。
pythonのバージョンは2にするの? 3にするの?
いろんなWebサイトを見ると、「version 3にすると対応してないライブラリがあるし、ノウハウが書いてあるサイトもversion 2がベースになっていることが多いから、2.7系列にしとけ」とか書いてあったりする。
ちょっと前にGAE/pyをイジってた時は、python 2.5にするか2.7にするか?的なことを考えてたワケだけれど、もうさすがに2.7は無いだろと思って、version3系列をインストールすることにした。
Cygwinのsetup-x86_64.exeを使ってpythonをインストールすると2.7になるんだけれど、python3をちゃんと選択すれば、3.4.3がインストールされる。
pip ?
パッケージ管理システムとして、setuptoolsだのeasy_installだのpipだのという単語は知ってるんだけど、具体的にはどうなってるのかよくわかってない。
なんかインストールせなあかんのやな、、、と思って少し調べたら、python3.4.3からはpipが標準的に使えるようになっているらしい。
% python3 -m ensurepip Ignoring indexes: https://pypi.python.org/simple Collecting setuptools Collecting pip Installing collected packages: pip, setuptools Successfully installed pip-6.0.8 setuptools-12.0.5 %
これでpipを使えるようになったところで、早速使ってみようとすると、以下のような警告が表示された。
You are using pip version 6.0.8, however version 8.1.2 is available. You should consider upgrading via the 'pip install --upgrade pip' command.
なるほど。
% /usr/bin/pip3 install --upgrade pip You are using pip version 6.0.8, however version 8.1.2 is available. You should consider upgrading via the 'pip install --upgrade pip' command. Collecting pip from https://pypi.python.org/packages/9c/32/004ce0852e0a127f07f358b715015763273799bd798956fa930814b60f39/pip-8.1.2-py2.py3-none-any.whl#md5=0570520434c5b600d89ec95393b2650b Downloading pip-8.1.2-py2.py3-none-any.whl (1.2MB) 100% |################################| 1.2MB 525kB/s Installing collected packages: pip Found existing installation: pip 6.0.8 Uninstalling pip-6.0.8: Successfully uninstalled pip-6.0.8 Successfully installed pip-8.1.2
画処理準備
PILを使うか、OpenCVを使うか、といったところだけれど、ひとまず今日はここまで。