画像処理100本ノック完全ガイド 005:フィルタ②

Python

はじめに

画像処理は、デジタル画像を操作してその内容を解析、変換、編集する技術です。この技術は、写真編集、医療画像解析、自動運転車の視覚システムなど、さまざまな分野で利用されています。このシリーズは、実際の画像処理技術をPythonで実装することで、理論と実践を組み合わせた学習を目指しています。画像処理において、ノイズ除去は非常に重要なステップです。ノイズの多い画像では、後続の処理や解析の精度が低下してしまいます。この記事では、画像処理の基本的なフィルタ技術である平滑化フィルタとモーションフィルタについて解説します。これらのフィルタは、画像のノイズを低減し、画像を滑らかにするために広く使用されています。特に、Pythonの関数を使わずにこれらのフィルタを実装する方法を紹介します。初心者にも分かりやすいように、各ステップを丁寧に説明しますので、ぜひ参考にしてください。この記事では、画像処理100本ノックで用意されている「imori_noise.jpg」をダウンロードしてください。ダウンロードのURLはこちらです。

画像処理100本ノック 010. 平滑化フィルタ

平滑化フィルタ(3×3)を実装せよ。
平滑化フィルタはフィルタ内の画素の平均値を出力するフィルタである。

画像処理100本ノック

方針

平滑化フィルタ(スムージングフィルタ)は、画像の各ピクセルに対してその周辺ピクセルの平均値を計算し、ノイズを低減するフィルタです。このフィルタは画像を滑らかにし、急激な変化を抑える効果があります。3×3の平滑化フィルタのカーネルは以下のようになります。

平滑化フィルタを適用するためには、以下の手順を踏みます:

  1. 平滑化フィルタのカーネルを定義する。
  2. 画像にゼロパディングを施し、画像の境界部分の処理を行う。
  3. 各ピクセルに対して平滑化フィルタを適用し、新しい値を計算する。

実装手順

  1. 画像の読み込み
    • 画像を読み込みます。
  2. 平滑化フィルタのカーネルを定義する
    • 3×3の平滑化フィルタのカーネルを作成します。
  3. ゼロパディング
    • 画像にゼロパディングを施し、カーネルの適用範囲を確保します。
  4. 平滑化フィルタを適用する
    • 各チャンネル(R, G, B)に対してカーネルを適用し、フィルタリングされた画像を生成します。

解答と実行結果

まず、必要なライブラリとしてcv2、numpy、およびmatplotlib.pyplotをインポートします。次に、cv2.imread(‘imori_noise.jpg’)を使用して、ノイズのある画像をカラーで読み込みます。このとき、img変数に画像データが格納されます。平滑化フィルタのカーネルを作成するために、kernel = np.ones((3, 3)) / 9と定義します。これは3×3の行列で、全ての要素が1/9です。このカーネルを使用して、画像の各ピクセルに対して周囲のピクセルの平均値を計算します。

