기울어진 스캔문서 이미지(칼라)가 아래와 같이 있을 경우, 문자인식등을 위해서는 기울기 보정을 해주어야 한다.
이번 기울기 보정의 흐름은 아래와 같다.
그레이 변환 ▶ B/W 변환 ▶ 문자를 흰색으로 변환 ▶ 문자를 두텁게 ▶ 라인을 검출 ▶ 라인의 기울기 평균
1. 그레이 변환, B/W 변환
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
cv::threshold(image, image, 100, 255, cv::THRESH_BINARY);
노이즈가 없는 샘플을 사용했기 때문에 위와 같이 간단한 Threshold함수를 사용하였다. 질이 나쁜 이미지를 사용한다면 노이즈제거, otsu 나 adaptive threshold 함수등을 사용해야 할 것 이다.
2. 문자를 흰색으로 변환
cv::bitwise_not(image, image);
이미지처리는 흰색(255)를 대상으로 하기때문에 문자를 흰색(바탕을 검은색)으로 변환해 주어야 한다.
3. 문자를 두텁게
cv::dilate(image, image, cv::Mat(), cv::Point(-1, -1), 5);
문자를 이용한 직선라인을 검출하기 위해서는 되도록이면 문자를 두텁게 해주어야 하기 때문에 dilate 함수를 이용하여 5번 확장하도록 한다.
4. 라인을 검출
cv::Size size = image.size();
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(image, lines, 1, CV_PI / 180, 100, size.width / 2.f, 20);
라인 검출은 The Probabilistic Hough Line Transform 를 사용한다.
라인의 길이가 이미지 넓이의 절반 이상(size.width / 2.f)인 것을 대상으로 하고 라인이 도중에 끊어진 경우에는 라인간의 갭이 20 이하인 경우에는 하나의 라인이 되도록 연결하도록 한다.
5. 라인의 기울기 평균
double angle = 0.;
unsigned line_count = lines.size();
for (unsigned i = 0; i < line_count; ++i)
{
angle += atan2((double)lines[i][3] - lines[i][1], (double)lines[i][2] - lines[i][0]);
}
// 래디안각도
angle /= line_count;
// 래디안을 각도로 변환
angle = angle * 180 / CV_PI;
검출된 line 은 왼쪽좌표 x, y = ([0], [1]), 오른쪽좌표 x,y = ([2], [3]) 이므로,
L1 = [3] - [1] L2 = [2] - [0] 이 되고 a 각도 = atan(L1/L2) 로 알 수 있다.
- atan = gives angle value between -90 and 90
- atan2 = gives angle value between -180 and 180
모든 각도의 평균은 = 2.6922 의 결과가 나왔다.
결과 각도로 보면 좌상에서 우하로 이어진 라인임을 알 수 있다.
나중에 OpenCV를 이용한 회전각도 조정을 하겠지만
ImageJ 회전 교정을(반대방향이므로 마이너스) 해 보면 아래와 같은 결과가 된다.
※ 표준적인 회전은 반시계방향이 + 이지만, ImageJ의 경우는 반시계 방향 회전이 - 이다.
'opencv' 카테고리의 다른 글
이미지 회전 (0) | 2023.11.27 |
---|---|
스캔문서의 기울기 알아보기 - 2 (0) | 2023.11.27 |
(opencv) 이미지 저장형태, 액서스 (1) | 2023.11.25 |
(opencv) Rectangle 간의 조작에 관해 (1) | 2023.11.23 |
(opencv) pixel access time (0) | 2023.08.09 |