最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。对于图像I(x,y),前景(即目标)和背景的分割阈值记作,属于前景的像素点数占整幅图像的比例记为,其平均灰度;背景像素点数占整幅图像的比例为,其平均灰度为。图像的总平均灰度记为,类间方差记为。
假设图像的背景较暗,并且图像的大小为,图像中像素的灰度值小于阈值的像素个数记作,像素灰度大于阈值的像素个数记作,则有:
采用遍历的方法得到使类间方差最大的阈值,即为所求。
代码区
- OpenCV代码:
- int
myOtsu(const IplImage *frame) //大津法求阈值 - {
- #define
GrayScale 256 //frame灰度级 -
int width = frame->width; -
int height = frame->height; -
int pixelCount[GrayScale]={0}; -
float pixelPro[GrayScale]={0}; -
int i, j, pixelSum = width * height, threshold = 0; -
uchar* data = (uchar*)frame->imageData; -
-
//统计每个灰度级中像素的个数 -
for(i = 0; i < height; i++) -
{ -
for(j = 0;j < width;j++) -
{ -
pixelCount[(int)data[i * width + j]]++; -
} -
} -
-
//计算每个灰度级的像素数目占整幅图像的比例 -
for(i = 0; i < GrayScale; i++) -
{ -
pixelPro[i] = (float)pixelCount[i] / pixelSum; -
} -
-
//遍历灰度级[0,255],寻找合适的threshold -
float w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0; -
for(i = 0; i < GrayScale; i++) -
{ -
w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0; -
for(j = 0; j < GrayScale; j++) -
{ -
if(j <= i) //背景部分 -
{ -
w0 += pixelPro[j]; -
u0tmp += j * pixelPro[j]; -
} -
else //前景部分 -
{ -
w1 += pixelPro[j]; -
u1tmp += j * pixelPro[j]; -
} -
} -
u0 = u0tmp / w0; -
u1 = u1tmp / w1; -
deltaTmp = (float)(w0 *w1* pow((u0 - u1), 2)) ; -
if(deltaTmp > deltaMax) -
{ -
deltaMax = deltaTmp; -
threshold = i; -
} -
} -
return threshold; - }
- MATLAB
代码1 -
- function
binariedImage=OSTU(scoreImage) -
- scoreImage=double(scoreImage);
- [height,length]=size(scoreImage);
- totalPixel=height*length;
- %
maxPixNumber=max(max(scoreImage)); - %
这个地方为了以后计算方便 就不这样计算了 而是默认最大的为255 -
- pixelCount=zeros(1,256);%统计各个像素值的个数
- %
0-256 - for
i=1:length -
for j=1:height -
number=scoreImage(j,i)+1; -
pixelCount(number)=pixelCount(number)+1; -
end - end
-
- %概率
- pf=pixelCount/totalPixel;
- %前向累计概率密度函数
- cpf=zeros(1,256);
- cpf(1)=pf(1);
- for
i=2:256 -
cpf(i)=cpf(i-1)+pf(i); - end
- %后向累计概率密度函数
- bpf=zeros(1,256);
- bpf(256)=pf(256);
- for
j=256:-1:2 -
bpf(j-1)=bpf(j)+pf(j-1); - end
-
-
- %前向累计期望
- meanForward=zeros(1,256);
- meanForward(1)=1;
- for
i=2:256 -
meanForward(i)=meanForward(i-1)*(cpf(i-1)/cpf(i))+(pf(i)/cpf(i))*i; - end
-
- %后向累计期望
- meanBack=zeros(1,256);
- meanBack(max(max(scoreImage)))=max(max(scoreImage));
- for
i=max(max(scoreImage)):-1:2 -
meanBack(i-1)=meanBack(i)*(bpf(i)/bpf(i-1))+(pf(i-1)/bpf(i-1))*(i-1); - end
-
-
- delta=cpf.*bpf.*(meanForward-meanBack).^2;
- [value,index]=max(delta);
- %
返回的是逻辑的图像 - binariedImage=scoreImage>index;
- MATLAB
代码2 -
- function
binariedImage=OSTU(scoreImage) -
-
- [height,length]=size(scoreImage);
- totalNum=height*length;
- pixelCount=zeros(1,256);%统计各个像素值的个数
- for
i=1:length -
for j=1:height -
number=scoreImage(j,i)+1; -
pixelCount(number)=pixelCount(number)+1; -
end - end
- pf=pixelCount/totalNum;
- deltaMax=0;
- a=1:256;
- maxmax=max(max(scoreImage));
- for
i=1:maxmax -
-
w1=sum(pf(1:i)); -
w2=1-w1; -
mean1=sum(pf(1:i).*a(1:i))/sum(pf(1:i)); -
mean2=sum(pf(i+1:maxmax).*a(i+1:maxmax))/sum(pf(i+1:maxmax)); -
delta=w1*w2*(mean1-mean2)^2; -
if delta>deltaMax -
deltaMax=delta; -
threshold=i; -
end -
- end
-
- %
返回的是逻辑的图像 - binariedImage=scoreImage>threshold;
本篇文章来源于 Linux公社网站(www.linuxidc.com)
在图像处理应用中二值化操作是一个很常用的处理方式,例如零器件图片的处理、文本图片和验证码图片中字符的提取、车牌识别中的字符分割,以及视频图像中的运动目标检测中的前景分割,等等。
较为常用的图像二值化方法有:1)全局固定阈值;2)局部自适应阈值;3)OTSU等。
全局固定阈值很容易理解,就是对整幅图像都是用一个统一的阈值来进行二值化;
局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值。这样做的好处在于每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。亮度较高的图像区域的二值化阈值通常会较高,而亮度较低的图像区域的二值化阈值则会相适应地变小。不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。常用的局部自适应阈值有:1)局部邻域块的均值;2)局部邻域块的高斯加权和。
OpenCV中实现了以上几种二值化方法。
下面这段代码对比了全局固定阈值与局部自适应阈值的二值化结果。
//
//
#include
#include
int main(int argc, char** argv)
{
}
原图:
全局固定阈值二值化结果(T = 100)
局部自适应阈值二值化结果(块大小 = 25)
[
本篇文章来源于 Linux公社网站(www.linuxidc.com)