文档图像倾斜角检测及校正(三)(Matlab)

文档图像倾斜角检测及校正(三)

996.icu LICENSE

  • 斜率空间投票原理
  • Matlab程序

阅读之前注意:

Hi,你好,我是Cooper Liu,欢迎来到我写的“文档图像校正”系列博客。基于三种原理,我写了四个实验性的Matlab验证程序,以及两个文档校正Matlab程序。在这里你将能够获取所有的源代码以及测试图片,完全可以在你自己的Matlab上跑这些程序。

如果你是学生,请注意不要抄袭,课程设计作业的话,这种程序仅仅只能让你得到80%左右的成绩。
如果你是工作人士或者只是感兴趣的极客,Okay,我想这些程序对于理解原理是如何应用为程序的已经足够 。

最后,请勿将这些资源用于商业用途(如你所见,这些程序都非常的初级)或者是谋取个人利益,知识在传播的过程中能展现更大的价值-

本文阅读建议用时:42min
本文阅读结构如下表:

项目下属项目测试用例数量
斜率空间投票原理0
Matlab程序2

斜率空间投票原理1

斜率空间投票指的是,在文档图像的某一个区域中,如果我们知道有一个点 ( x 0 , y 0 ) (x_0,y_0 ) (x0,y0)是直线上的点,那我们将该点所在的直线斜率定为m,则坐标和斜率的关系可表示为 y 0 = m ( x − x 0 ) y_0=m(x-x_0) y0=m(xx0)。由此图像区域中的每个目标像素 ( x ′ , y ′ ) (x',y') (x,y) ( x 0 , y 0 ) (x_0,y_0 ) (x0,y0)点之间连线的斜率 m ′ m' m可表示为 m ′ = ( y ′ − y 0 ) / ( x ′ − x 0 ) m'=(y'-y_0)/(x'-x_0) m=(yy0)/(xx0)

我们将斜率值映射到一组累加器上,每求出一个斜率值,对应的累加器加一。因为同一直线上的点求得的斜率相同,所以累加器会出现局部最大值,该值所对应的斜率即是所求直线的斜率,倾斜角也能相应的求出。

值得注意的是,当 x ′ = x 0 x'=x_0 x=x0时, m ′ m' m为无穷大。为了避免这一情况,当 x ′ = x 0 x'=x_0 x=x0时,我们令 m ′ = 2 m'=2 m=2,而当 m ′ > 1 m'>1 m>1 m ′ < 1 m'<1 m<1时,我们采用公式 m ′ ′ = 1 / m ′ − 2 m''=1/m'-2 m=1/m2的计算值代替 m ′ m' m。这样一来, m ′ m' m的范围即被限定在(-1,3)的区间内。

Matlab程序

基于以上原理,我编写了Matlab程序来进行实验,源代码可以参考angleDetection3.m文件和angleDetection4.m文件。测试图片为line5.bmp。2
测试图片可以从这里获取,链接:https://pan.baidu.com/s/1dGmmGjn 密码:okt3

我编写了两个版本的Matlab程序,其中版本一(angleDetection3.m文件)的思想是把斜率区间尽可能的细分,比如分成10000份,再计算对应10000个累加器的最大值,从而反推出斜率。而版本二(angleDetection4.m文件)的思想则是先把斜率空间分为10个子区间,求出累加器的最大值,把最大值对应的子区间再分为10个子区间,如此迭代,直至区间宽度小于我们所控制的迭代精度。

以下是版本一的实验结果:
实验结果
时间

以下是版本二的实验结果:
实验结果
时间

如果您不想打开新的页面查看matlab源代码,也可以直接参考以下代码:
版本一(angleDetection3.m文件):

%%本版基于斜率空间投票原理 
%%2018.01.20_14:09 by Cooper Liu
%%Questions? Contact me: angelpoint@foxmail.com
clear;clc; %清空之前的变量
I=imread('line5.bmp'); %读取图像
level=graythresh(I); %使用最大类间方差法找到图片的一个合适的阈值
bw=im2bw(I,level); %根据阈值,使用im2bw函数将灰度图像转换为二值图像
figure(1);imshow(bw);
[m,n]=size(bw); %获取尺寸
flag=0;
tic; %计时开始
 for i=1:m
    for j=1:n
        if bw(i,j)==0
            if flag==0
                x0=i;y0=j; %获取第一个点
                flag=1;
            end
        end
    end
 end
