brunch

You can make anything
by writing

C.S.Lewis

by 서준수 May 19. 2019

파이썬 이미지 프로세싱 (5)

블러 효과

파이썬 이미지 프로세싱 (5)


노이즈를 좀 줄여볼까 하다가 실패한 결과로 블러 효과가 탄생했다.

실패는 처음부터 예상된 결과였다. 어떤 방식이었냐면 각 픽셀의 그레이스케일 값을 주변 픽셀의 그레이스케일 평균값으로 보정하는 것이었다. 그러면 노이즈뿐만 아니라 정상적인 픽셀도 변경이 된다. 결과적으로 선명도가 떨어져 블러 효과가 나타나게 된다. 알고 보니 실제로 블러 효과를 줄 때 이것과 비슷하게 주변 픽셀의 평균값을 이용하는 방식이 존재했다. 또한 노이즈 감소를 위해서도 이러한 방법을 좀 더 복잡하게 이용한다.


블러 효과


보정할 픽셀의 평균값을 구할 때는 경곗값에 주의해야 한다.



위 그림에서처럼 좌측 상단의 픽셀은 주변의 3개 픽셀의 평균값으로 보정한다.



가장자리에 있는 픽셀은 주변의 5개 픽셀의 평균값으로 보정한다.



마지막으로 내부에 위치한 일반적인 픽셀들은 주변의 8개 픽셀의 평균값으로 보정한다.

이런 식으로 모든 픽셀을 주변 픽셀의 평균값으로 대체하면 이미지가 흐리게 된다. 즉 블러 효과가 나타난다.


주변에 가장 많은 8개의 픽셀이 있을 때만 for문으로 처리했고 나머지는 그냥 하드 코딩했다.


import matplotlib.pyplot as plt

import cv2

def draw_image(original_img, result_img, title, original_title, result_title):

    fig = plt.figure()

    fig.suptitle(title)

    ax = fig.add_subplot(1, 2, 1)

    ax.imshow(original_img, cmap=plt.cm.gray)

    ax.set_title(original_title)

    ax = fig.add_subplot(1, 2, 2)

    ax.imshow(result_img, cmap=plt.cm.gray)

    ax.set_title(result_title)

    plt.show()

def blur_image():

    file_path = "img\\camera.bmp"

    original_img = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE)

    result_img = original_img.copy()

    row, col = original_img.shape

    near_pixel_list = []

    for i in range(0, row):

        for j in range(0, col):

            if 0 < i < row - 2 and 0 < j < col - 2:

                for k in range(i - 1, i + 3):

                    for l in range(j - 1, j + 3):

                        if not (i == k and j == l):

                            near_pixel_list.append(original_img[k, l])

            elif i == 0 and j == 0:

                # 좌상단

                near_pixel_list.append(original_img[i + 1, j])

                near_pixel_list.append(original_img[i, j + 1])

                near_pixel_list.append(original_img[i + 1, j + 1])

            elif i == 0 and j == col - 1:

                # 우상단

                near_pixel_list.append(original_img[i, j - 1])

                near_pixel_list.append(original_img[i + 1, j])

                near_pixel_list.append(original_img[i, j - 2])

            elif i == row - 1 and j == 0:

                # 좌하단

                near_pixel_list.append(original_img[i - 1, j])

                near_pixel_list.append(original_img[i - 1, j + 1])

                near_pixel_list.append(original_img[i, j + 1])

            elif i == row - 1 and j == col - 1:

                # 우하단

                near_pixel_list.append(original_img[i - 1, j])

                near_pixel_list.append(original_img[i - 1, j - 1])

                near_pixel_list.append(original_img[i, j - 1])

            elif i == 0 and 0 < j < col - 1:

                # 첫 행

                near_pixel_list.append(original_img[i, j - 1])

                near_pixel_list.append(original_img[i, j + 1])

                near_pixel_list.append(original_img[i + 1, j - 1])

                near_pixel_list.append(original_img[i + 1, j])

                near_pixel_list.append(original_img[i + 1, j + 1])

            elif j == 0 < i < row - 1:

                # 첫 열

                near_pixel_list.append(original_img[i - 1, j])

                near_pixel_list.append(original_img[i - 1, j + 1])

                near_pixel_list.append(original_img[i, j + 1])

                near_pixel_list.append(original_img[i + 1, j])

                near_pixel_list.append(original_img[i + 1, j + 1])

            elif j == col - 1 and 0 < i < row - 1:

                # 끝 열

                near_pixel_list.append(original_img[i - 1, j])

                near_pixel_list.append(original_img[i - 1, j - 1])

                near_pixel_list.append(original_img[i, j - 1])

                near_pixel_list.append(original_img[i + 1, j])

                near_pixel_list.append(original_img[i + 1, j - 1])

            elif i == row - 1 and 0 < j < col - 1:

                # 끝 행

                near_pixel_list.append(original_img[i, j - 1])

                near_pixel_list.append(original_img[i, j + 1])

                near_pixel_list.append(original_img[i - 1, j - 1])

                near_pixel_list.append(original_img[i - 1, j])

                near_pixel_list.append(original_img[i - 1, j + 1])

            if len(near_pixel_list) > 0:

                result_img[i, j] = sum(near_pixel_list) / len(near_pixel_list)

                near_pixel_list.clear()

    draw_image(original_img, result_img, "Blur Image", "Original Image", "Result Image")

    cv2.imwrite("blur_image.bmp", result_img)

blur_image()




그런데 사실 OpenCV를 사용하면 기본적으로 제공되는 훌륭한 블러 함수들이 있다.

가장 기본적인 방법으로 다음과 같이 단 한 줄만으로 여태까지 열심히 각 픽셀의 평균값을 구하던 작업을 수행할 필요가 없어진다. 심지어 가장자리 처리를 보면 훨씬 품질이 좋다.


result_img = cv2.blur(original_img, (3, 3))



OpenCV blur 함수 사용 결과


OpenCV blur 함수 사용 코드


ref.)

이미지 출처 : https://github.com/gilbutITbook/006796/blob/master/images/ch07/camera.bmp

OpenCV 블러 자료 (1) : https://webnautes.tistory.com/1255

OpenCV 블러 자료 (2) : https://docs.opencv.org/3.4.3/d4/d13/tutorial_py_filtering.html

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari