Python+OpenCVを使った画像処理入門



OpenCV(Open Source Computer Vision Library)とはインテル社が開発したC/C++、Java、Python、MATLABの言語向けの画像処理ライブラリ集です。

画像のフィルタ処理、テンプレートマッチング、物体認識、映像解析、機械学習などのアルゴリズムが多数用意されています。

顔の検出や特徴抽出等のパッケージも揃っているため、比較的容易に画像処理を試す&実装することができます。

スポンサードリンク

前提条件

Windows パソコン上で gnupack_devel を利用して動作確認しています。

Pythonをインストールした後、各ライブラリを「pip install」でインストールしてください。

OpenCV 3.1.0 の各種サンプル

OpenCVのGitHubからダウンロードします。

展開

opencv → releases → OpenCV 3.1 → Downloads → opencv-3.1.0.exe → 実行 → 展開フォルダを指定 → Extract

サンプル(写真、動画)は、以下に格納されています。

opencv\sources\samples\data

コンピュータ画像処理とは?

画像処理は、出力形態から大きく分けて3つに分類されます。

画像改善雑音やぼけのような画像劣化要因を取り除くことにより、見にくいもの・見えないものを見えるようにする
画像解析特徴量を計測する
画像認識画像に写っているモノを識別し、その判断後にアクションを起こさせる(人間の視覚の代行)

静止画処理

OpenCV 3.1.0は以下の画像フォーマットの入出力をサポートしています(※詳細は「公式ドキュメント(英語)」を参照)

画像フォーマット 拡張子
Windows bitmap .bmp、.dib
JPEG .jpeg、.jpg、.jpe
JPEG 2000 .jp2
Portable Network Graphics .png
WebP .webp
Portable image format .pbm、.pgm、.ppm
Sun rasters .sr、.ras
TIFF .tiff、.tif
OpenEXR Image .exr
Radiance HDR .hdr、.pic
GDAL Raster、Vectorに列挙されるフォーマット

※ 画像の種類をファイルの拡張子からではなく、内容から判別しています。

スポンサードリンク

動画処理

動画ファイル(.mp4, .avi, .mov, .mpeg, .flv, .wmv形式)を利用することができます。

# coding: UTF-8
import numpy as np
import cv2

cap = cv2.VideoCapture('input.avi')

ret, frame = cap.read()
cv2.imwrite('first_frame.png',frame)

while(cap.isOpened()):
    ret, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

cv2.waitKey()はキーボードからのなんらかの応答を、指定したミリ秒間だけ待ち受ける関数です。

ここでは'q'ボタンを押すとwhileループから抜け出ることができるように、waitkey()で'q'ボタンが押されたときに帰ってくる応答コマンドを待ちうけています。

画像解析

二値画像

濃淡がなく、白と黒しかない図形・画像は、画素の値が0、1の2つの値しか取りません。そのような画像を2値画像と呼びます。

ret, dst = cv2.threshold(src, threshold, max_value, threshold_type)

エッジ検出

特徴が急激に変化する画像中の場所を探すにはエッジ検出するのが画像分割の基本的手法となっている。

Canny法

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('sample.jpg',0)
edges = cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()

特徴空間におけるクラスタ化を利用した領域分割

物体抽出

特徴量による画像比較は検出したい物体について「ピクセルの値(RGB値など)の表現ではなく、その物体を最もよく表現するポイントを数値で表現し、そのポイントごとの数値で比較」するというアプローチです。

特徴量の具体的な手法としてOpenCVでは、HaarLike(明度差)、HOG(輝度の勾配方向)、SIFTやSURF、AKAZE(Accelerated KAZE)などが実装されています。

特徴点抽出

テンプレートマッチング(特徴点マッチング)

画像のマッチングを行うときは、回転、拡縮、アフィン変換などを意識する必要があります。

局所特徴量

特徴点対応付け

オプティカルフロー

動画像での水玉コラ自動作成に詳細を書いています。

for m in range(0, len(gFeature)):
    features_prev = np.array([[[gFeature[m][0], gFeature[m][1]]]], np.float32)
 
    # 前フレーム、現フレーム、前フレームでの点の位置、画像ピラミッドの最大レベル数
    features, status, err = cv2.calcOpticalFlowPyrLK( \
                                         gray_prev, \
                                         gray_next, \
                                         features_prev, \
                                         None, \
                                         winSize = (20, 20), \
                                         maxLevel = 3, \
                                         criteria = CRITERIA, \
                                         flags = 0)
    # フレームに有効な特徴点を描画
    if features is not None:
       for feature in features:
           gFeature[m][0] = feature[0][0]
           gFeature[m][1] = feature[0][1]
    else:
       del gFeature[m]

実際の活用例

モザイク画像の生成

部分切り出し

文字認識

Tesseract-OCR というgoogleが開発を行っているOCRエンジンが存在します。

