Bernsen算法的中心思想:
设当前像素为P,计算以P为中心的大小为(2k+1)*(2k+1)窗口内的所有像素的最大值Max与最小值Min,两者的均值T,
伪代码如下:
if(Max-Min)> S
则当前点P的阈值为T。
else
当前窗口所在区域的灰度级差别较小,那么窗口在目标区或在背景区,若T>Th则当前点灰度值为255,否则,当前点灰度值为0.
S和Th可以根据需要进行调整,本文中将S最初设为15, Th设为128。
//Bernsen算法
void Bernsen(const cv::Mat &src,cv::Mat &dst,int blockSize,int Th,int S){
cv::Mat padded(src);
//对原图的边缘进行扩展
cv::copyMakeBorder(src,padded,blockSize,blockSize,blockSize,blockSize,cv::BORDER_CONSTANT,cv::Scalar::all(0));
int row=padded.rows;
int col=padded.cols;
for(int i=blockSize;i<row-blockSize;i++){
const uchar* p=padded.ptr<const uchar>(i);
uchar* q=dst.ptr<uchar>(i-blockSize);
for(int j=blockSize;j<col-blockSize;j++){
//求(i,j)像素点邻域内的最大值和最小值
int max=0,min=256;
int T=0;
for(int k=i-blockSize;k<i+blockSize;k++){
const uchar* ptr=padded.ptr<const uchar>(k);
for(int l=j-blockSize;l<j+blockSize;l++){
if(ptr[l]>max)
max=ptr[l];
if(ptr[l]<min)
min=ptr[l];
}
}
//求max和min的均值
T=(max+min)>>1;
if((max-min)>S){//如果max-min>S,那么阈值设为T
q[j-blockSize]=p[j]>T ? 255:0;
}
else{//若T>Th,则当前像素点灰度值为255;否则,当前像素点灰度值为0.
q[j-blockSize]=T>Th ? 255:0;
}
}
}
}
效果图如下:
原图 效果图
整体效果来看还是不错,只是时间复杂度太大,计算过程太耗时间!
这种最原始的算法的效果总体来说还行,但一般所用的Bernsen算法都是经过各种改进的。