次に、カーネルのサイズに基づいてゼロパディングのサイズを計算します。ここでは、カーネルのサイズを2で割った値(pad_size = kernel.shape[0] // 2)をゼロパディングのサイズとして使用します。画像に平滑化フィルタを適用するための関数apply_smoothing_filterを定義します。この関数は、各カラーチャンネル(R、G、B)に対してゼロパディングを施し、カーネルを適用して新しいピクセル値を計算します。具体的には、ゼロパディングされた画像の各位置に対してカーネルを適用し、その結果をoutputに格納します。

最後に、apply_smoothing_filter(img, kernel)を使用してフィルタを適用し、plt.imshow(cv2.cvtColor(output_smoothing, cv2.COLOR_BGR2RGB))を使用してフィルタを適用した画像を表示します。

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

# 画像の読み込み(カラー)
img = cv2.imread('imori_noise.jpg')

# ガウシアンカーネルの作成
def gaussian_kernel(size, sigma):
    kernel = np.fromfunction(
        lambda x, y: (1/ (2*np.pi*sigma**2)) * np.exp(- ((x - (size - 1) / 2) ** 2 + (y - (size - 1) / 2) ** 2) / (2 * sigma ** 2)), (size, size)
    )
    return kernel / np.sum(kernel)

kernel = gaussian_kernel(3, 1.3)

# ゼロパディング
pad_size = kernel.shape[0] // 2

# ガウシアンフィルタの適用
def apply_gaussian_filter(img, kernel):
    padded_img = np.pad(img, ((pad_size, pad_size), (pad_size, pad_size), (0, 0)), mode='constant')
    output = np.zeros_like(img)
    for c in range(3):  # 各チャンネルに対してフィルタを適用
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                output[i, j, c] = np.sum(kernel * padded_img[i:i + kernel.shape[0], j:j + kernel.shape[1], c])
    return output

output = apply_gaussian_filter(img, kernel)

# 結果の表示
plt.imshow(cv2.cvtColor(output, cv2.COLOR_BGR2RGB))
plt.title('Gaussian Filter Output')
plt.show()

このコードを実行すると、次のような結果(右の画像)が得られます。

画像処理100本ノック 011. モーションフィルタ

モーションフィルタ(3×3)を実装せよ。
モーションフィルタとは対角方向の平均値を取るフィルタである。

画像処理100本ノック

方針

モーションフィルタは、画像の特定の方向に沿った平均値を計算するフィルタです。通常、対角方向の平均値を計算するために使用されます。3×3のモーションフィルタのカーネルは以下のようになります。

このカーネルを画像に適用することで、対角方向の平滑化が行われます。モーションフィルタを適用するためには、以下の手順を踏みます:

  1. モーションフィルタのカーネルを定義する。
  2. 画像にゼロパディングを施し、画像の境界部分の処理を行う。
  3. 各ピクセルに対してモーションフィルタを適用し、新しい値を計算する。

実装手順

  1. 画像の読み込み
    • 画像を読み込みます。
  2. モーションフィルタのカーネルを定義する
    • 3×3のモーションフィルタのカーネルを作成します。
  3. ゼロパディング
    • 画像にゼロパディングを施し、カーネルの適用範囲を確保します。
  4. モーションフィルタを適用する
    • 各チャンネル(R, G, B)に対してカーネルを適用し、フィルタリングされた画像を生成します。

解答と実行結果

まず、平滑化フィルタの場合と同様に、必要なライブラリをインポートし、ノイズのある画像をカラーで読み込みます。次に、モーションフィルタのカーネルを作成します。このカーネルは、対角方向の平均値を計算するために使用される3×3の行列で、対角成分が1/3です。

画像にモーションフィルタを適用するための関数apply_motion_filterを定義します。この関数は、各カラーチャンネルに対してゼロパディングを施し、カーネルを適用して新しいピクセル値を計算します。具体的には、ゼロパディングされた画像の各位置に対してカーネルを適用し、その結果をoutputに格納します。

最後に、apply_motion_filter(img, motion_kernel)を使用してフィルタを適用し、plt.imshow(cv2.cvtColor(output_motion, cv2.COLOR_BGR2RGB))を使用してフィルタを適用した画像を表示します。

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

# 画像の読み込み(カラー)
img = cv2.imread('imori_noise.jpg')

# モーションフィルタのカーネル
motion_kernel = np.array([[1/3, 0, 0], [0, 1/3, 0], [0, 0, 1/3]])

# モーションフィルタの適用
def apply_motion_filter(img, kernel):
    output = np.zeros_like(img)
    for c in range(3):  # 各チャンネルに対してフィルタを適用
        padded_img = np.pad(img[:, :, c], ((pad_size, pad_size), (pad_size, pad_size)), mode='constant')
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                output[i, j, c] = np.sum(kernel * padded_img[i:i + kernel.shape[0], j:j + kernel.shape[1]])
    return output

output_motion = apply_motion_filter(img, motion_kernel)

# 結果の表示
plt.imshow(cv2.cvtColor(output_motion, cv2.COLOR_BGR2RGB))
plt.title('Motion Filter Output')
plt.show()

このコードを実行すると、次のような結果(右の画像)が得られます。

最後に

この記事では、画像処理の基本的なフィルタ技術である平滑化フィルタとモーションフィルタの原理と実装方法について詳しく解説しました。これらのフィルタを適用することで、画像のノイズを低減し、画像を滑らかにすることができます。Pythonの関数を使わずにこれらのフィルタを実装する方法を紹介しましたが、理解を深めるために実際にコードを試してみることをお勧めします。今後も、画像処理の様々な技術について解説していきますので、ぜひ参考にしてください。

私の経歴などについては以下の記事から確認することができます!

ブログランキングに参加しています。ぜひクリックで応援お願いします

ブログランキング・にほんブログ村へ
「#Python」人気ブログランキング

コメント

タイトルとURLをコピーしました