OpenCV 강좌, Perspective 변환과 문서 스캐너 만들기

이번 강좌에서는 OpenCV를 활용하여 이미지의 Perspective(원근) 변환을 이해하고, 이를 기반으로 문서 스캐너를 구현하는 방법에 대해 알아보겠습니다. 문서 스캐너는 촬영된 문서 이미지에서 왜곡된 부분을 수정하고 실제 문서와 같은 형태로 변환하여 편리하게 사용할 수 있도록 도와주는 기능입니다.

OpenCV란?

OpenCV(Open Source Computer Vision Library)는 실시간 이미지 처리와 컴퓨터 비전 작업을 위한 라이브러리입니다. 다양한 이미지 처리 및 컴퓨터 비전 알고리즘을 제공하며, Python, C++, Java 등 여러 언어에서 사용할 수 있습니다. OpenCV는 이미지 필터링, 객체 인식, 이미지 변형, 모션 분석 등 여러 기능을 지원합니다.

Perspective 변환이란?

Perspective 변환은 2차원 이미지를 3차원 공간에서의 관점에 따라 변형하는 방법입니다. 이미지를 한쪽 면이 더 넓게 보이게 하거나, 특정 각도에서 바라본 듯한 왜곡 효과를 줄 수 있습니다. 이는 주로 촬영된 이미지를 왜곡 없이 교정할 때 유용하게 사용됩니다.

Perspective 변환의 정의

원근 변환은 4개의 점을 통해 정의됩니다. 이 4개의 점은 원본 이미지에서 변환할 사각형의 코너를 구성하며, 이를 목표 이미지에서 일치하는 4개의 점과 연결하여 변환을 수행합니다.

OpenCV 설치하기

시작하기에 앞서 OpenCV를 설치해야 합니다. Python 환경에서 OpenCV를 설치하려면 다음 명령어를 실행하십시오:

pip install opencv-python opencv-python-headless numpy

Perspective 변환을 위한 기초 예제

먼저 간단한 이미지를 불러온 후, Perspective 변환을 적용하는 기본적인 예제를 살펴보겠습니다.

예제 코드: 기본 Perspective 변환

import cv2
import numpy as np

# 이미지 로드
image = cv2.imread('document.jpg')

# 변환할 점들 (원본)
points_src = np.float32([[100, 100], [400, 100], [100, 400], [400, 400]])

# 변환할 점들 (목표)
points_dst = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])

# 변환 행렬 계산
matrix = cv2.getPerspectiveTransform(points_src, points_dst)

# Perspective 변환 적용
warped_image = cv2.warpPerspective(image, matrix, (300, 300))

# 결과 이미지 보기
cv2.imshow('Warped Image', warped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

위의 코드를 통해 원본 이미지를 불러오고, 변환할 사각형의 네 점을 지정하여 원근 변환을 적용하였습니다. ‘document.jpg’는 여러분이 변환하고자 하는 이미지 파일의 경로로 변경해주어야 합니다.

문서 스캐너 구현

문서 스캐너를 만들기 위해서는 촬영된 문서 이미지로부터 사각형 형태의 영역을 찾아내고, 이를 Perspective 변환을 통해 정사각형으로 변환해야 합니다. 다음 단계로 진행해보겠습니다.

1단계: 이미지 전처리

먼저, 입력 이미지를 그레이스케일로 변환하고, 블러링 및 에지 검출을 수행하여 문서의 경계를 강조합니다.

# 이미지 로드
image = cv2.imread('scanned_document.jpg')

# 그레이스케일 변환
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 이미지 블러링
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# 엣지 검출
edged = cv2.Canny(blurred, 75, 200)

# 확인을 위해 엣지 이미지 표시
cv2.imshow('Edged Image', edged)
cv2.waitKey(0)
cv2.destroyAllWindows()

2단계: 윤곽선 찾기

문서의 윤곽선을 찾기 위해서 OpenCV의 findContours 함수를 사용할 수 있습니다. 찾은 윤곽선 중에서 사각형 형태의 윤곽선을 선별하여야 합니다.

# 윤곽선 찾기
contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 가장 큰 윤곽선 선택
contour = max(contours, key=cv2.contourArea)

# 그려진 윤곽선 시각화
image_contours = image.copy()
cv2.drawContours(image_contours, [contour], -1, (0, 255, 0), 2)

cv2.imshow('Contours', image_contours)
cv2.waitKey(0)
cv2.destroyAllWindows()

3단계: 사각형 변환 포인트 결정

선택한 윤곽선에서 사각형의 네 점을 선택합니다. 이 점들은 Perspective 변환을 위해 사용될 것입니다. 일반적으로 이 점들은 시계 방향으로 정렬되어야 합니다.

# 사각형 변환 포인트 정리
epsilon = 0.02 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)

if len(approx) == 4:
    points = approx.reshape(4, 2)
else:
    print("사각형을 찾을 수 없습니다.")
    points = None

4단계: Perspective 변환 적용

마지막으로, 선택된 사각형 변환 포인트를 기준으로 Perspective 변환을 적용합니다.

if points is not None:
    # 목표 점 생성 (정사각형 형태)
    width = max(np.linalg.norm(points[0]-points[1]), np.linalg.norm(points[2]-points[3]))
    height = max(np.linalg.norm(points[0]-points[3]), np.linalg.norm(points[1]-points[2]))
    
    destination_points = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
    
    # 변환 행렬 계산
    matrix = cv2.getPerspectiveTransform(points, destination_points)
    
    # Perspective 변환 적용
    warped = cv2.warpPerspective(image, matrix, (int(width), int(height)))
    
    # 결과 이미지 보기
    cv2.imshow('Scanned Document', warped)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

마무리

이번 강좌에서는 OpenCV를 이용한 원근 변환 기법과 문서 스캐너를 만드는 방법을 살펴보았습니다. 이미지 내 사각형 영역을 찾아내고, 이 영역을 정사각형으로 변환하는 과정은 이미지 처리의 기초를 다지는데 큰 도움이 됩니다. 이 기술을 기반으로 다양한 이미지 처리 프로젝트로 확장할 수 있습니다.

편리한 문서 스캐너를 만드는 것 외에도, 다른 형태의 이미지 변환이나 처리에 응용할 수 있으니, 실습을 통해 다양한 시도를 해보시기 바랍니다. 다음 강좌에서는 더 심화된 OpenCV 기능에 대해 다뤄보겠습니다. 감사합니다!