これ を入れる

Pythonで使いたいのでラッパーを入れる。

日本語に対応させるためにここからjapn.traineddataを/usr/local/tessdataに入れる。
パスを貼る。

export TESSDATA_PREFIX="/usr/local/share/tessdata/tessdata/

プログラムを書く。

#-*- coding:utf-8 -*-
import tesseract

#tesseractオブジェクト作成(文字コードも設定)
api = tesseract.TessBaseAPI()
api.Init(".","jpn",tesseract.OEM_DEFAULT)
api.SetPageSegMode(tesseract.PSM_AUTO)

#画像ファイル読み込み
mImgFile = "D:\\work\\image.jpg"
mBuffer=open(mImgFile,"rb").read()

#文字情報取得
result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api)
print result

動体検出

物体抽出

制約のない実世界シーンの画像に対して、コンピュータがその中に含まれる物体を一般的な名称で認識することを一般物体認識と呼びます。

2010年に「物体検出アルゴリズムObjectness」がリリースされました。

候補(オブジェクト)を検出

OpenCVのContributionにあるBING(Objectness)を使用します。

BINGとは

BING(Binarized Normed Gradients for Objectness Estimation)

画像中からオブジェクトらしい矩形領域を抽出することができる手法で、物体認識の前処理に利用できます。

画像認識

物体認識を問題領域の観点から大別して2系統あります。

特定物体認識既知の物体Aについて、画像中のどこに物体Aが存在するか(もしくは存在しない)を調べる
一般物体認識画像が何を示しているものなのかを言い当てる(例:車の画像)

一般物体認識

特定物体認識

カメラ画像から自分の好きな物体を検出する

OpenCVでHOGを求めて、scikit-imageのSVMで学習できますが、dlibを使う方が容易です。

dlib を使って、HOG特徴とSVMによる学習を使った物体検出

学習により、切り出した画像中にHOG特徴の有無を判定できるSVMを作成します。

検出時には、入力画像からHOGピラミッドを作成し、各画像におけるHOG特徴の有無でSVMで判定します。

顔が写っているか確認

複雑な形の認識は(顔認識など)は CascadeClassifier で行います。

単純な認識機を多段(カスケード)に組み合わせることで認識精度を上げます。

ただし、機械学習したデータを使って認識を行うため学習データを作る必要です。

OpenCVには以下の学習データ(Haar-like特徴分類器)があらかじめ用意されています。

[OpenCV Install Dir]/Library/etc/haarcascades/

ファイル名 内容
haarcascade_eye.xml
haarcascade_eye_tree_eyeglasses.xml 眼鏡
haarcascade_frontalcatface.xml 猫の顔(正面)
haarcascade_frontalcatface_extended.xml猫の顔(正面)
haarcascade_frontalface_alt.xml 顔(正面)
haarcascade_frontalface_alt2.xml 顔(正面)
haarcascade_frontalface_alt_tree.xml 顔(正面)
haarcascade_frontalface_default.xml 顔(正面)
haarcascade_fullbody.xml 全身
haarcascade_lefteye_2splits.xml 左目
haarcascade_licence_plate_rus_16stages.xml ロシアのナンバープレート(全体)
haarcascade_lowerbody.xml 下半身
haarcascade_profileface.xml 顔(証明写真)
haarcascade_righteye_2splits.xml 右目
haarcascade_russian_plate_number.xml ロシアのナンバープレート(数字)
haarcascade_smile.xml 笑顔
haarcascade_upperbody.xml 上半身
#coding: utf-8
import cv2
import sys
import numpy as np

# Haar-like特徴分類器の読み込み
face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_eye.xml')

# イメージファイルの読み込み
img = cv2.imread(sys.argv[1])

# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔を検知
faces = face_cascade.detectMultiScale(gray)
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)

# 画像表示
cv2.imshow('img',img)

# 何かキーを押したら終了
cv2.waitKey(0)
cv2.destroyAllWindows()

CascadeClassifier.detectMultiScale のパラメータは次のとおりです。

パラメータ 説明
image: CV_8U型の行列。ここに格納されていいる画像中から物体が検出されます
objects: 矩形を要素とするベクトル。それぞれの矩形には、検出した物体を含みます
scaleFactor: 画像スケールにおける縮小量
minNeighbors: 物体候補となる矩形は、最低でもこの数だけの近傍矩形を含む必要があります
minSize: 物体が取り得る最小サイズ。これよりも小さい物体は無視されます
maxSize: 物体が取り得る最大サイズ

トラブルシューティング

error: (-215) !empty() in function detectMultiScale

とエラーが出力される場合は、cv2.CascadeClassifier('パス名/haarcascade_frontalface_alt.xml') のpathが間違っています。

絶対PATHで書き直すか、ファイルそのものを同じディレクトリに持ってきてください。

スポンサードリンク