【Python/OpenCV】空間フィルタリング・畳み込み演算(cv2.filter2d)

PythonとOpenCVを用いて空間フィルタリング処理する方法をソースコード付きで解説します。

空間フィルタリング(畳み込み演算)

空間フィルタリング(畳み込み演算)は、画像処理において輪郭検出やぼかし(ノイズ除去)など広く使用されます。原理と計算式については以下ページで解説しています。

【画像処理】空間フィルタリングと畳み込み演算(マスク演算)
画像処理における空間フィルタリングと畳み込み演算(マスク演算)の計算方法についてまとめました。

また、OpenCVライブラリでは、cv2.filter2Dメソッドで空間フィルタリングを簡単に実装できます。

今回は、空間フィルタリングの処理を以下の2通りの方法で実装する方法を解説します。

方法①・・・NumPyでアルゴリズムを書いて実装
方法②・・・cv2.filter2Dで実装

解説動画

本ページの内容は以下動画で解説しています。

サンプルコード①OpenCVで実装した場合

サンプルプログラムのソースコードです。


実行結果

■入力画像(左)と出力画像(右)

コード解説

このカーネルは、Sobelフィルタと呼ばれるもので、水平方向の輪郭を検出するために使用されます。

   kernel = np.array([[-1, 0, 1],
                      [-2, 0, 2],
                      [-1, 0, 1]])

cv.filter2Dを使用して、入力画像grayに対してカーネルkernelを適用して畳み込み演算をします。
第2引数の-1は、出力画像の深さ(データ型)を入力画像と同じにすることを指定しています。dstは畳み込み演算後の出力画像す。

   dst = cv.filter2D(gray, -1, kernel)

サンプルコード②NumPyで実装した場合


実行結果

■入力画像(左)と出力画像(右)

コード解説

filter2d関数は、入入力画像srcに対して指定されたカーネルkernelを使用して畳み込み演算を行い、空間フィルタリングされた画像を生成します。
以下では、カーネルのサイズ(行数mと列数n)を取得します。

   m, n = kernel.shape
  • カーネルの半径dを計算します。これは、畳み込み演算をしない領域の幅となります。

   d = int((m-1)/2)

入力画像srcの高さhと幅wを取得します。

   h, w = src.shape[0], src.shape[1]

出力画像用の2次元配列dstを入力画像と同じサイズで要素は全て0で初期化します。

   dst = np.zeros((h, w))

入力画像の各ピクセルに対して、カーネルを適用して畳み込み演算を行います。
src[y-d:y+d+1, x-d:x+d+1]は、カーネルのサイズに対応する入力画像の部分領域を取得します。
np.sum(src[y-d:y+d+1, x-d:x+d+1]*kernel)は、部分領域とカーネルの要素ごとの積の総和を計算し、その値を出力画像dstの対応するピクセルに設定します。

   for y in range(d, h - d):
       for x in range(d, w - d):
           # 畳み込み演算
           dst[y][x] = np.sum(src[y-d:y+d+1, x-d:x+d+1]*kernel)

フィルタリング後の出力画像dstを返します。

   return dst

関連記事

【PythonとOpenCVで画像処理超入門】使い方とサンプルコードを解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。
Python基礎
「Python基礎」の記事一覧です。
この記事を書いた人
西住技研

Python使用歴10年以上。研究、仕事、趣味でデータ分析や作業自動化などに活用してきたノウハウを情報発信しています。
詳しいプロフィールやお問合せはこちらのページまで。
YoutubeX(旧Twitter)でも情報発信中です!

西住技研をフォローする
OpenCV

コメント