山内セミナーⅠ(2020/07/01)

関連サイトと資料

サンプル画像


color_spaces.png


lena_image.png


cat-face.png


cat.jpg


lenna.png


cat.png


lenna_250.png


opencv_binary_logo_250.png

morpho_test_imgs.zip

Image filtering

このセクションでは、画像をぼかしたり、鮮明にしたりする方法に取り組みます。カスタムメイドのカーネルも適用します。 さらに、他の画像処理機能を実行するために使用できる、いくつかの一般的なカーネルにも注目します。

Applying arbitrary kernels

OpenCVは、任意のカーネルを画像に適用するためにcv2.filter2D()関数を提供し、提供されたカーネルで画像をたたみ込みます。 この関数がどのように機能するかを確認するには、まず、後で使用するカーネルを構築する必要があります。 この場合、次のコードに示すように、5 x 5カーネルが使用されます。

kernel_averaging_5_5 = np.array([[0.04, 0.04, 0.04, 0.04, 0.04], [0.04,
0.04, 0.04, 0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04],[0.04, 0.04, 0.04,
0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04]])
    

これは5 x 5の平均化カーネルに対応します。 さらに、このような方法でカーネルを作成することもできます。

kernel_averaging_5_5 = np.ones((5, 5), np.float32) / 25

次に、前述の関数を適用して、ソースイメージにカーネルを適用します。 次のコードに示されています:

smooth_image_f2D = cv2.filter2D(image, -1, kernel_averaging_5_5)

ここまで、任意のカーネルをイメージに適用する方法を見てきました。 前の例では、 画像を滑らかにするために平均化カーネルが作成されました。 カーネルを作成する必要のない、画像の平滑化(画像のぼかしとも呼ばれます)を 実行する他の方法もあります。 代わりに、いくつかの他のパラメーターを対応するOpenCV関数に与えます。

Smoothing images

前述のように、smoothing_techniques.pyスクリプトでは、他の 平滑化操作を実行するための一般的なフィルタリング手法を使用しています。 平滑化手法は一般的にノイズを減らすために使用され、さらに、 これらの技術は低解像度画像のピクセル効果を減らすために適用することができます。

Averaging filter

カーネルで画像をたたみ込むことで画像平滑化を行うに際して、 cv2.blur()とcv2.boxFilter()の両方が使えます。 ただし、cv2.boxFilter()では正規化は行われません。 これらの手法は、単にカーネル領域の下のすべてのピクセルの平均を取り、 中央の要素をこの平均値に置き換えます。 ユーザーが制御できるのは、カーネルサイズとアンカーカーネル(デフォルトでは(-1、-1)、 つまりアンカーはカーネルのセンターにあります)です。 cv2.boxFilter()の正規化パラメーター(デフォルトではTrue)がTrueの場合、 両方の関数は同じ処理を実行します。 このようにして、両方の関数が 次の式に示すように、カーネルを使用して画像の平滑化を行います。

\( K = \frac{1}{\alpha} \left[ \begin{array}{ccc} 1 & 1 & \ldots & 1 \\ 1 & 1 & \ldots & 1 \\ \vdots & \vdots & \ddots & \vdots \\ 1 & 1 & \ldots & 1 \end{array} \right] \)

cv2.boxFilter()の場合は以下のようになる。

