画像用移動平均フィルタをPython自作してみた

プログラミング

フィルタとは

カメラで写真を撮ったとき、ノイズというゴミみたいなものが含まれていることがあります。

そのノイズを取り除くためにフィルタを用います。

具体的には

具体的にどのような計算をするのか?

下の画像はフィルタの中身です。(行と列の数と中身の数値はフィルタによって変動します)

下の画像は画像の中身です。

計算の方法は以下のようにします。

フィルタのサイズ3×3に合わせて、画像の左上から順に上の画像のように計算していきます。

画像の黄色い部分とフィルタを掛けて計算しますが、黄色い部分の左上とフィルとの左上を掛け算します。同じように行と列の番号が一致するもの同士を掛け算して足していきます。足し合わせた数の結果を真ん中の数と書き換えます。(上の画像で言うと1=>3になっています)

この計算が終わると、黄色い部分を1つ隣に移動させ計算します。

このようにして1つずつずらし計算していきます。

移動平均フィルタ

移動平均フィルタはフィルタ内の数を全て足し合わせると1になると言う特徴と全て同じ値になる特徴があります。

Pythonで実装

最初に全部のコードを乗っけます

import numpy as np
import cv2

img = cv2.imread("画像名")
def padarray(img, m, n, h, w):
    clc_img = np.zeros((w+m-1, h+n-1, 3))
    s = int((m - 1) / 2)
    t = int((n - 1) / 2)
    for x in range(0, w):
        for y in range(0, h):
            clc_img[x + s][y + t] = img[x][y]

    return clc_img

def filter(img, kernel):
    # カーネルサイズ
    m, n = kernel.shape
    # 画像サイズ
    h, w = img.shape[0], img.shape[1]

    clc_img = padarray(img, m, n, h, w)
    after_img = np.zeros((w, h, 3))
    sum = np.zeros((3, 1))
    for x in range(0, w):
        for y in range(0, h):
            for s in range(0, n):
                for t in range(0, m):
                    sum[0] = sum[0] + kernel[s][t] * clc_img[x+s][y+t][0]
                    sum[1] = sum[1] + kernel[s][t] * clc_img[x+s][y+t][1]
                    sum[2] = sum[2] + kernel[s][t] * clc_img[x+s][y+t][2]
            after_img[x][y][0] = sum[0]
            after_img[x][y][1] = sum[1]
            after_img[x][y][2] = sum[2]
            sum[0] = 0
            sum[1] = 0
            sum[2] = 0

    return after_img


kernel = np.array([[1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9]])

after_img = filter(img, kernel)

cv2.imwrite("保存する画像名", after_img)

処理していく順に説明します。

1. ライブラリのインポート

import numpy as np
import cv2

2. 画像の読み込み

img = cv2.imread("画像名")

3. フィルタの用意

移動平均フィルタを作成します。

kernel = np.array([[1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9]])

4. 関数実行

自作関数を実行し、after_img変数にフィルタ処理後の画像データが格納されます。

after_img = filter(img, kernel)

5.1. 自作関数

この関数がメイン処理になります。

def filter(img, kernel):
    # カーネルサイズ
    m, n = kernel.shape
    # 画像サイズ
    h, w = img.shape[0], img.shape[1]

    clc_img = padarray(img, m, n, h, w)
    after_img = np.zeros((w, h, 3))
    sum = np.zeros((3, 1))
    for x in range(0, w):
        for y in range(0, h):
            for s in range(0, n):
                for t in range(0, m):
                    sum[0] = sum[0] + kernel[s][t] * clc_img[x+s][y+t][0]
                    sum[1] = sum[1] + kernel[s][t] * clc_img[x+s][y+t][1]
                    sum[2] = sum[2] + kernel[s][t] * clc_img[x+s][y+t][2]
            after_img[x][y][0] = sum[0]
            after_img[x][y][1] = sum[1]
            after_img[x][y][2] = sum[2]
            sum[0] = 0
            sum[1] = 0
            sum[2] = 0

    return after_img

5.2. 自作関数

フィルタ処理を行うと、処理後の画像サイズが小さくなってしまうので、それを防ぐために元画像の端にデータを作成します。

一般的に値が0のデータを端に作成します。今回もその方法で行います。

def padarray(img, m, n, h, w):
    clc_img = np.zeros((w+m-1, h+n-1, 3))
    s = int((m - 1) / 2)
    t = int((n - 1) / 2)
    for x in range(0, w):
        for y in range(0, h):
            clc_img[x + s][y + t] = img[x][y]

    return clc_img

コメント

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