OpenCVでの画像処理004_滑らかな画像

この記事の主な内容は、OpenCV-Python チュートリアルの OpenCV の画像処理部分から来ています。この部分の主な内容は次のとおりです。

目標

勉強:

  • さまざまなローパスフィルターを使用して画像をぼかします
  • 画像にカスタム フィルターを適用する (2D コンボリューション)

2Dコンボリューション(画像フィルタリング)

1 次元信号と同様に、画像はさまざまなローパス フィルター (LPF)、ハイパス フィルター (HPF) などを使用してフィルター処理できます。LPF はノイズやぼやけた画像などを除去するのに役立ちます。HPF フィルターは、画像内のエッジを見つけるのに役立ちます。

OpenCV は、カーネルとイメージを畳み込むための関数 ** cv.filter2D() ** を提供します。たとえば、画像に平均化フィルターを試してみましょう。5x5 平均化フィルター カーネルは次のようになります。

K = 1 25 [ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ] K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \終了{b行列}K=2 511111111111111111111111111

操作は次のように行われます。このカーネルを 1 ピクセル上に保持し、このカーネルの下の 25 ピクセルをすべて追加し、平均を取得し、中央のピクセルを新しい平均で置き換えます。画像内のすべてのピクセルに対してこの操作を続けます。このコードを試して結果を確認してください。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

def image_filtering():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    img = cv.imread(cv.samples.findFile('opencv-logo.png'))

    kernel = np.ones((5, 5), np.float32) / 25
    dst = cv.filter2D(img, -1, kernel)

    row, col, _ = img.shape

    edge = np.full((row, 10, 3), (255, 255, 255), np.uint8);
    images = [img, edge, dst]
    dst = cv.hconcat(images)

    cv.imshow("Image", dst)

    cv.waitKey(-1)
    cv.destroyAllWindows()


if __name__ == "__main__":
    image_filtering()

結果は次のとおりです。

画像

画像のぼかし(画像の平滑化)

画像のぼかしは、画像をローパス フィルター カーネルで畳み込むことによって実現されます。ノイズを除去するのに役立ちます。実際には、画像から高周波成分 (ノイズ、エッジなど) が除去されます。したがって、この操作ではエッジが少しぼやけます (エッジをぼかさないぼかしテクニックもあります)。OpenCV は、主に 4 種類のぼかし技術を提供します。

1. 平均的

これは、正規化されたボックス フィルターを使用して画像を畳み込むことによって行われます。カーネル領域の下のすべてのピクセルの平均を取得し、中央の要素を置き換えるだけです。これは、関数 cv.blur() または cv.boxFilter()を通じて行われます。詳細については、カーネルに関するドキュメントを確認してください。カーネルの幅と高さを指定する必要があります。3x3 の正規化ボックス フィルターは次のようになります。

K = 1 9 [ 1 1 1 1 1 1 1 1 ] K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \終了{b行列}K=91111111111


正規化されたボックスフィルターを使用したくない場合は、cv.boxFilter()を使用してください。パラメータnormalize=Falseを関数に渡します。

5x5 サイズのコアを使用する次のデモ例を見てください。

def averaging_filter():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    img = cv.imread(cv.samples.findFile('opencv-logo-white.png'))

    blur = cv.blur(img, (5, 5))

    plt.subplot(121), plt.imshow(img), plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(blur), plt.title('Blurred')
    plt.xticks([]), plt.yticks([])
    plt.show()


if __name__ == "__main__":
    averaging_filter()

結果は次のとおりです。
画像

ガウスぼかし

この方法では、ボックス フィルターを使用する代わりに、ガウス カーネルが使用されます。これは関数 cv.GaussianBlur()を通じて行われます。カーネルの幅と高さを指定する必要があります。これらは正の奇数である必要があります。X 方向と Y 方向の標準偏差、sigmaX と sigmaY も指定する必要があります。sigmaX のみを指定した場合、sigmaY は sigmaX と同じ値になります。両方がゼロの場合、カーネル サイズに基づいて計算されます。ガウスぼかしは、画像からガウス ノイズを除去するのに非常に効果的です。

必要に応じて、関数cv.getGaussianKernel()を使用してガウス カーネルを作成できます。

上記のコードは、ガウスぼかし用に変更できます。

    blur = cv.GaussianBlur(img, (5, 5), 0)

