前言
之前处理图像二值化时使用的是经典的Otsu算法,这次要求使用Fuzzy Density Model去做一个图像二值化处理,网上参考文档除了作者的论文,几乎为零,可参考代码都没有。所以读完论文后特地记录一下。
先声明:这篇论文还没有完全理解吸收,记录自己学习过程,如果有误,欢迎交流
论文简介
一般图像二值化的处理是对图像灰度化后,处理其直方图,取其中的一个点作为threshold,以此为界,将图片中灰度小于该点的值、大于该点的值分成两部分。
Fuzzy Set Theory
作者先介绍了一个称作Fuzzy Set的理论。令X={X1,X2....Xn},函数μ,它将X中的每个元素映射到[0,1]区间上,即对于X中元素Xi,有: 0<=μ(Xi)<=1,令A={( Xi , μ(Xi) )},A即为X上的Fuzzy Set。相当于对于X中的每个元素给予了一个0-1的权重。这里的μ特别地被称为membership function。
Fuzzy Set Model
何为图像密度?以下图为例,假设点距离圆心越近,则拥有越高的权重,那么我们可以得出(a)图中点权重之和比上以r为半径的圆面积,大于,(b)图中点权重之后比上以r为半径的圆面积
论文里提到了三个membership function,分别为
-
Zadeh’s S-membership function
-
Gamma membership function
-
Gaussian membership function
这里引入fdm(r,p)函数,用于计算fuzzy density,r为计算的图像区域,p为区域内的点。fdm计算结果越高,则相似度越大。
Threshold Selection Method
对于图像的直方图有明、暗两部分,对于Object(亮部),显然有灰度越小,越暗,权重越低,对于Background则反之,所以如果我们分别选取灰度图中最大、最小作为明暗中心,做出他们的fdm函数,大致如图
交界处即为所需要的threshold。
The Rest
论文剩余部分对左右两个初始区域、以及threshold的适当调整做了更近一步探讨,这里暂时不记录了(主要是没有看大明白。。。),有兴趣读者可以查看作者原论文
实践
Lang:Python
Package:PIL
# Created by william wei on 17/1/7.
# Copyright © 2017年. All rights reserved.
import PIL
import math
from PIL import Image
Xmin=0
Xmax=0
hist = []
def membership_function(x):
b = (Xmin+Xmax)/2
x = x*1.0
if x <= Xmin:
return 0
if x>Xmin and x<=b:
return 2*math.pow( (x-Xmin)/(Xmax-Xmin), 2 )
if x>b and x<Xmax:
return 1-2*math.pow( (x-Xmax)/(Xmax-Xmin), 2 )
if x>=Xmax:
return 1
return 0
def fdm(x,y,inverse=0):
global Xmin,Xmax
result = 0
num = 0
for i in xrange(x,y):
num = num+hist[i]
if inverse==1:
result = result+hist[i]*membership_function(Xmax-(i-Xmin))
else:
result = result+hist[i]*(membership_function(i))
return result/num
if __name__ == "__main__":
im=Image.open('cherry.png')
im = im.convert('L')
hist = im.histogram()
threshold = 0
for i in xrange(0,256):
if hist[i] > 0:
Xmin = i
break;
for i in xrange(0,256):
if hist[255-i] > 0:
Xmax = 255-i
break;
for x in xrange(Xmin+1,Xmax):
left = fdm(Xmin,x,1)
right = fdm(x,Xmax)
if left<right and threshold == 0:
threshold = x
print threshold
height,width = im.size
bkg = im.convert('L')
obj = im.convert('L')
for x in xrange(0,height):
for y in xrange(0,width):
pixel = im.getpixel((x,y))
print (threshold)
if pixel<threshold :
obj.putpixel((x,y),0)
else:
bkg.putpixel((x,y),0)
bkg.save('bkg.png')
obj.save('obj.png')
效果如图:
-
原图
-
Object
-
Background
再说点
效果说实话,确实不是很好,比Otsu差不少,不过这倒不是作者的问题,应该是把论文剩余部分读完的原因吧,姑且先这样,后面有时间再回来研究一下。