对于数字图像识别,其实有很多方法,例如模板匹配、神经网络、支持向量机等。但是,在这里我们处理的情况比较简单,主要体现在如下两点:(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
(3) 在matlab中实现基于java的截屏工具:
https://download.csdn.net/download/hit1524468/10303366,按照如下方式放置,即可运行使用