【OpenCV】阈值分割之自适用阈值

在不均匀照明或者灰度值分布不均匀的情况下,如果使用全局阈值分割,那么得到的分割效果往往不理想。想到的策略是针对每一个位置的灰度值设置一个对应的阈值,而该位置阈值的设置也和其邻域有必然的关系。
在对图像进行平滑处理时,均值平滑、高斯平滑、中值平滑用不同规则计算出以当前像素为中心的邻域内的灰度“平均值”,所以可以使用平滑处理后的输出结果作为每个像素设置阈值的参考值。
在自适应阈值处理中,平滑算子的尺寸决定了分割出来的物体的尺寸,如果滤波器尺寸太小,那么估计出的局部阈值将不理想。凭经验,平滑算子的宽度必须大于被识别物体的宽度,平滑算子的尺寸越大,平滑后的结果越能更好地作为每个像素的阈值的参考,当然也不能无限大。
假设输入图像为I,高为H,宽为W,平滑算子的尺寸记为HXW,其中W和H均为奇数。自适应阈值分割算法的步骤如下:
第一步,对图像进行平滑处理,平滑结果记为fsmooth(I),其中fsmooth可以代表均值平滑、高斯平滑、中值平滑。
第二步,自适应阈值矩阵Thresh=(1-ratio)*fsmooth(I),一般令ratio=0.15.
第三步,利用局部阈值分割的规则
在这里插入图片描述

在这里插入图片描述
进行阈值分割。

C++实现
在以下c++实现的自适应阈值分割中,利用OpenCV提供的boxfilter、GaussianBlur、medianBlur函数分别完成了均值平滑、高斯平滑和中值平滑,其中radius为平滑算子窗口的半径,即平滑窗口尺寸(2radius+1,2radius+1),返回值为自适用阈值分割后的结果。具体代码如下:
enum METHOD {MEAN,GAUSS,MEDIAN};
Mat adaptiveThresh(Mat I, int radius, float ratio, METHOD method=MEAN)
{
//第一步,对图像矩阵进行平滑处理
Mat smooth;
switch(method)
{
case MEAN://均值平滑
boxFilter(I,smooh,CV_32FC1,Size(2radius+1,2radius+1));
break;
case GAUSS:
GaussianBlur(I,smooth,Size(2radius+1,2radius+1),0,0);
case MEDIAN:
medianBlur(I,smooth,2*radius+1);
default:
break;
}
//第二步:平滑结果乘以比例系数,然后图像矩阵与其做差
I.convertTo(I,CV_32FC1);
smooth.convertTo(smooth,CV_32FC1);
Mat diff =I-(1.0-ratio)*I_smooth;
//第三步:阈值处理,当大于或等于0时,输出值为255;反之,输出值为0
Mat out = Mat::zeros(diff.size(),CV_8UC1);
for(int r=0;r<out.rows;r++)
{
for(int c=0;c<out.cols;c++)
{
if(diff.at(r,c)>=0)
{
out.at(r,c)=255;
}
}
return out;
}

**OpenCV提供的自适用阈值函数:**
void adaptiveThreshold(InputArray src,OutputArray dst,double maxValue,int adaptiveMethod,int thresholdType,int blockSize,double C)
src :单通道矩阵,数据类型为CV_8U
dst:输出矩阵,即阈值分割后的矩阵
maxValue:与函数threshold类似,一般取255
adaptiveMethold:ADAPTIVE_THRESH_MEAN_C:采用均指平滑,ADAPTIVE_THRESH_GAUSSIAN_C:采用高斯平滑
thresholdType:THRESH_BINARY THRESH_BINARY_INV
blockSize:平滑算子的尺寸,且为奇数
C:比例系数

猜你喜欢

转载自blog.csdn.net/weixin_42104289/article/details/86686359