全局阙值分割中的直⽅图算法和熵算法
前⾔:
阙值分割处理主要是根据灰度值信息提取前景,所以对前景物体与背景物体对⽐度较⼤的图像可以得到理想的分割效果,对于对⽐度较弱的
图像,可以先提⾼图像的对⽐度,再进⾏阙值分割。
⼀、全局阙值分割
全局阙值分割是为所有的像素都设置同⼀个灰度值,⼤于或等于threshold的像素设为⿊⾊或⽩⾊,相应地,⼩于threshold的像素设为⽩
⾊或⿊⾊。
在OpenCV3.2版本,重写了阙值函数threshold(),包含在""头⽂件中,
doublethreshold(InputArraysrc,OutputArraydst,
doublethresh,doublemaxval,inttype);
enumThresholdTypes{
THRESH_BINARY=0,THRESH_BINARY_INV=1,THRESH_TRUNC=2,THRESH_TOZERO=3,
THRESH_TOZERO_INV=4,THRESH_MASK=7,THRESH_OTSU=8,THRESH_TRIANGLE=16
};
解释⼀下最后⼀个type,如果type为THRESH_BINARY,阙值分割规则为,当灰度⼤于阙值时,返回maxval,否则返回0;如果type为
THRESH_BINARY_INV,则与前者规则相反。⽽如果type为THRESH_OTSU和THRESH_TRIANGLE,那么输⼊的图像矩阵只⽀持
uchar类型,且thresh参数也作为输出参数,因为Ostu和TRIANGLE算法会⾃动计算thresh。
⼆、直⽅图技术进⾏阙值分割
当⼀幅图像有⼀个与背景呈现明显对⽐的物体的图像会具有包含双峰的直⽅图,⽽直⽅图技术则是根据这⼀“双峰”特点计算的。⾸先要找
到这两个峰值,然后取两个峰值之间的波⾕对应的灰度值,这个灰度值就是阙值,我们采⽤如下的算法来寻找直⽅图中的波⾕。
假设输⼊图像为I,⾼位H,宽为W,代表其对应的灰度直⽅图,代表灰度值等于k的像素点个数,其中
,
第⼀步:找到灰度直⽅图的第⼀个峰值,并找到其对应的灰度值也就是该峰值对应的位置,显然,第⼀个峰值就是灰度直⽅图的最⼤值,它
对应的灰度值使⽤firstPeak表⽰。
第⼆步:找到灰度直⽅图的第⼆个峰值,并找到其对应的灰度值。注意:第⼆峰值不⼀定是直⽅图的第⼆⼤值,因为我们需要的峰值是希望
在⼀定邻域内是最⼤值,如果第⼆⼤值和第⼀⼤值出现的很近,那么这种情况下第⼆⼤值就很明显不是⼀个峰值。我么使⽤如下公式计算最
⼤峰值,,其中,这个公式不仅考虑到
了灰度值的⼤⼩,还将灰度值的位置与第⼀个峰值位置的距离作为参数。
第三步:找到了两个峰值后,就可以在两个峰值之间找到波⾕灰度值,即该区域内灰度图的最⼩值的位置,然后设置为阙值进⾏阙值分割。
其中,上⾯提到的阙值分割类型中的THRESH_TRIANGLE就和直⽅图技术类似。
实现代码:
//直⽅图技术⾃动计算全局阙值
intthreshTwoPeaks(constMat&image,Mat&threshImageOut){
Mathistogram=calcGrayHist(image);
//计算第⼀个峰值位置
PointfirstPeakLoc;
minMaxLoc(histogram,NULL,NULL,NULL,&firstPeakLoc);
intfirstPeak=firstPeakLoc.x;
//计算第⼆个峰值位置
MatmeasureDist=Mat::zeros(Size(256,1),CV_32FC1);
for(intk=0;k<256;k++){
inthist_k=
}
PointcondPeakLoc;
minMaxLoc(measureDist,NULL,NULL,NULL,&condPeakLoc);
intcondPeak=condPeakLoc.x;
//得到波⾕位置
PointthreshLoc;
intthresh=0;
if(firstPeak
minMaxLoc(ge(firstPeak,condPeak),NULL,NULL,&threshLoc);
thresh=firstPeak+threshLoc.x+1;
}
el{
minMaxLoc(ge(condPeak,firstPeak),NULL,NULL,&threshLoc);
thresh=condPeak+threshLoc.x+1;
}
//根据波⾕值进⾏阙值分割
threshold(image,threshImageOut,thresh,255,THRESH_BINARY);
returnthresh;
}
注意:直⽅图技术只对灰度直⽅图有两个明显波峰的图像有较好的分割效果。
三、熵算法
信息熵(entropy)的概念来⾃信息论,假设信源信号u有n种取值,记为,每⼀种信号出现的概率记为
,那么该信号的信号熵记为:,如果把图像看作是⼀个信源,假设输⼊图像
为I,代表归⼀化的图像灰度直⽅图,那么对于8位图,就可以将其看为256个灰度符号,每⼀个符号出现的概率为
,
使⽤熵计算阙值的步骤如下:
第⼀步:计算归⼀化的灰度直⽅图I的累加概率直⽅图,⼜称零阶累积矩,记为
所以,⾸先要获取灰度直⽅图,然后将其归⼀化得到normHist。
第⼆步:计算各个灰度级的熵,记为,计算完之后将其存⼊⼀个1⾏
256列的矩阵中
第三步:计算使最⼤的t的值,即为阙值,其中
代码实现时,要特别注意在第⼆步和第三步的公式中,log函数要判断参数是否为0,进⾏相除操作时需要判断被除数是否为0,否则会出现
异常。
//熵算法计算全局阙值
//熵算法计算全局阙值
intthreshByEntroy(constMat&image,Mat&threshImageOut){
//获取灰度直⽅图
Mathistogram=calcGrayHist(image);
//归⼀化灰度直⽅图
MatnormHist;
tTo(normHist,CV_32FC1,1.0/(*),0.0);
//第⼀步,计算零阶累积矩阵
MatcumuHist=Mat::zeros(Size(256,1),CV_32FC1);
for(inti=0;i<256;i++){
if(i==0)
el
}
//第⼆步,计算各个灰度级的熵
MatentroyHist=Mat::zeros(Size(256,1),CV_32FC1);
for(inti=0;i<256;i++){
floatnormHist_i=
if(i==0){
if(normHist_i==0)
el
}
el{
if(normHist_i==0)
el
}
}
printMat(entroyHist);
//计算最⼤的f(t),得到阙值
MatFHist=Mat::zeros(Size(256,1),CV_32FC1);
floattotalEntroy=
for(inti=0;i<256;i++){
floatcumuHist_i=
doublemaxVal1;
minMaxLoc(normHist(Rect(0,0,i+1,1)),NULL,&maxVal1);
floatf1=0;
if(cumuHist_i==0||cumuHist_i==1||maxVal1==0||maxVal1==1||totalEntroy==0){
f1=0;
}
el{
f1=(
}
doublemaxVal2;
minMaxLoc(normHist(Rect(i+1,0,255-i,1)),NULL,&maxVal2);
floatf2=0;
if(cumuHist_i==0||cumuHist_i==1||maxVal2==0||maxVal2==1){
f2=0;
}
el{
if(totalEntroy==0){
f2=log10f(1-cumuHist_i)/log10f(maxVal2);
}el
f2=(
}
}
}
PointthreshLoc;
minMaxLoc(FHist,NULL,NULL,NULL,&threshLoc);
//阙值分割操作
threshold(image,threshImageOut,threshLoc.x,255,THRESH_BINARY);
returnthreshLoc.x;
}
本文发布于:2022-11-16 00:30:23,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/88/27676.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |