数字图像识别——基于模板匹配

对于数字图像识别,其实有很多方法,例如模板匹配、神经网络、支持向量机等。但是,在这里我们处理的情况比较简单,主要体现在如下两点:(1)场景简单,是白底黑字;(2)具有明显可利用的特点,这个对于数字识别很重要。其实,在matlab中就有一个OCR的函数可以识别数字、标点和英文字母,但是,该算法对于数字比较密集的情况下,识别能力有限。 


现在简介一下我的识别程序处理的场景,如下图测试图像所示,我们处理的是白底黑字、字符大小一样的密集的图像。在这里首先想到的是将数字分割出来,通过观察我们发现具有如下特点:(1)行与行之间的间隔比较明显,可以轻松分割出各个行;(2)列与列之间的间隔可以大于字符之间的间隔;(3)在同一个数字中,每隔3个进位会产生一个比较大的间隔,但是,仍然小于列之间的间隔。



根据上述特点,整理出如下的思路来实现数字识别:

(1)对图像中的数字按行列进行分割,以获取每一个数字;

                        (2)通过构造自适应构造模板进行模板匹配,实现数字图像分类。尽管这个思路是如此的简单,但是,在该场景中,仍然可以获得很好的识别效果。

先看测试图像和识别结果如下:

测试图像:


输出结果: 

Outputs = 



  Columns 1 through 9


    '133.133.133.252'    '40756'    '36.110.219.248'    '80'      '4'      '532'      '2'    '420'     '2'
    '133.133.133.252'    '54147'    '36.110.219.248'    '80'      '13'     '1888'    '7'    '1156'    '6'
    '127.0.0.1'            '33293'    '127.0.0.1'          '6477'    '2'      '132'      '1'    '76'      '1'


  Columns 10 through 11


    '112'    '1.025877000'
    '732'    '1.030972000'
    '56'     '2.002403000'

代码如下:

(1)主程序部分如下(其中Font_10.png在后面):

close all;
clear all;
clc;
filepath = mfilename('fullpath');
filename = mfilename();
jarfilepath = filepath(1:end-length(filename));
javaaddpath(fullfile(jarfilepath,'SimpleCaptureScreen.jar'));
ScreenCapture = javaObjectEDT('com.huawei.ScreenCapture.SimpleCaptureScreen');
ScreenCapture.MainCaptureScreen;
Img = imread('MyCaptureScreen.png');
TemplateImg = imread('Font_10.png'); 
Font = 10; 
Scale = 4; % 原始图像放大倍数
% 创建模板
[TemplateCell,Hight,TemplateSize] = FontTemplate(TemplateImg,Font,Scale);
Img = imresize(Img,Scale); % 进行尺度变换
% 要对图像进行分区域
BinaryImg = (rgb2gray(Img) < 110);
FindSegmentColumn = sum(BinaryImg,1);
FindSegmentRow = sum(BinaryImg,2);
PositionsColumn = [];
PositionsRow = [];
% 加第一列/行
PositionsColumn = [max(1,find(FindSegmentColumn,1,'first')-5),PositionsColumn];
PositionsRow = [max(1,find(FindSegmentRow,1,'first')-5),PositionsRow];
% 获取数字的最大宽度
MaxCharactor = 0;
iter = find(FindSegmentColumn,1,'first');
while iter <= find(FindSegmentColumn,1,'last')
    StarIndex = iter;
    while FindSegmentColumn(iter)
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    if iter - 1 - StarIndex > MaxCharactor
        MaxCharactor = iter - 1 - StarIndex;
    end
    while FindSegmentColumn(iter) == 0
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
end
% 对列进行分割
iter = find(FindSegmentColumn,1,'first');
while iter <= find(FindSegmentColumn,1,'last')
    while FindSegmentColumn(iter)
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    StarIndex = iter;
    while FindSegmentColumn(iter) == 0
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    if (iter-1 - StarIndex) > 2*MaxCharactor
        PositionsColumn = [PositionsColumn,ceil((iter-1 - StarIndex)/2) + StarIndex];
    end
end
% 对行进行分割
iter = find(FindSegmentRow,1,'first');
while iter <= find(FindSegmentRow,1,'last')
    while FindSegmentRow(iter)
        iter = iter + 1;
        if iter > find(FindSegmentRow,1,'last')
            break;
        end
    end
    StarIndex = iter;
    while FindSegmentRow(iter) == 0
        iter = iter + 1;
        if iter > find(FindSegmentRow,1,'last')
            break;
        end
    end
    if (iter-1 - StarIndex) > 0
        PositionsRow= [PositionsRow,ceil((iter-1 - StarIndex)/2) + StarIndex];
    end
