- 구부러진 문서 사진을 평평한 이미지로 바꾸기 위해 3D 자세와 곡률을 모델링하고, 텍스트 기준점을 맞추는 최적화 문제로 풀어냄
- Leptonica와 CTM처럼 텍스트를 줄 단위로 나눈 뒤, 줄들이 평행하고 수평에 가깝게 보이도록 좌표 변환을 찾는 흐름을 따름
- 모델은 회전 벡터
r, 이동 벡터t, 곡률 기울기α,β, 텍스트 span의x,y오프셋을 포함하며 재투영 오차를 최소화함 - 파이프라인은 페이지 경계 자르기, 텍스트 윤곽 검출, span 조립, 기준점 샘플링, 초기값 생성, Powell 최적화,
cv2.remap재매핑으로 이어짐 - 예제 실행에서 파라미터는 104~600개, 총 실행 시간은 5.3~24.8초였고 대부분이 최적화에 쓰여 solver나 컴파일 언어로 속도 개선 여지가 남음
구부러진 페이지를 최적화 문제로 풀기
- 손글씨 사진을 PDF로 만드는 기존 스크립트는
adaptiveThreshold와 여러 이미지를 PDF로 묶는 수준이었지만, 보관 문서 사진에서는 페이지 말림 때문에 텍스트가 크게 휘어짐 - 목표는 구부러진 페이지 사진을 자동으로 평평한 문서 이미지로 변환하는 프로그램을 만드는 것임
- 코드는 GitHub의 page_dewarp에 공개되어 있음
Leptonica와 CTM에서 가져온 기본 흐름
- 문서 이미지 왜곡 보정은 이미 알려진 문제이며, Dan Bloomberg의 오픈소스 이미지 처리 라이브러리 Leptonica에도 구현되어 있음
- 참고 자료에는 dewarping contest 결과 요약과 우승 방식인 Coordinate Transform Model, 즉 CTM 관련 논문이 포함됨
- Leptonica와 CTM은 문제를 공통적으로 두 단계로 나눔
- 텍스트를 줄 단위로 분리함
- 줄들이 평행하고 수평이 되도록 왜곡 또는 좌표 변환을 찾음
- 이 구현은 페이지 외형을 여러 파라미터로 표현함
r,t: 페이지의 3D 방향과 위치를 나타내는 회전 벡터와 이동 벡터α,β: 페이지 표면 곡률을 정하는 두 기울기y₁ ... yₙ: 페이지 위n개 수평 span의 세로 오프셋xᵢ: 각 span 안의 여러 기준점에 대한 가로 오프셋
3D 곡면과 재투영 오차
- 페이지의 3D 형태는 로컬
y축 방향으로 곡선을 쓸어 만든 표면으로 표현함 - 페이지의 가로 좌표
x는 표면의z방향 변위로 매핑되며, 수평 단면은 3차 스플라인으로 모델링함- 스플라인 양 끝점은 0으로 고정됨
- 끝점 기울기
α,β만으로 스플라인 형태가 정해짐
- 자세와 곡률 파라미터가 정해지면, 페이지의 각
(x, y)좌표가 이미지 평면의 특정 위치로 투영됨 - 원본 사진에서 수평 텍스트 span의 keypoint를 찾고, 초기 추정값에서 시작해 keypoint의 재투영 오차를 최소화하는 파라미터를 찾음
- 최적화 전에는 곡률이 없다고 가정해 재투영점이 일직선에 놓이지만, 최적화 후에는 모델 투영점이 실제 검출 keypoint에 거의 겹침
이미지 처리 파이프라인
-
페이지 경계 자르기
- 이미지 전체를 쓰지 않고, 가장자리의 불필요한 영역을 피하기 위해 고정 margin으로 가운데 영역만 잘라냄
- 지능적인 페이지 경계 검출은 사용하지 않음
-
텍스트 윤곽 검출
- 초기 adaptive threshold를 적용함
- 수평 박스로 morphological dilation)을 수행해 가로로 인접한 마스크 픽셀을 연결함
- 수직 박스로 erosion)을 수행해 한 픽셀 높이의 잡음을 제거함
- connected component analysis 뒤, 너무 높거나 두꺼운 blob을 걸러냄
- 남은 텍스트 윤곽은 PCA로 가장 잘 맞는 선분으로 근사함
-
수평선 검출 보완
- 일부 입력은 세로 텍스트가 많은 표 형태였기 때문에, 수평 텍스트가 충분히 검출되지 않으면 수평선이나 rule 검출도 시도함
텍스트 span 구성과 기준점 샘플링
- 검출된 윤곽들을 같은 수평 span에 묶기 위해 모든 윤곽 쌍에 대해 후보 edge를 만들고 비용을 계산함
- 두 윤곽이 길이 방향으로 크게 겹치거나 너무 멀거나 각도가 많이 벌어지면 비용을 무한대로 둠
- 유효한 edge의 비용은 거리와 각도 변화의 선형 조합으로 계산됨
- edge를 비용순으로 정렬한 뒤, 양쪽 윤곽이 아직 연결되지 않았을 때만 연결하는 탐욕적 이차 시간 방식을 사용함
- 실행 시간 대부분이 최적화에 쓰이므로 이 단계의 이차 시간 복잡도는 큰 문제가 아니었음
- span이 만들어진 뒤에는 너무 작아 모델 결정에 도움이 되지 않는 span을 제거함
- 파라미터 모델에는 이산 기준점이 필요하므로, 텍스트 윤곽 약 20픽셀마다 keypoint 하나를 선택함
초기값 생성과 Powell 최적화
- 모든 span의 평균 방향은 PCA로 추정함
- PCA 결과의 주성분을 이용해 초기
x,y좌표와 평평한 무곡률 페이지의 자세를 해석적으로 설정함 - 재투영은 3차 스플라인을 샘플링해 객체점의
z오프셋을 얻고, OpenCV 함수로 이미지 평면에 투영함cv2.solvePnPcv2.projectPoints
- 재투영 오차 최소화에는
scipy.optimize.minimize와'Powell'solver를 사용함- 블랙박스 방식의 미분 없는 최적화 도구로 사용됨
- 문제 자체는 비선형 최소제곱에 해당함
- 다른 solver나 특화된 비선형 최소제곱 solver는 많이 실험하지 않음
- 프로그램 실행 시간의 거의 100%가 이 최적화 단계에 쓰임
재매핑과 출력 이미지 생성
- 최적화가 끝나면
r,t,α,β만 분리해 좌표 변환을 만듦 - 실제 dewarp는 3D 페이지 점들의 dense mesh를
cv2.projectPoints로 투영하고, 그 이미지 좌표를cv2.remap에 전달해 얻음 - 최종 결과는
cv2.adaptiveThreshold와 Pillow를 사용해 bi-level PNG로 저장함
예제 결과와 실행 시간
- GitHub 저장소에는 여러 example images가 포함되어 있음
- 단일 2012 MacBook Pro 실행 기준 통계는 다음과 같음
| 입력 | Spans | Keypoints | Parameters | 최적화 시간 | 총 시간 |
|---|---|---|---|---|---|
boston_cooking_a.jpg |
38 | 554 | 600 | 23.3초 | 24.8초 |
boston_cooking_b.jpg |
38 | 475 | 521 | 18.0초 | 18.8초 |
linguistics_thesis_a.jpg |
20 | 161 | 189 | 5.1초 | 6.1초 |
linguistics_thesis_b.jpg |
7 | 89 | 104 | 4.2초 | 5.3초 |
- 가장 작은 모델도 파라미터가 104개이고, 가장 큰 모델은 600개라서 작은 최적화 문제는 아님
- 최적화 속도는 다른 방법을 시도하거나 컴파일 언어를 사용하면 개선될 수 있음
남은 한계
- 전체 접근은 배경 지식을 조금 읽고, 문제 전체를 최적화 과정의 출력으로 공식화하는 방식임
- 이 방식은 deformable part models와 active appearance models를 떠올리게 하지만, 둘만큼 정교하지는 않음
- Leptonica와 CTM은 수직 왜곡뿐 아니라 수평 왜곡도 모델링하고 보정하려고 시도함
- 이 구현은 수평 왜곡 보정까지 다루지 않음
- 3차 스플라인이 arc-length 파라미터화가 아니기 때문에, 스플라인 기울기가 큰 영역에서는 텍스트가 약간 압축됨
- 프로젝트가 주로 proof-of-concept였기 때문에 이 문제는 더 진행하지 않음
- 최종 코드는 GitHub 저장소에 공개되어 있으며, 자세한 주석 보강은 아직 충분하지 않음