range=10000; %range越大对角度分得更细,计算量更大
low=-1;
high=3;

a=zeros(range,1);
 for i=1:m
   for j=1:n
        if bw(i,j)==0
            if i==x0
                k=2;
                area=floor((k-(-1))/4*range); %向下取整
                a(area+1,1)=a(area+1,1)+1; %区间计数
            else
                k=(j-y0)/(i-x0);
                k2=k;
                if  k>1 || k<-1
                    k2=2-1/k; %转换斜率,保证斜率范围(-1, 3)
                end
                area=floor((k2-(-1))/4*range); %向下取整
                a(area+1,1)=a(area+1,1)+1;
            end 
        end
    end
 end
 toc %获取时间
[s_i,index] = sort(a,'descend'); %降序排序并获取原来序列的序号至index
max=index(1);
tmp=(-1)+max/range*4;
if tmp>1
    k=1/(2-tmp); %还原原来的斜率
else
    k=tmp;
end
angle=atan(k); %用atan求出来的角度在-pi/2到+pi/2之间
angle=angle*180/pi

rot=90-angle;
pic=imrotate(I,rot,'crop'); %旋转图像
figure(2);imshow(pic);

版本二(angleDetection4.m文件):

%%本版基于斜率空间投票原理,改进自angleDetection3.m 
%%2018.01.20_15:41 by Cooper Liu
%%Questions? Contact me: angelpoint@foxmail.com
clear;clc; %清空之前的变量
I=imread('line5.bmp'); %读取图像
level=graythresh(I); %使用最大类间方差法找到图片的一个合适的阈值
bw=im2bw(I,level); %根据阈值,使用im2bw函数将灰度图像转换为二值图像时
figure(1);imshow(bw);
[m,n]=size(bw); %获取尺寸
flag=0;

 for i=1:m
    for j=1:n
        if bw(i,j)==0
            if flag==0
                x0=i;y0=j;
                flag=1;
            end
        end
    end
 end
range=10; %整个斜率区间分为10个子区间
low=-1;
high=3;
tmpLow=low;
tmpHigh=high;
max=0;
areaAddtion=0; 
tic; %开始计时
while high-low>0.0001
a=zeros(range,1);
    for i=1:m
        for j=1:n
            if bw(i,j)==0
                if i==x0 %如果x坐标与x0相同
                    k=2; %则固定k为2
                    if k>=low && k<=high
                        area=floor((k-low)/(high-low)*range); %向下取整
                        if area==range %如果等于最后一个区间
                            area=area-1; %请考虑到后面区间计数的area+1
                        end
                        a(area+1,1)=a(area+1,1)+1; %区间计数
                    end
                else     %如果x坐标与x0不同
                    k=(j-y0)/(i-x0); %则计算斜率
                    k2=k;
                    if  k>1 || k<-1
                        k2=2-1/k;
                    end
                    if k2>=low && k2<=high
                        area=floor((k2-low)/(high-low)*range); %向下取整
                        if area==range
                            area=area-1;
                        end
                        a(area+1,1)=a(area+1,1)+1;
                    end
                end 
            end
        end
    end
[s_i,index] = sort(a,'descend');
max = index(1);
tmpLow = low;
tmpHigh = high;
if max>=2 && max<=9
    areaAddition=0; %根据需要可以更改子区间的范围
else
    areaAddtion=0;
end
low = tmpLow + (max - 1 - areaAddition)/range*(tmpHigh - tmpLow);
high = tmpLow + (max + areaAddtion)/range*(tmpHigh - tmpLow);
end

toc %获取计时时间

tmp=tmpLow+max/range*(tmpHigh-tmpLow);
if tmp>1
    k=1/(2-tmp);
else
    k=tmp;
end
angle=atan(k); %用atan求出来的角度在-pi/2到+pi/2之间
angle=angle*180/pi

rot=90-angle;
pic=imrotate(I,rot,'crop'); %旋转图像
figure(2);imshow(pic);

如果本文有帮助到你,不如请我一罐可乐吧 🎏
在这里插入图片描述


  1. 参考文献:[1] 荆雷,张欣,郭金鑫.基于版面的拍照文档图像倾斜校正.激光与红外[J].2010,第10期 ↩︎

  2. 同时感谢愿意在网络上分享自己想法的各位博主。 ↩︎

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页