Image Filtering 실습

관심 영역의 밝기 반전된 영상 생성하기

입력 영상의 관심 영역에 대한 밝기를 반전한 후 결과를 확인한다. 동일한 영상처리 내용을 개별 픽셀에 대한 접근 방법과 Numpy의 브로드캐스팅 기법으로 수행해본다.

해결 과정 및 주요 코드에 대한 설명

def invert_image_m1(img, rect):
    dst = img.copy()
    length = len(img.shape)
    for x in range(rect[0], rect[2]):
        for y in range(rect[1], rect[3]):
            if (length == 3):
                dst[y, x, 0] = 255 - dst[y, x, 0]
                dst[y, x, 1] = 255 - dst[y, x, 1]
                dst[y, x, 2] = 255 - dst[y, x, 2]
            else:
                dst[y, x] = 255 - dst[y, x]
    return dst

개별 픽셀에 대한 접근 방법에 해당하는 함수이다. img.copy()를 통해 원본 영상의 복제본을 만든다. 다음으로, len을 사용하여 그레이스케일 영상인지 컬러 영상인지 파악하고 이에 따라 영상 반전 처리 관련 코드를 다르게 구현한다. 이중 for문을 이용하여 각각의 픽셀에 접근하여 관심 영역으로 지정한 영역의 픽셀 밝기를 변경한다.

def invert_image_m2(img, rect):
    dst = img.copy()
    dst[rect[1]:rect[3], rect[0]:rect[2]] = 255 - dst[rect[1]:rect[3], rect[0]:rect[2]]
    return dst

브로딩캐스팅 기법에 해당하는 함수이다. 개별 픽셀 접근 방법과 마찬가지로 입력 영상에 대한 복제본을 만든다. 이후 Numpy 라이브러리를 활용하여 슬라이싱 연산을 사용하여 브로드캐스팅 기법을 통해 픽셀의 밝기 반전이 이루어진다.

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, \
			help = "Path to the input image")
ap.add_argument("-s", "--start_point", type = int, \
 			nargs='+', default=[0, 0], \
			help = "Start point of the rectangle")
ap.add_argument("-e", "--end_point", type = int, \
	 		nargs='+', default=[150, 100], \
			help = "End point of the rectangle")
args = vars(ap.parse_args())

filename = args["image"]
sp = args["start_point"]
ep = args["end_point"]

i로 밝기 반전을 처리할 영상의 경로를 입력받고 s와 e를 통해 관심 영역의 시작 위치과 끝 위치를 입력받는다. 각각 default 값이 설정되어 있어 입력 받지 않을 경우 해당 default 값에 해당하는 픽셀부터 관심 영역으로 지정된다. 받아온 값들을 각각 filename, sp, ep 변수에 저장한다.

실행 결과

  • python invert_ROI.py --image ../images/nature_grayscale.jpg 으로 명령을 주었을 경우

    방법 1 소요시간: 0.1040038
    방법 2 소요시간: 0.0028256

관심 영역의 시작 위치와 끝 위치를 기본영역으로 설정한 후 실행시킨 결과 default값에 맞게 왼쪽 상단부터 관심 영역이 설정되었음을 알 수 있다. 소요 시간을 비교해보았을 때, 개별 픽셀에 접근하는 방법보다 numpy를 이용한 브로드캐스팅 기법으로 영상에 반전을 수행했을 때 처리 속도가 더 빠른 것을 확인할 수 있다.

  • python invert_ROI.py —image ../images/nature.jpg —start_point 50 10 —end_point 300 200 으로 명령을 주었을 경우

    방법 1 소요시간: 0.343072
    방법 2 소요시간: 0.0006391

앞선 명령과 달리 반전 영역의 시작 위치과 끝 위치를 지정해 주었을 때의 결과는 입력한 좌표에 맞게 해당 영역이 관심 영역으로 지정되어 영상 반전이 올바르게 이루어졌다. 소요 시간의 경우 마찬가지로 개별 픽셀에 접근하는 방법보다 numpy를 이용한 브로드캐스팅 기법으로 영상에 반전을 수행했을 때 처리 속도가 더 빠른 것을 확인할 수 있다.

  • python invert_ROI.py —image ../images/coins.jpg —start_point 100 100 —end_point 300 300 으로 명령을 주었을 경우

    방법 1 소요시간: 0.402538
    방법 2 소요시간: 0.0007115

