輪郭追跡処理をやってみよう!」の続きです。世の中には便利で信頼できるライブラリがたくさんあるので、何かやってみたいことがある場合は、それらを利用して組み合わせて作るのが近道ですし高性能で高信頼性なものができるでしょう。がしかし、一部でもじっくり泥臭く自作することや苦戦を楽しむのもエンターテイメントと言えますよね。よって今回も泥臭い内容の解説です。

画像内に複数のターゲットがある場合
前回紹介した輪郭追跡処理は読み込んだ画像の中に抽出すべきターゲットが1つの場合でした。そのためラスタスキャンによって最初の1(画像を2値化したときに背景を示す画素を0、抽出したい側の画像の画素を1とした場合)を見つけ、そこを輪郭追跡を開始するスタート座標としました。しかし、読み込んだ画像の中に抽出すべきターゲットが複数ある場合、このやり方ではラスタスキャン順で2番目以降に配置されている目標物の輪郭追跡開始座標を見つけられません。

輪郭追跡スタート時点の候補リスト(頂点メモリ)を作る
注目画素を中心とする3×3の9画素を考えたときに、輪郭追跡スタート座標となり得るパターンは15個しかありません。(いや、15個とします。)ラスタスキャンをしながら単純に最初の1を見つけるのではなく、これらのパターンに該当する3×3画素が無いか調べます。画像の最後までラスタスキャンを行い、頂点候補となった座標を「頂点メモリ」(本稿ではこう呼ぶことにします。なんと呼ぶのが通じるのだろうか。)へ記憶します。

3×3画素の画素それぞれに名前(b数字)をつけ、頂点に該当する条件を論理式で表すと次のとおりとなります。
 b8 and ( not ( b1 or b2 or b3 or b4 ) and ( b0 or b5 or b6 or b7 )
注目画素(この図でいうところのb8)とその近傍の3×3画素がこのパターンで真の時、そのX座標とY座標を頂点メモリへ保存していきます。(本稿ではPythonを使っているのでlistにappendしていきます。)

輪郭追跡処理
頂点メモリから頂点候補の座標データを順次読み出して、輪郭追跡処理を行います。輪郭追跡処理自体は「輪郭追跡処理をやってみよう!」で解説していますので、見てない方は参照してください。

重なりデータの除去
頂点候補の情報を頼りに輪郭追跡処理を行って得られる結果の中には、”同一画像を示している” ”画像の中の画像(模様)を示している”データが存在します。(存在しない場合もあるかな)これらを除去する処理を行います。輪郭追跡処理で得られたチェーンコードデータの中に、抽出画像の上下左右の座標データがあるのでこの座標データを使って、”同一画像を示している” ”画像の中の画像(模様)を示しているデータを見つけます。そしてそのデータを所有するチェーンコードを削除します。そしてそのチェーンコードと紐付いた頂点候補座標データを削除します。そうすると、重なりデータが除去されたチェーンコードリストができあがります。

抽出画像(上図では”粒子”と表現)Aの上下左右の座標をそれぞれA_YMIN, A_YMAX, A_XMIN, A_XMAX、抽出画像Bの上下左右の座標をそれぞれB_YMIN, B_YMAX, B_XMIN, B_XMAXとするとき、以下の条件が成立する場合は、削除します。
(A_XMIN <= B_XMIN) and
(A_XMAX >= B_XMAX) and
(A_YMIN <= B_YMIN) and
(A_YMIN >= B_YMIN)

一つの輪郭情報の中に複数の頂点候補が存在するのがほとんどのため、同じ座標データの集まりを比較するケースがたくさん発生します。

画像の切り出し処理
輪郭追跡処理で得られたチェーンコードデータの中に、抽出画像の上下左右の座標データがあるのでこの座標データを使って、”抽出画像+周囲の余白3画素”の長方形の4角の座標を計算し、長方形画像として保存します。(本稿ではPythonを使っているので、Numpy array(2次元)のスライスを使うことで画像を切り出し、OpenCVの関数を使って画像ファイルを作っています。)

実行結果
実験には背景と抽出すべき画像の輝度差がはっきりした画像を使いました。

輪郭追跡が正しいかどうか、得られたチェーンコードデータを使って輪郭を着色します。

重なりデータの除去もちゃんと機能しています。

続いて画像の切り出しですが、ちゃんと12画像の切り出しに成功しました。(自動でファイル名をつけフォルダ内に保存しています。)

画像の抽出ができまたね。 この回はここまでです。

ソースコード一式を公開します。”data”フォルダの中のファイルは画像処理前の原画像ファイルです。”output”フォルダの中のファイルはプログラムを実行した結果、作成されたファイルです。

この下のファイルは、上記のPythonプログラムの中から呼び出したC言語で作った拡張モジュールです。これを使わなくても上記は実行できますが、処理速度を早くしたい場合は下記のモジュールを利用します。この話は、「Python C言語による拡張モジュールで高速化」の記事を参照してください。(2023年9月17日追記)