-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalignDocument.m
125 lines (108 loc) · 4.38 KB
/
alignDocument.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
function [aligned_img] = alignDocument(img)
% Align a text image with skew [-45, 45] degrees
% ----------------------------------------------
%
% Brief:
% This function takes an input image 'img' and performs
% deskewing to align the text image. The function returns 'aligned_img',
% which is the fully aligned image.
%
% The alignment process involves finding the approximate rotation angle
% using the FFT, rotating the image by the estimated angle, and then
% iteratively refining the rotation angle to find the exact skew angle
%
% Input:
% - img: Input image of the text
%
% Output:
% - aligned_img: Aligned text image
%
% Example:
% % Load and align a text image
% img = imread('text1.png');
% aligned_img = alignDocument(img);
% imshow(aligned_img);
%
% See also: findRotationAngle, rotateImage, cropBlackPadding
interp_method = "bilinear";
% Find approximate rotation angle using FFT
angle_approx = findRotationAngle(img);
fprintf("An approximation skew angle is %.4f\n", angle_approx);
% Rotate the image by that angle
img = rotateImage(img, angle_approx, interp_method);
fprintf("Rotation of %.4f was performed\n", angle_approx);
figure
imshow(img)
title("IMAGE AFTER INITIAL ROTATION")
% Implement Projection Profiling Method to find exact rotaton angle
% -----------------------------------------------------------------
% Determine whether the approximate deskew angle is bigger or smaller
% than the actual rotation angle
% -------------------------------------------------------------------
% For that purpose, check in which direction the standard deviation
% of the sum of the projections increases
theta = -0.1;
% Case 1: Counter-clockwise rotation check
rotated_img = rotateImage(img, abs(theta), interp_method);
rotated_img_grayscale = im2gray(rotated_img);
std_counter_clockwise = std(sum(rotated_img_grayscale, 2));
% Case 2: Clockwise rotation check
rotated_img = rotateImage(img, theta, interp_method);
rotated_img_grayscale = im2gray(rotated_img);
std_clockwise = std(sum(rotated_img_grayscale, 2));
if std_counter_clockwise > std_clockwise
% Image still needs to be rotated in counter-clockwise direction
step_size = 0.5;
theta = step_size;
elseif std_counter_clockwise < std_clockwise
% Image still needs to be rotated in clockwise direction
step_size = -0.5;
theta = step_size;
else
% Image is aligned perfectly
aligned_img = rotated_img;
return;
end
% To make the search more efficient, new angles are calculated until
% the first one that has standard deviation of projections smaller than
% the previous
% Loop forward to find maximum standard deviation
prev_std = max(std_counter_clockwise, std_clockwise);
while true
% Rotate the image
rotated_test = rotateImage(rotated_img, theta, interp_method);
rotated_test = cropBlackPadding(rotated_test);
std_test = std(sum(im2gray(rotated_test), 2));
if std_test > prev_std
prev_std = std_test;
theta = theta + step_size;
else
% Undo the last iteration to get the theta for maximum STD
theta = theta - step_size; % undo the previous addition
step_size = step_size / 5;
break;
end
end
% Rotate the image by the angle found at this stage
rotated_img = cropBlackPadding(rotateImage(img, theta, interp_method));
prev_std = std(sum(im2gray(rotated_img), 2));
% Loop backward to find more accurate result
theta = -step_size;
while true
% Rotate the image
rotated_test = rotateImage(rotated_img, theta, interp_method);
rotated_test = cropBlackPadding(rotated_test);
std_test = std(sum(im2gray(rotated_test), 2));
if std_test > prev_std
prev_std = std_test;
theta = theta - step_size;
else
% Undo the last iteration to get the theta for maximum STD
theta = theta + step_size;
break;
end
end
% Rotate the image by the refined angle to deskew it and crop unnecessary
% padding
aligned_img = cropBlackPadding(rotateImage(rotated_img, theta, interp_method));
end