end
% 加最后一列/行
PositionsColumn = [PositionsColumn,min(find(FindSegmentColumn,1,'last')+5,length(FindSegmentColumn))];
PositionsRow = [PositionsRow,min(find(FindSegmentRow,1,'last')+5,length(FindSegmentRow))];
% 对分割出来的每一组数字进行识别
BinaryImg = (rgb2gray(Img) < 100);
% % 更新二值图像
Outputs = {length(PositionsRow) - 1,length(PositionsColumn) - 1};
for iterrow  = 2:length(PositionsRow)
    for itercol = 2:length(PositionsColumn)
        % 获取字段图像区域
        Temp = BinaryImg(PositionsRow(iterrow-1):PositionsRow(iterrow),:);
        %根据实际的字体调整,以匹配模板:假设一行只包含一种大小
        TempFindSegmentColumn = sum(Temp,1);
        subFindSegmentColumn = TempFindSegmentColumn(PositionsColumn(itercol-1):PositionsColumn(itercol));        
        % 分离每一个数字和小数点
        iterPosition = find(subFindSegmentColumn,1,'first');  
        subPositionsColumn = [];
        subPositionsColumn = [subPositionsColumn,PositionsColumn(itercol-1)];%添加第一列             
        while iterPosition <= find(subFindSegmentColumn,1,'last')
            while subFindSegmentColumn(iterPosition)
                iterPosition = iterPosition + 1;
                if iterPosition > find(subFindSegmentColumn,1,'last')
                    break;
                end
            end
            StarIndex = iterPosition;
            while subFindSegmentColumn(iterPosition) == 0
                iterPosition = iterPosition + 1;
                if iterPosition > find(subFindSegmentColumn,1,'last')
                    break;
                end
            end  
            % 注意获取的是数据段中的相对位置,所以要加PositionColumn(itercol-1)
            subPositionsColumn = [subPositionsColumn,PositionsColumn(itercol-1) + ceil((iterPosition-1 - StarIndex)/2) + StarIndex];
        end %while iterPosition
        % 字段识别结果
        ResultTemp = [];
        for subitercol = 2:length(subPositionsColumn)
            DigitalColumn = TempFindSegmentColumn(subPositionsColumn(subitercol-1):subPositionsColumn(subitercol));  % 这里是导致分离出的数字偏离的根因
            DigitalRow = FindSegmentRow(PositionsRow(iterrow-1):PositionsRow(iterrow)); 
            StartRowIndex = PositionsRow(iterrow-1) + find(DigitalRow,1,'first');
            EndRowIndex = PositionsRow(iterrow-1) + find(DigitalRow,1,'last'); 
            StarIndex = subPositionsColumn(subitercol-1)+find(DigitalColumn,1,'first'); 
            EndIndex = subPositionsColumn(subitercol-1)+find(DigitalColumn,1,'last'); 
            DigitalHight = EndIndex - StarIndex + 1; %可能会用到
            subsubImg = BinaryImg(StartRowIndex:EndRowIndex,StarIndex:EndIndex);
            subsubImg = CreateTemplate(subsubImg,TemplateSize); 
            Index = 1; 
            Dist = 1e10; %模板之间的最大距离
            [Irow,Icol] = find(subsubImg); 
            for iter = 1:length(TemplateCell)
                [Trow,Tcol] = find(TemplateCell{iter});                
                NewDist = Distance(Trow,Tcol,Irow,Icol); 
                if NewDist < Dist 
                    Index = iter; 
                    Dist = NewDist; 
                end 
            end 
            if Index == 11
                ResultTemp = [ResultTemp,'.']; 
            else 
                ResultTemp = [ResultTemp,num2str(Index-1)]; 
            end
        end
        Outputs(iterrow-1,itercol-1) = {ResultTemp};
    end%for itercol
end%for iterrow 
Outputs
figure;
imshow(Img);
title('测试图像'); 
创建匹配模板: 

function Template = CreateTemplate(TemplateDigital,TemplateSize)
% Inputs:
% TemplateDigital: 截取的模板图像
% TemplateSize: 模板的大小
% Outputs:
% Template: 生成的数字模板
% Author: HSW
% Date: 2015/11/22
%
[nrow,ncol] = size(TemplateDigital); 
drow = max(1,floor((TemplateSize - nrow)/2));
dcol = max(1,floor((TemplateSize - ncol)/2));
Template = zeros(TemplateSize);
Template(drow:drow+nrow-1,dcol:dcol+ncol-1) = TemplateDigital; 
Template = bwmorph(Template,'bridge',Inf);
Template = bwmorph(Template,'skel',Inf);
Template = bwmorph(Template,'bridge',Inf);
Template = imresize(Template,[TemplateSize,TemplateSize]); 
end %function
 
 计算距离: 

