画像認識とは - KawaSwitch/Poke-Controller GitHub Wiki

現在メソッドとして提供している画像認識の機能は次の通りです

  • テンプレートマッチング
  • 動体検知

これから追加予定の主な画像認識の機能は次の通りです

  • OCR(文字読み取り)
  • 特徴量マッチングによる認識
  • 動体認識

これらは順次更新/改良していきます

各機能

テンプレートマッチング

What is this

ある画像からテンプレート画像と最も一致する場所を探索する方法です
左上からテンプレート画像を走査していき, 最も類似度が高いと判定される箇所を見つけます
原理や計算式はこことかを参考にしてください

本プロジェクトではZNCCで類似度を計算しています
ZNCCでは類似度は -1から1の範囲 で出ます(1に近づくほど類似度が高い)

Example

例として次の画像から「どうぐをポケットに しまった」という文言があるかを判定してみます

入力画像
sample

探したい画像(テンプレート画像)
※勝手にリサイズされて表示されますが実際は切り取ったサイズです
dougu

実際にテンプレートマッチングで求めると次のようになります
一致と判断した箇所を四角で囲んでいます

カラー画像結果
template-color

この時の類似度は1.0でした!加工なしですからね

一般的に計算量を減らすためにグレースケール画像で処理を行うことが多いです
RGBの3チャンネルで計算するより1チャンネルの方が速いことは明白です
グレースケールで試してみました

グレースケール画像結果
template-gray

今回の類似度は0.9995401501655579でした. かなりの精度ですね
ただしグレースケールでは色の情報が失われるので, 色違いなどの判定の際にはカラーで行います

PokeController/SerialController/TestImageRecognition.py のisContainTemplateメソッドで好きな画像で試すことができます
テンプレート画像がマッチングするか不安な場合や確認したいときは活用してください

フレーム間差分法

What is this

動体を検知する手法の1つで, 複数枚のフレーム間画像の差分から動いている部分を検出します
より詳しくはこことかを参照してください

本プロジェクトではフレーム画像から差分画像を取得し2値化処理を行う方法を採っています
膨張処理は加えていません
また現在は認識としての機能は考えていません

Example

メニュー画面で輝度値(グレースケールでの色の濃さ)のフレーム間差分を見てみます

メニュー画面の輝度差分画像
interframe-diff

矢印部分だけが切り取れていることが分かりますね!
短い時間の間で輝度値が変化した部分が検出箇所として白いピクセル(=非0)で現れています

通常の動体検知ではさらにもう1枚差分画像を計算し論理積をとって2値化したものを使うそうです
※2値化とは一定の基準(threshold)で各ピクセルの輝度値を0(黒)か255(白)にすること
本プロジェクトで提供する関数もそのように実装しています

実際の例として実際に木が揺れたときの検知を行うと次のようになります

木の揺れの動体検出 2値化済み
is-tree-shake

一定間隔で差分画像の白ピクセルの数え上げ → 多かったら揺れが多い
というように揺れの多さを検知できます(かなり単純でしょう)
応用の仕方次第でより多くの認識が可能です

PokeController/SerialController/TestImageRecognition.py のtestInterframeDiffメソッドでキャプチャボードを用いて試すことができます
動きが認識できるか確認したいときは活用してください

How to use in Poke-Controller

準備

テンプレートマッチング
テンプレート画像を用意します
テンプレートとして比較するにはサイズを一致させる必要があるのでCaptureボタンを押してそれを加工するのが早いです
キャプチャ画像は1280*720として処理しているので注意してください

フレーム間差分法
白画素を数える(OpenCVのcv2.countNonZeroメソッドなどを用いる)場合はあらかじめしきい値を決めておきます

実装

  1. 実装するクラスへ ImageProcPythonCommand クラスを継承します

in PythonCommand.py
class DoSomething(ImageProcPythonCommand):
    def __init__(self, name, cam):
        super(DoSomething, self).__init__(name, cam)

継承後, 画像処理用のメソッドが使えます
使用法はここで示しています

ver. 1.0-alphaの場合
self.py_commandsへ追加します(cameraの引数を忘れない)

in Window.py
self.py_commands = [
    PythonCommand.DoSomething('anything', self.camera),
    ...

それより後のバージョンの場合
commandsへ追加します

in PythonCommand.py
self.py_commands = [
    'name': DoSomething,
    ...