В данном посте поделюсь итеративным методом определения угла наклона сканированного текста.
Суть метода заключается в следующем: постепенно меняя угол наклона — считаем некоторую характеристику-функцию от изображения (о ней чуть дальше). При каком угле наклона получим максимум — значит это и есть оптимальный угол наклона.
Теперь о том, что считать, для этого внимательно взглянем на то как выглядит текст на сканированном документе. Если представим изображение только в виде черных и белых пикселей и потом спроецируем их все на ось X, то в местах где есть строчки гистограмма будет выдавать пики по черным пикселям, а где междустрочный интервал — по белым пикселям. Пики будут максимально выраженными при правильном угле. Но мы хотим получить наиболее простой алгоритм, поэтому будет считать только кол-во черных и белых пикселей при проекции на ось X. Т.к. строки текста парралельны друг другу, то при лучшем угле кол-во белых пикселей будет максимальным, а кол-во черных минимальным. Этим и воспользуемся:
import numpy as np import cv2 def get_angle(img): # сперва переведём изображение из RGB в чёрно серый # значения пикселей будут от 0 до 255 img_gray = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) # а теперь из серых тонов, сделаем изображение бинарным th_box = int(img_gray.shape[0] * 0.007) * 2 + 1 img_bin_ = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, th_box, th_box) img_bin = img_bin_.copy() num_rows, num_cols = img_bin.shape[:2] best_zero, best_angle = None, 0 # итеративно поворачиваем изображение на пол градуса for my_angle in range(-20, 21, 1): rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows /2 ), my_angle/2, 1) img_rotation = cv2.warpAffine(img_bin, rotation_matrix, (num_cols*2, num_rows*2), borderMode=cv2.BORDER_CONSTANT, borderValue=255) img_01 = np.where(img_rotation > 127, 0, 1) sum_y = np.sum(img_01, axis=1) th_ = int(img_bin_.shape[0]*0.005) sum_y = np.where(sum_y < th_, 0, sum_y) num_zeros = sum_y.shape[0] - np.count_nonzero(sum_y) if best_zero is None: best_zero = num_zeros best_angle = my_angle # лучший поворот запоминаем if num_zeros > best_zero: best_zero = num_zeros best_angle = my_angle return best_angle * 0.5 img = cv2.imread('singapore_01.jpg') best_angle = get_angle(img) print(best_angle) cv2.imshow('Result', img) cv2.waitKey()