입력 영상, 반전 영역의 시작 위치과 끝 위치를 다르게 지정해 주었을 때의 결과는 또한 앞선 실행 결과들처럼 올바르게 영상 반전이 실행됨을 확인했다.

코드

자세한 코드는 Github에서 확인할 수 있다.

언샤프 필터링(unsharp filtering) 수행하기

언샤프 필터링을 사용하여 영상 선명화를 수행한 후 다른 이름으로 저장한다. 필터링 수행 전 영상 평활화도 수행하여 품질을 높인다.

해결 과정 및 주요 코드에 대한 설명

def unsharp_image(img, alpha=1.5, beta=0.5) :
    dst = img.copy()
    dst = cv2.GaussianBlur(dst, (5, 5), 0)
    dst = cv2.addWeighted(image, alpha, dst, -beta, 0)
    return dst

먼저 copy() 함수를 이용하여 원본 영상의 복제본을 만든다. 샤프닝을 수행하기 전, GaussianBlur 함수를 통해 영상에 대한 필터링을 수행한다. 이 때 필터의 크기는 (5, 5)로 지정하였다. 그리하여 원본 영상과 가우시안 필터링을 수행한 dst 영상을 입력 받은 인자값만큼의 비율로 더한 다음 결광 영상에 해당하는 dst를 반환한다.

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", required = True, \
			help = "Path to the input image")
ap.add_argument("-o", "--output", required = True, \
			help = "Path to the output image")
args = vars(ap.parse_args())

infile = args["input"]
outfile = args["output"]

i로 입력 영상에 대한 파일 경로를 입력받고, o로 샤프닝을 수행한 영상을 저장할 파일 경로를 입력받는다. 받아온 값들을 각각 infile, outfile 변수에 저장한다.

실행 결과

  • python invert_ROI.py --input ../images/nature.jpg —output ../images/nature_unsharp.jpg 으로 명령을 주었을 경우

  • python invert_ROI.py --input ../images/pumpkin.jpg —output ../images/pumpkin_unsharp.jpg 으로 명령을 주었을 경우

  • python invert_ROI.py --input ../images/cup.jpg —output ../images/cup_unsharp.jpg 으로 명령을 주었을 경우

Gaussian 블러 처리를 한 후, unsharp 필터링을 수행한 결과 우선 –o에서 지정한 경로로 올바르게 파일이 저장된 것을 확인했다. 또한 정상적으로 선명화 작업이 수행되었음을 확인했다.

코드

자세한 코드는 Github에서 확인할 수 있다.

관심 영역의 모자이크 영상 생성하기

지정한 관심 영역에 모자이크 효과를 만들어낸다. 또한 다양한 방식으로 모자이크 영역을 생성할 수 있도록 한다.

해결 과정 및 주요 코드에 대한 설명

def mosaic_image(img, rect, size=(5,5), mtype=1):
    for x in range(rect[0], rect[2], size[0]):
        for y in range(rect[1], rect[3], size[1]):
            mosaic_area= img[y:y + size[0], x:x + size[1]]
            
            if mtype == 1:
                mosaic_area = np.mean(mosaic_area, 1)
                mosaic_area = np.mean(mosaic_area, 0)
                output = mosaic_area
            elif mtype == 2:
                mosaic_area = np.max(mosaic_area, 1)
                mosaic_area = np.max(mosaic_area, 0)
                output = mosaic_area
            elif mtype == 3:
                mosaic_area = np.min(mosaic_area, 1)
                mosaic_area = np.min(mosaic_area, 0)
                output = mosaic_area
            elif mtype == 4:
                if (rect[2] - x) < size[0]:
                    random_x = random.randrange(rect[0], (rect[2] - x) + rect[0])
                else:
                    random_x = random.randrange(rect[0], rect[0] + size[0])
                if (rect[3] - y) < size[1]:
                    random_y = random.randrange(rect[1], (rect[3] - y) + rect[1])
                else:
                    random_y = random.randrange(rect[1], rect[1] + size[1])
                    
                output = mosaic_area[random_x % size[0]][random_y % size[1]]
            
            img[x:x+size[0], y:y+size[1]] = output
            
    return img