\( \begin{eqnarray} \alpha=\left\{ \begin{array}{ll} ksize.width \times ksize.height & (normalize=true) \\ 1 & (normalize=false) \\ \end{array} \right. \end{eqnarray} \)

cv2.blur()の場合は以下のようになる。

\( \alpha = ksize.width \times ksize.height \)

Gaussian filtering

OpenCVは、cv2.GaussianBlur()関数を提供します。 これは、ガウスカーネルによって画像をぼかします。 このカーネルは、次のパラメーターを使用して制御できます: ksize(カーネルサイズ)、sigmaX(ガウスカーネルのx方向の標準偏差)、および sigmaY(ガウスカーネルのy方向の標準偏差)。 どのカーネルが適用されるか知るために、あなたはcv2.getGaussianKernel()関数を利用することができます。 たとえば次のコードでは、cv2.GaussianBlur()は、サイズ(9、9)のガウスカーネルを用いて画像をぼかします。

smooth_image_gb = cv2.GaussianBlur(image, (9, 9), 0)
    

Median filtering

OpenCVは、次のコードに示すように、中央値カーネルで画像をぼかすcv2.medianBlur()関数を提供します。

smooth_image_mb = cv2.medianBlur(image, 9)
    

このフィルターは、画像のソルトアンドペッパーノイズ(ごましお雑音)を低減するために適用できます。

Bilateral filtering

バイラテラルフィルターを適用するためには、cv2.bilateralFilter()関数を入力画像に適用します。 この関数は、エッジを維持しながらノイズを低減します。

smooth_image_bf = cv2.bilateralFilter(image, 5, 10, 10)
    

これまでのすべてのフィルターは、エッジを含む画像全体を平滑化する傾向があることに注意すべきです。

サンプルプログラム(1)

smoothing_techniques.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
	
def show_with_matplotlib(color_img, title, pos):
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(3, 3, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
	
plt.figure(figsize=(12, 6))
plt.suptitle("Smoothing techniques", fontsize=14, fontweight='bold')
	
image = cv2.imread('cat-face.png')
	
kernel_averaging_10_10 = np.ones((10, 10), np.float32) / 100
kernel_averaging_5_5 = np.array([[0.04, 0.04, 0.04, 0.04, 0.04],
                                 [0.04, 0.04, 0.04, 0.04, 0.04],
                                 [0.04, 0.04, 0.04, 0.04, 0.04],
                                 [0.04, 0.04, 0.04, 0.04, 0.04],
                                 [0.04, 0.04, 0.04, 0.04, 0.04]])
print("kernel: {0}".format(kernel_averaging_5_5))
	
smooth_image_f2D_5_5 = cv2.filter2D(image, -1, kernel_averaging_5_5)
smooth_image_f2D_10_10 = cv2.filter2D(image, -1, kernel_averaging_10_10)
smooth_image_b = cv2.blur(image, (10, 10))
smooth_image_bfi = cv2.boxFilter(image, -1, (10, 10), normalize=True)
smooth_image_gb = cv2.GaussianBlur(image, (9, 9), 0)
smooth_image_mb = cv2.medianBlur(image, 9)
smooth_image_bf = cv2.bilateralFilter(image, 5, 10, 10)
smooth_image_bf_2 = cv2.bilateralFilter(image, 9, 200, 200)
	
show_with_matplotlib(image, "original", 1)
show_with_matplotlib(smooth_image_f2D_5_5, "cv2.filter2D() (5,5) kernel", 2)
show_with_matplotlib(smooth_image_f2D_10_10, "cv2.filter2D() (10,10) kernel", 3)
show_with_matplotlib(smooth_image_b, "cv2.blur()", 4)
show_with_matplotlib(smooth_image_bfi, "cv2.boxFilter()", 5)
show_with_matplotlib(smooth_image_gb, "cv2.GaussianBlur()", 6)
show_with_matplotlib(smooth_image_mb, "cv2.medianBlur()", 7)
show_with_matplotlib(smooth_image_bf, "cv2.bilateralFilter() - small values", 8)
show_with_matplotlib(smooth_image_bf_2, "cv2.bilateralFilter() - big values", 9)
	
plt.show()
    

Sharpening images

この最後の関数に関連して、画像のエッジをシャープにするために、試すことができるいくつかのオプションがあります。 1つの簡単なアプローチは、アンシャープマスキングと呼ばれるものを実行することです。 これは平滑化された画像を元の画像から差し引くというものです。 次の例では、最初にガウス平滑化フィルターを適用し、元の画像から差し引いています。

smoothed = cv2.GaussianBlur(img, (9, 9), 10)
unsharped = cv2.addWeighted(img, 1.5, smoothed, -0.5, 0)
    

別のオプションは、エッジをシャープにするために特定のカーネルを使用することです。 カーネルの適用は、cv2.filter2D()関数を使用します。 sharpening_techniques.pyスクリプトでは、この目的に適用できるいくつかのカーネルを定義しています。

サンプルプログラム(2)

sharpening_techniques.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
	
def show_with_matplotlib(color_img, title, pos):
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(2, 3, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
	
def unsharped_filter(img):
    smoothed = cv2.GaussianBlur(img, (9, 9), 10)
    return cv2.addWeighted(img, 1.5, smoothed, -0.5, 0)
	
plt.figure(figsize=(12, 6))
plt.suptitle("Sharpening images", fontsize=14, fontweight='bold')
	
image = cv2.imread('cat-face.png')
	
kernel_sharpen_1 = np.array([[0, -1, 0],
                             [-1, 5, -1],
                             [0, -1, 0]])
	
kernel_sharpen_2 = np.array([[-1, -1, -1],
                             [-1, 9, -1],
                             [-1, -1, -1]])
	
kernel_sharpen_3 = np.array([[1, 1, 1],
                             [1, -7, 1],
                             [1, 1, 1]])
	
kernel_sharpen_4 = np.array([[-1, -1, -1, -1, -1],
                             [-1, 2, 2, 2, -1],
                             [-1, 2, 8, 2, -1],
                             [-1, 2, 2, 2, -1],
                             [-1, -1, -1, -1, -1]]) / 8.0
	
sharp_image_1 = cv2.filter2D(image, -1, kernel_sharpen_1)
sharp_image_2 = cv2.filter2D(image, -1, kernel_sharpen_2)
sharp_image_3 = cv2.filter2D(image, -1, kernel_sharpen_3)
sharp_image_4 = cv2.filter2D(image, -1, kernel_sharpen_4)
sharp_image_5 = unsharped_filter(image)
	
show_with_matplotlib(image, "original", 1)
show_with_matplotlib(sharp_image_1, "sharp 1", 2)
show_with_matplotlib(sharp_image_2, "sharp 2", 3)
show_with_matplotlib(sharp_image_3, "sharp 3", 4)
show_with_matplotlib(sharp_image_4, "sharp 4", 5)
show_with_matplotlib(sharp_image_5, "sharp 5", 6)
	
plt.show()