opencv

스캔문서의 기울기 알아보기

꼰대코더 2023. 11. 26. 22:55

기울어진 스캔문서 이미지(칼라)가 아래와 같이 있을 경우, 문자인식등을 위해서는 기울기 보정을 해주어야 한다.

이번 기울기 보정의 흐름은 아래와 같다.

그레이 변환 ▶ 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) Mat 의 기초  (0) 2023.08.05