sauvola是一种考虑局部均值亮度的图像二值化方法, 以局部均值为基准在根据标准差做些微调.算法实现上一般用积分图方法来实现的.
步骤1 计算区域像素积分和和积分平方和
步骤2 计算标准差,标准差的计算方法为: std = sqrt((sqdiff - diff*diff / area) / (area - 1))
步骤3 sauvola二值化算法的阈值为T = mean*(1 + k*((std / 128) - 1)).
python代码如下:
def integral(img):
'''
计算图像的积分和平方积分
:param img:Mat--- 输入待处理图像
:return:integral_sum, integral_sqrt_sum:Mat--- 积分图和平方积分图
'''
integral_sum=np.zeros((img.shape[0],img.shape[1]),dtype=np.int32)
integral_sqrt_sum=np.zeros((img.shape[0],img.shape[1]),dtype=np.int32)
rows,cols=img.shape
for r in range(rows):
sum=0
sqrt_sum=0
for c in range(cols):
sum+=img[r][c]
sqrt_sum+=math.sqrt(img[r][c])
if r==0:
integral_sum[r][c]=sum
integral_sqrt_sum[r][c]=sqrt_sum
else:
integral_sum[r][c]=sum+integral_sum[r-1][c]
integral_sqrt_sum[r][c]=sqrt_sum+integral_sqrt_sum[r-1][c]
return integral_sum, integral_sqrt_sum
def sauvola(img,k=0.1,kernerl=(31,31)):
'''
sauvola阈值法。
根据当前像素点邻域内的灰度均值与标准方差来动态计算该像素点的阈值
:param img:Mat--- 输入待处理图像
:param k:float---修正参数,一般0>1#计算领域类半径的一半
for row in range(rows):
print('第{}行处理中...'.format(row))
for col in range(cols):
xmin=max(0,row-whalf)
ymin=max(0,col-whalf)
xmax=min(rows-1,row+whalf)
ymax=min(cols-1,col+whalf)
area=(xmax-xmin+1)*(ymax-ymin+1)
if area<=0:
sys.exit(1)
if xmin==0 and ymin==0:
diff[row,col]=integral_sum[xmax,ymax]
sqrt_diff[row,col]=integral_sqrt_sum[xmax,ymax]
elif xmin>0 and ymin==0:
diff[row, col] = integral_sum[xmax, ymax]-integral_sum[xmin-1,ymax]
sqrt_diff[row, col] = integral_sqrt_sum[xmax, ymax]-integral_sqrt_sum[xmin-1, ymax]
elif xmin==0 and ymin>0:
diff[row, col] = integral_sum[xmax, ymax] - integral_sum[xmax, ymax-1]
sqrt_diff[row, col] = integral_sqrt_sum[xmax, ymax] - integral_sqrt_sum[xmax, ymax-1]
else:
diagsum=integral_sum[xmax, ymax]+integral_sum[xmin-1, ymin-1]
idiagsum=integral_sum[xmax, ymin-1]+integral_sum[xmin-1, ymax]
diff[row,col]=diagsum-idiagsum
sqdiagsum=integral_sqrt_sum[xmax, ymax]+integral_sqrt_sum[xmin-1, ymin-1]
sqidiagsum=integral_sqrt_sum[xmax, ymin-1]+integral_sqrt_sum[xmin-1, ymax]
sqrt_diff[row,col]=sqdiagsum-sqidiagsum
mean[row,col]=diff[row, col]/area
std[row,col]=math.sqrt((sqrt_diff[row,col]-math.sqrt(diff[row,col])/area)/(area-1))
threshold[row,col]=mean[row,col]*(1+k*((std[row,col]/128)-1))
if img[row,col]
原图:
Sauvola二值化后: