이전 참고글
10 . 흑백
수많은 이미지 데이터에서도 불 필요하거나 정확하지 않은 부분이 있을 수 있다. 이러한 부분을 걸러내고 이미지로부터 원하는 결과물을 얻어내기 위해 전처리 하는 과정으로 이미지 변형 작업을 수행한다.
이 전에 이미 이미지를 불러오면서 흑백처리하는 과정은 했었다. 이번에는 이미지를 불러올 때 흑백처리를 하는 것이 아닌 불러온 이미지를 흑백처리하는 방법이란 점에서 차이가 있다. 이미지를 불러올 때 흑백처리하는 방법은 아래와 같다.
# 이미지를 불러올 때 흑백처리
import cv2
img = cv2.imread("img.jpg", cv2.IMREAD_GRAYSCALE)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
위의 과정은 이미지를 읽으면서 흑백처리를 한다. 이와 다르게 이미 읽어 온 이미지를 흑백처리할 때는 cv2.cvtColor() 함수를 사용한다.
cv2.cvtColor(file, code)
여기서 cv2.COLOR_BGR2 GRAY코드를 입력하면 불러온 이미지를 흑백처리할 수 있다.
# 불러온 이미지를 흑백으로 변경
import cv2
img = cv2.imread("img.jpg")
dst = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("image", img)
cv2.imshow("gray", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
11. 흐림
이미지를 의도적으로 흐리게 하는 이유는 보이는 정보를 흐리게 함으로 써 외곽선 검출과 같은 작업을 보다 단순하게 처리할 수 있기 때문이다. 여러 가지 블러 처리 방법 중 가우시안 블러처리 방법을 사용해 이미지를 블러처리한다.
가우시안 블러(Gaussian Blur)
가우시안 블러는 이미지를 흐리게 할 뿐만 아니라 노이즈를 동시에 제거할 수 있다. 따라서 이미지연산이 필요할 때 보다 빠르고 정확하게 계산할 수 있다. 가우시안 블러효과를 적용하기 위해 cv2.GaussianBlur() 함수를 사용한다.
kernel = cv2.GaussianBlur(file, kernel size, sigma X)
kernel 값은 블러처리의 정도를 의미하는데, 이때 kernel size는 일반적으로 양수의 홀수로 지정할 때 가장 좋은 성능을 보인다. 따라서 (3, 3), (5, 5), (7, 7)과 같은 값으로 설정한다.
sigma X는 가우시안 커널의 x 방향의 표준편차를 의미한다.
커널 사이즈 변화에 따른 흐림
커널 사이즈변화에 따른 흐림 효과를 지정할 때에는 커널 사이즈를 조정하고, 표준편차값은 0으로 둔다. 커널 사이즈 값에 따라 흐림 효과가 다르다. 이를 확인하기 위해 원본 사진과 각각의 이미지에 (3, 3), (5, 5), (7, 7)으로 커널 사이즈를 적용하여 확인하면 다음과 같다.
import cv2
img = cv2.imread("img.jpg")
# kernel = cv2.GaussianBlur(file, kernel_size, sigma_X(표준편차))
kernel_3 = cv2.GaussianBlur(img, (3,3), 0)
kernel_5 = cv2.GaussianBlur(img, (5,5), 0)
kernel_7 = cv2.GaussianBlur(img, (7,7), 0)
cv2.imshow("image", img)
cv2.imshow("kernel_3", kernel_3)
cv2.imshow("kernel_5", kernel_5)
cv2.imshow("kernel_7", kernel_7)
cv2.waitKey(0)
cv2.destroyAllWindows()
사진을 자세히 보면 커널 사이즈를 조정하면 사진이 흐리게 보이는 것을 확인할 수 있다. 또한 kernel_3과 kernel_7을 비교했을 때 커널 사이즈가 클수록 흐림 정도가 더 큰 것을 알 수 있다.
표준편차 변화에 따른 흐림
표준편차 값에 따른 흐림정도를 비교하기 위해선 커널사이즈를 (0, 0)으로 고정하고 표준편차에 차이를 두면 확인할 수 있다. 예를 들어 표준편차 값이 각각 1, 2, 3인 이미지를 비교해 보면 다음과 같다.
import cv2
img = cv2.imread("img.jpg")
sigma_1 = cv2.GaussianBlur(img, (0,0), 1)
sigma_2 = cv2.GaussianBlur(img, (0,0), 2)
sigma_3 = cv2.GaussianBlur(img, (0,0), 3)
cv2.imshow("image", img)
cv2.imshow("sigma_1", sigma_1)
cv2.imshow("sigma_2", sigma_2)
cv2.imshow("sigma_3", sigma_3)
cv2.waitKey(0)
cv2.destroyAllWindows()
위 결과를 통해 표준편차 값이 커질수록 흐린 정도가 더 큰 것을 알 수 있다. 또한 커널 사이즈 변화에 따른 흐린 정도 보다 표준편차값의 차이가 더 흐린 정도가 큰 것을 확인할 수 있다.
12. 원근
원근은 눈으로 보는 3차원을 2차원의 평면으로 옮길 때, 일정한 시점에서 본 것 그대로 멀고 가까운 거리감을 느낄 수 있음을 의미한다. 이러한 원근이 적용된
이러한 원근이 적용된 이미지를 평면으로 변환하기 위해 먼저 원근법이 적용된 이미지를 불러온다
사다리꼴 이미지 펼치기
import cv2
img = cv.imread("newspaper.jpg")
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
위의 이미지를 보면 이미지의 아래쪽은 가깝고 위로가 수록 시선에서 멀어져 기울어진 느낌이며, 포커스가 맞는 중앙을 중심으로 그 외에는 마치 블러처리되어 거리감이 잘 느껴지는 이미지이다. 여기서 포커싱이 맞는 사다리꼴 형태의 기사 부분을 똑바로 직사각형 형태로 출력하기 위해선 다음 과정을 거친다.
이미지 좌표 찾기 - 출력 이미지 좌표 지정 - 크기변환 정보 정의 - 크기 변환
이미지 좌표 찾기
먼저 원근을 적용한 특정 부분을 가져오기 위해서 input이 되는 네 개의 좌표를 찾아야 한다. 이미지에서 좌표를 찾기 위해서는 이미지를 그림판에서 연다. 여기서 커서를 각각의 점에 올려두면 왼쪽 하단에 좌표에 대한 정보가 뜨는데, 이 좌표가 바로 커서의 위치를 의미한다.
input은 위의 방법을 통해 이미지에 표시한 4개의 좌표이다. 각각의 좌표를 찾아보면 왼쪽 상단부터 시계방향으로 대략 (510, 351), (1006, 351), (1127, 593), (447, 593)이다. 이를 numpy의 array 형식으로 정의한다.
src = np.array([[510, 351], [1006, 351], [1127,593], [447, 593]], dtype)
출력 이미지 좌표 지정
변환할 이미지의 좌표를 찾고 나면 변환후 출력할 이미지의 좌표를 지정한다. output의 좌표는 먼저 출력할 결과의 width, height를 정하고, 왼쪽 상단부터 시계방향으로 (0, 0), (width, 0), (width, height), (0, height) 순서로 정의한다. 좌표는 input의 경우와 마찬가지로 numpy의 array 형식으로 정의한다.
dst = np.array([[0, 0], [width, 0], [width, height], [0,height]], dtype)
크기 변환 정보 정의
크기를 변환하기 위해 cv2.getPerspectiveTransform() 함수에 input 좌표(src)와 output 좌표(dst)를 입력해 변환 정보가 담긴 matrix를 얻어온다.
matrix = cv2.getPerspectiveTransform(src, dst)
크기 변환
cv2.warpPerspective()함수를 이용해 이 전에 얻은 변환정보가 담긴 matrix와 출력 이미지 크기인 width와 height를 튜플형태로 대입하여 matrix 대로 변환한다.
cv2.warpPerspective(file, matrix, dsize = (width, height))
위 과정을 바탕으로 예시 이미지에 적용하면 다음과 같다
import cv2
import numpy as np
img = cv2.imread("newspaper.jpg")
width, height = 640, 240
# input
src = np.array([[510, 351], [1006, 351], [1127,593], [447, 593]], dtype = np.float32)
# output
dst = np.array([[0,0], [width, 0], [width, height], [0,height]], dtype = np.float32)
matrix = cv2.getPerspectiveTransform(src, dst)
result = cv2.warpPerspective(img, matrix, (width, height))
cv2.imshow("image", img)
cv2.imshow("transform", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
회전된 이미지 올바르게 세우기
회전된 이미지를 올바르게 세우는 방법도 위에서 봤던 사다리꼴 이미지를 펼치는 방법과 동일하다. 먼저 회전된 이미지는 다음과 같은 이미지를 의미한다.
위의 이미지에서 다이아A카드가 바르게 있지 않고 오른쪽으로 기울어져 있다. 이처럼 기울어진 이미지도 사다리꼴 형태의 이미지를 바르게 출력하는 것처럼 input좌표를 찾고, output 좌표에 변환하여 출력하면 된다.
import cv2
import numpy as np
img = cv2.imread("poker.jpg")
width, height = 530, 710
# input
src = np.array([[951, 202], [1267,470], [880,900], [576,607]], dtype = np.float32)
# output
dst = np.array([[0,0], [width, 0], [width, height], [0,height]], dtype = np.float32)
matrix = cv2.getPerspectiveTransform(src, dst)
result = cv2.warpPerspective(img, matrix, (width, height))
cv2.imshow("image", img)
cv2.imshow("transform", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
'Study > ML | DL' 카테고리의 다른 글
[Python] OpenCV를 이용한 반 자동 문서스캐너 구현하기2 - 반 자동 문서 스캐너 구현 (0) | 2023.06.01 |
---|---|
[Python] OpenCV를 이용한 반 자동 문서스캐너 구현하기1 - Mouse event (0) | 2023.05.25 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 이미지 처리 (0) | 2023.05.19 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 크기 조정 (0) | 2023.05.18 |
[Python] OpenCV를 이용한 이미지/영상 처리 - 파일 저장 (0) | 2023.05.17 |