方法一:直接寻找表格边框的倾斜角
如果表格中的水平边框能够很好经过预处理得到,那么通过定位这一边框。得到边框的起始点和斜率,就能得到相应的角度。通过角度就能够实现校正。
难点在于如何得到边框的起始点。起始点的特点是起点的行坐标最小,终点的列坐标最小。
方法二:采用熟悉的hough变换
倾斜校正前处理和后处理都是一致,区别在于怎么得到倾斜的角度,而倾斜的角度是通过倾斜的直线得到。关键就在于检测直线的方法。hough变换检测直线的原理其他地方有详细的介绍,这里结合matlab的函数做一个梳理。这里要用的三个函数是hough,houghpeaks,houghlines。
图像经hough后得到的是一个参数空间的矩阵,矩阵的每一个值是对应坐标处累加器的值,参数空间的划分在得到的另外两个向量theta,rho中体现。
在得到hough变换的矩阵后,houghpeaks就来检测矩阵中符合要求有可能是直线的参数点,当然阈值和检测的个数是可以自己设定的。这时得到的是峰值的横纵坐标。
得到峰值后就要确定每个峰值所确定的线段,houghlines就是用来完成这一工作的。houghlines返回的是关于一个线段的所有信息-两个点的横纵坐标和的值。
后续的工作就是遍历所有线段并显示出来,找到其中最长的一条。用这一条确定斜率,由斜率得到角度,然后进行旋转就可。
方法三:radon变换
Radon 变换检测倾斜角度的原理是:对倾斜的表格图像在一定的倾斜角度(0:179)范围内进行,然后查找使投影最大的那个角度。记录这一角度,就能够得到倾斜的角度。
%hough变换倾斜校正: clc; clear all; [fn pn fi]=uigetfile('*.*','choose apicture'); Img=imread([pn fn]); % Img=imrotate(Img,5,'bilinear'); I =rgb2gray(Img); figure;imhist(I); bw = ~improve_hist(I); figure; imshow(bw); BW=bw; str=strel('line',20,0); BW=imerode(BW,str); str=strel('line',80,0); BW=imdilate(BW,str); % BW=edge(BW,'canny'); figure; imshow(BW);title('canny 边界图像'); [H,T,R]=hough(BW); figure,imshow(H,[],'XData',T,'YData',R,'InitialMagnification','fit'); xlabel('\theta'),ylabel('\rho'); axis on, axis normal,hold on; P=houghpeaks(H,4,'threshold',ceil(0.3*max(H(:)))); x=T(P(:,2)); y = R(P(:,1)); plot(x,y,'s','color','white'); lines=houghlines(BW,T,R,P,'FillGap',50,'MinLength',7); figure,imshow(BW),title('直线标识图像'); max_len = 0; hold on; for k=1:length(lines) xy=[lines(k).point1;lines(k).point2]; %标出线段 plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');%[260,1;348,142]的第一列x值,第二列y值。绿色画出直线 %标出线段的起始和终端点 plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');%线段的起点--黄色 plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');%线段的终点--红色 len=norm(lines(k).point1-lines(k).point2);%计算矩阵的范数。 Len(k)=len; if (len>max_len) max_len=len; xy_long=xy; end end % 强调最长的部分 plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','blue');%最长的线段--蓝色。 [L1 Index1]=max(Len(:)); % 最长线段的起始和终止点 x1=[lines(Index1).point1(1)lines(Index1).point2(1)]; y1=[lines(Index1).point1(2)lines(Index1).point2(2)]; % 求得线段的斜率 K1=-(lines(Index1).point1(2)-lines(Index1).point2(2))/... (lines(Index1).point1(1)-lines(Index1).point2(1)) angle=atan(K1)*180/pi A = imrotate(I,-angle,'bilinear','loose');%imrate 是逆时针的所以取一个负号 figure, subplot(121);imshow(I); subplot(122);imshow(A);
radon变换倾斜校正: clc; clear all; close all; [fn pn fi]=uigetfile('*.*','choose apicture'); Img=imread([pn fn]); imshow(Img);title('Original image'); I = rgb2gray(Img); I=improve_hist(I); bw=edge(I,'canny'); theta=1:179; [R,xp]=radon(bw,theta); [I0,J]=find(R>=max(R(:)));%J记录了倾斜角 if J<=90 qingxiejiao=J; else qingxiejiao=J-180; end I1=imrotate(Img,-qingxiejiao,'bilinear','crop'); subplot(1,2,1),imshow(Img);title('Originalimage'); subplot(1,2,2),imshow(I1);title('correct image');
function [ b1 ] = improve_hist( f1 ) I=f1; [m,n]=size(I); I=double(I); avg=mean(I(:)); mi=min(I(:)); p=0.45; for i=1:m for j=1:n if I(i,j)>avg I(i,j)=255; else I(i,j)=(255-abs((((I(i,j)-avg)^p)*255)/(avg-mi)^p)); end end end mask=fspecial('log'); g=imfilter(I,mask,'replicate'); g=I-g; g=im2uint8(g); [~,re]=binary_iterate(g); b1=re; end
function [t b1 ] = binary_iterate( f1 ) % 用迭代的方法对图像进行二值化 t=mean(f1(:)); is_done=false; count=0; while ~is_done r1=f1(f1<=t); r2=f1(f1>t); temp1=mean(r1(:)); if isnan(temp1); temp1=0; end temp2=mean(r2(:)); if isnan(temp2) temp2=0; end t_new=(temp1+temp2)/2; is_done=abs(t_new-t)<1; t=t_new; count=count+1; if count>=1000 Error='Error:Cannot find the ideal threshold.' Return end end b1=im2bw(mat2gray(f1),t/256); end不能保证对其他图像也能取到好效果。