모자이크 범위만큼 이중 for문을 사용하여 영상처리를 진행한다. 4가지 모자이크 타입에 맞게 if-elif문을 사용하여 각 방법에 맞는 numpy 연산을 수행한다. default값인 type 1의 경우 블록의 평균값을 계산하는데, 열단위로 먼저 계산을 수행한 후 행단위로 다시 평균값 계산을 수행한다. type 2와 type 3은 각각 최대값, 최소값에 해당하는 픽셀 값을 구하여 이에 맞게 모자이크 처리를 진행한다. 마지막으로 type 4의 경우 임의의 위치를 정하는 데에는 random 라이브러리를 사용하여 randrange 함수를 통해 임의의 값을 결정한다. 이 과정에서 이중 if문으로 블록 크기를 고려해서 상황에 맞게 재지정해주게 된다.

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, \
			help = "Path to the input image")
ap.add_argument("-s", "--start_point", type = int, \
 			nargs='+', default=[0, 0], \
			help = "Start point of the rectangle")
ap.add_argument("-e", "--end_point", type = int, \
	 		nargs='+', default=[150, 100], \
			help = "End point of the rectangle")
ap.add_argument("-z", "--size", type = int, \
	 		nargs='+', default=[15, 15], \
			help = "Mosaic Size")
ap.add_argument("-t", "--type", type = int, \
	 		default=1, \
			help = "Mosaic Type")
args = vars(ap.parse_args())

filename = args["image"]
sp = args["start_point"]
ep = args["end_point"]
size = args["size"]
mtype = args["type"]

i로 모자이크를 생성할 영상의 경로를 입력받고 s와 e를 통해 모자이크 처리하고자 하는 영역의 시작 위치와 끝 위치를 입력받는다. 각각 default 값이 설정되어 있어 입력받지 않을 때는 default 값에 해당하는 픽셀부터 관심 영역으로 지정된다. z를 이용하여 모자이크의 크기를 입력받고, 모자이크를 처리 방식 4가지에 대해 어떠한 방식으로 처리할지 t를 통해 입력받는다. 마찬가지로 default 값이 각각 지정되어 있다. 받아온 값들을 filename, sp, ep, size, mtype 변수에 저장한다.

실행 결과

  • python mosaic_image.py --image ../images/nature.jpg 으로 명령을 주었을 경우

    default 값이 주어진 인자들에 대해서는 아무런 값도 따로 지정해주지 않고 입력 영상의 주소만 입력해주었을 때의 결과이다. (0, 0)에 해당하는 시작 위치에서부터 type 1에 해당하는 평균값 방식으로 모자이크가 생성되었음을 확인할 수 있다.

  • python mosaic_image.py --image ../images/nature.jpg --type 2 으로 명령을 주었을 경우

    처음의 명령과 동일하지만 모자이크 처리 방식에 대해서만 추가로 type 2로 지정하여 실행한 결과, 최대값에 해당하는 픽셀로 모자이크가 생성되었음을 확인했다.

  • python mosaic_image.py --image ../images/nature.jpg --start_point 100 100 --end_point 200 200 --type 3 으로 명령을 주었을 경우

    모자이크 영역의 시작 위치와 끝 위치를 지정하고 최소값에 해당하는 방식인 type 3를 입력하여 실행시킨 결과이다. 올바른 영역에 최소값에 해당하는 픽셀 값들로 모자이크 처리가 되었음을 확인했다.

  • python mosaic_image.py --image ../images/nature.jpg —start_point 100 100 —end_point 300 300 --size 21 21 --type 4 으로 명령을 주었을 경우

    이번에는 type 4 방식에 size 또한 default 값이 아닌 (21, 21) 로 지정한 후 실행시켰을 때, 기존의 모자이크보다 더 커진 사이즈를 확인할 수 있었다.

코드

자세한 코드는 Github에서 확인할 수 있다.

좋은 웹페이지 즐겨찾기