関数cv.getGaussianKernel()を使用する場合は、次のコードが必要です。

    kernel = cv.getGaussianKernel(5, 0)
    kernel_2D = kernel @ kernel.transpose()
    blur = cv.filter2D(img, -1, kernel_2D)

結果は次のとおりです。
画像

3.中央ぼかし

ここで、関数cv.medianBlur() は、カーネル領域の下のすべてのピクセルの中央値を取得し、中央の要素を中央値で置き換えます。これは、画像内の塩胡椒ノイズに最適です。興味深いことに、上記のフィルターでは、中心要素は新しく計算された値であり、画像内のピクセル値または新しい値である可能性があります。ただし、メディアンブラーでは、中心要素は常に画像内の何らかのピクセル値に置き換えられます。ノイズを効果的に低減します。そのカーネル サイズは正の奇数である必要があります。

このデモでは、元の画像に 50% のノイズを追加し、中央値のぼかしを適用しました。次のSalt_and_pepper(image, n)関数を使用してノイズ ポイントを追加します。テスト結果:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
import random

def salt_and_pepper(image, n):
    print(image.shape)
    for i in range(int(n / 2)):
        row = random.randint(0, image.shape[0] - 1)
        col = random.randint(0, image.shape[1] - 1)

        write_black = random.randint(0, 2)
        if write_black == 0:
            image[row][col] = (255, 255, 255)
        else:
            image[row][col] = (0, 0, 0)
    return image


def median_blurring():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    img = cv.imread(cv.samples.findFile('opencv-logo-white.png'))

    img = salt_and_pepper(img, img.shape[0] * img.shape[1])

    median = cv.medianBlur(img, 5)

    plt.subplot(121), plt.imshow(img), plt.title('Original')
    plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(median), plt.title('Blurred')
    plt.xticks([]), plt.yticks([])
    plt.show()


if __name__ == "__main__":
    median_blurring()

結果は次のとおりです。

画像

4. 双方向フィルタリング

cv.bi LateralFilter()関数は、エッジをシャープに保ちながらノイズを除去するのに非常に効果的です。ただし、この操作は他のフィルターに比べて時間がかかります。ガウス フィルターがピクセルの周囲を取得し、そのガウス加重平均を求めることを見てきました。このガウス フィルターは、フィルター処理時に近くのピクセルを考慮する別の空間関数です。ピクセルがほぼ同じ強度を持つかどうかは考慮されません。ピクセルがエッジ ピクセルであるかどうかは考慮されません。したがって、エッジもぼやけてしまいますが、これは望ましくありません。

バイラテラル フィルタリングでも空間でガウス フィルタを使用しますが、ピクセル差の関数である追加のガウス フィルタがあります。空間のガウス関数では、近くのピクセルのみがぼかしの対象として考慮されますが、強度差のガウス関数では、中心のピクセルと同様の強度を持つピクセルのみがぼかしの対象として考慮されます。エッジのピクセルの強度が大きく変化するため、エッジが維持されます。

以下の例は、バイラテラル フィルターの使用を示しています (パラメーターの詳細についてはドキュメントを参照してください)。

def bilateral_blurring():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    img = cv.imread(cv.samples.findFile('bilateral.jpg'))

    img = img[0:img.shape[0], 0:int(img.shape[1] / 2)]

    blur = cv.bilateralFilter(img, 9, 75, 75)

    images = [img, blur]
    dest = cv.hconcat(images)

    cv.imshow("Image", dest)
    cv.waitKey(-1)
    cv.destroyAllWindows()


if __name__ == "__main__":
    bilateral_blurring()

結果は次のとおりです。
画像

明らかなテクスチャは消えていますが、エッジはまだ残っています。

その他のリソース

  1. 双方向フィルタリング詳細情報

練習する

参考資料

画像の平滑化

ガウス カーネルで cv2.GaussianBlur と cv2.filter2D を使用すると結果が異なりますか?

OpenCVを使用してカラー画像に塩胡椒ノイズを追加する方法

Python-OpenCVを使用した画像へのノイズ付加(ガウスノイズ、塩胡椒ノイズ)の実装

Pythonの乱数生成

終わり。

おすすめ

転載: blog.csdn.net/tq08g2z/article/details/123976069