function NewDist = Distance(Trow,Tcol,Irow,Icol)
% Inputs: 
%
%
% Outputs: 
% NewDist: 
% Author: HSW
% Date: 2015-11-22
NewDist1 = 0; 
for TIter = 1:length(Trow)
    Min = min((Trow(TIter) - Irow).^2 + (Tcol(TIter) - Icol).^2);
    NewDist1 = NewDist1 + Min; 
end %for
NewDist1 = NewDist1/length(Trow); 
NewDist2 = 0; 
for IIter = 1:length(Irow)
    Min = min((Irow(IIter) - Trow).^2 + (Icol(IIter) - Tcol).^2); 
    NewDist2 = NewDist2 + Min; 
end 
NewDist2 = NewDist2/length(Irow); 
NewDist = max(NewDist1,NewDist2); 

end
创建字体模板:
function [TemplateCell,Hight,TemplateSize] = FontTemplate(TemplateImg,Font,Scale)
% Inputs:
% TemplateImg: 模板数字图像
% Font: 模板数字图像字体
% Outputs:
% FontTemplate: 模板数字
% Author: HSW
% Date: 2015/11/22
% 设置默认参数
% if ~(exist(TemplateImg,'var'))
%     TemplateImg = imread('Font_10.png'); % 默认模板数字图像
% end
% 
% if ~(exist(Font,'var'))
%     Font = 10; % 默认字体为 微软雅黑-10
% end
% 
% if ~(exist(Scale,'var'))
%     Scale = 2; % 默认图像放大倍数
% end
TemplateImg = imresize(TemplateImg,Scale); % 进行尺度变换
BinaryTemplateImg = (rgb2gray(TemplateImg) < 110);
% 获得Template中的每一个字符,并形成模板
FindSegmentColumn = sum(BinaryTemplateImg,1);
FindSegmentRow = sum(BinaryTemplateImg,2);
PositionsColumn = [];
% 获得模板数字的高
FirstRowPosition = max(1,find(FindSegmentRow,1,'first') - 4);
LastRowPosition = min(length(FindSegmentRow),find(FindSegmentRow,1,'last')+4);
% 获取数字的最大宽度
MaxCharactor = 0;
iter = find(FindSegmentColumn,1,'first');
while iter <= find(FindSegmentColumn,1,'last')
    StarIndex = iter;
    while FindSegmentColumn(iter)
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    if iter - 1 - StarIndex > MaxCharactor
        MaxCharactor = iter - 1 - StarIndex;
    end
    while FindSegmentColumn(iter) == 0
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
end

% 对列进行分割
PositionsColumn = [max(1,find(FindSegmentColumn,1,'first')-5),PositionsColumn];
iter = find(FindSegmentColumn,1,'first');
while iter <= find(FindSegmentColumn,1,'last')
    while FindSegmentColumn(iter)
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    StarIndex = iter;
    while FindSegmentColumn(iter) == 0
        iter = iter + 1;
        if iter > find(FindSegmentColumn,1,'last')
            break;
        end
    end
    if (iter-1 - StarIndex) > 1.05*MaxCharactor
        PositionsColumn = [PositionsColumn,ceil((iter-1 - StarIndex)/2) + StarIndex];
    end
end
PositionsColumn = [PositionsColumn,min(find(FindSegmentColumn,1,'last')+5,length(FindSegmentColumn))];
% TemplateCell{1} = FirstRowPosition;
% TemplateCell{2} = LastRowPosition;
Hight = LastRowPosition - FirstRowPosition + 1; 

% 构造模板
TemplateSize = max(LastRowPosition-FirstRowPosition, MaxCharactor + 7); %模板的大小
for iter = 2:length(PositionsColumn) %十个数字
    Temp = FindSegmentColumn(PositionsColumn(iter-1):PositionsColumn(iter)); 
    StarIndex = PositionsColumn(iter-1)+find(Temp,1,'first');
    EndIndex = PositionsColumn(iter-1)+find(Temp,1,'last'); 
    TemplateDigital = BinaryTemplateImg(FirstRowPosition:LastRowPosition,StarIndex:EndIndex);%
    % 将数字复制到Template的中心
    Template = CreateTemplate(TemplateDigital,TemplateSize);
    TemplateCell(iter-1) = {Template};
end %for iter

end %function


(2)构造自适应模板的图像Font_10.png如下: 

(3) 在matlab中实现基于java的截屏工具:

https://download.csdn.net/download/hit1524468/10303366,按照如下方式放置,即可运行使用

数字图像识别——基于模板匹配_第1张图片


你可能感兴趣的:(matlab,图像处理,数字识别)