前言
之前處理圖像二值化時使用的是經典的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差不少,不過這倒不是作者的問題,應該是把論文剩余部分讀完的原因吧,姑且先這樣,后面有時間再回來研究一下。