本文章由wikiwen撰写,转载请注明出处。
文章链接:http://blog.csdn.net/kk55guang2/article/details/78475414
作者:wikiwen
在数字图像处理中,图像分割是很关键的一步,当图像质量较好,光照很均匀的时候只需用全局阈值的方法就能很完美地完成图像分割任务,但是有些时候会遇到光照不均匀的现象,这个时候就需要用一些技巧才能达到比较好的分割效果,本文要介绍的是一种通过分块阈值进行分割的方法。
在进入正题之前,我们先看一个实例,下面图1和图3为做硬币面额识别拍摄的,可以看到,由于硬币表面的反光以及打光角度的原因,图片存在严重的光照不均现象。
如果对两幅图像直接进行全局阈值可以得到图2和图4的结果,可以看到分割的效果很差,比如第一幅,右上角的光照要强一些,而且右上角的硬币存在一定的反光,灰度值整体偏高,导致最后分割效果很差。第二幅则是左边部分光照太强,左边的硬币分割效果很差。
本文将用分块阈值的方法解决这一问题。
通过将图像分割成若干块,分别进行阈值分割,可以在一定程度上解决光照或反射造成的不均匀影响。选择的块要足够小,以便每个块的光照都近似均匀的,这样自动阈值时,在高灰度区域就会用高阈值分割,在低灰度区域就会用低阈值分割。
图5为分块结果,示例中分块与硬币大小相当,分完块之后就可以按块进行全局阈值法(这里采用常用的最大类间方差法,otsu法)处理了,但是需要注意的是有的块中只有背景,这个时候需要进行判断,排除对这种块的处理。
对于这种块的判断,笔者尝试过用otsu方法中提到的可分性度量:
%功能:对一副图像进行分块阈值,可解决光照不均分割不足的问题
%通过判断类间灰度差以排除纯背景或纯物体的干扰
%作者:wikiwen
%日期:2017/10/24
%平台:matlab R2014
clc,clear;
close all;
rn=5;cn=5;
I = rgb2gray(imread('d.jpg'));
[R , C]=size(I);%分别返回行和列数
rblk=R/rn;cblk=C/cn;%小块的行数和列数
x = 0:cblk:C;
y = 0:rblk:R;
M = meshgrid(x,y); %产生网格
N = meshgrid(y,x); %产生网格
imshow(I);
hold on
plot(x,N,'r'); %画出水平横线
plot(M,y,'r'); %画出垂直竖线
T = zeros(rn,cn);
dif = zeros(rn,cn);
J = false(R,C);%初始化二值图
X = uint8(zeros(rblk,cblk));
%分块阈值,并判断类间灰度差以排除纯背景或纯物体的干扰
for r=1:rn
for c=1:cn
r0=rblk*(r-1)+1;r1=rblk*r;
c0=cblk*(c-1)+1;c1=cblk*c;
X = I(r0:r1,c0:c1);
T(r,c) = graythresh(X);
[h,~] = histcounts(X,0:255);
T_int =uint8(T(r,c)*255);
dif(r,c) = graydiffer(h,T_int);%计算类间灰度差的函数略
str = ['T=',num2str(T_int),' d=',num2str(dif(r,c))];
text(c0+cblk/4,r0+rblk/2,str,'color','black');%显示信息
if dif(r,c)>20
J(r0:r1,c0:c1) = ~im2bw(X,T(r,c));
end
end
end
J = imfill(J,'holes');%填充孔洞
figure;
imshow(J);
%功能:计算一幅图像前景和背景类间平均灰度差
%输入:直方图数据h,分割阈值T
%输出:类间平均灰度差
%作者:wikiwen
%日期:2017/10/26
function[differ] = graydiffer(h,T)
s1 = sum(h(1:T));
s2 = sum(h(T:255));
n1 = 1:T;
n2 = T:255;
u1 = double(n1)*h(1:T)' / s1; %背景灰度均值
u2 = double(n2)*h(T:255)' / s2; %前景灰度均值
differ = uint8(u2-u1);
end