手背血管预处理--利用PIL进行数字图像的综合处理_

    终于把这个Project弄完了。我采取的是Python的轻量级的图像处理插件PIL进行包括图像增强,图像分割等方面的处理。实验室采集的手背静脉图像低对比度低分辨率噪声非常大。整个处理过程包括预处理,ROI定位,以及后续处理,实验结果还算理想。

   原始图片:

  

(此图如有版权问题请与我联系)

ROI:

最后的细化结果:

    网上有很多人采取的是Python与Opencv结合的方式进行数字图像的处理,更多的是直接使用matlab。由于我采用的是纯python语言,因此我做了很多PIL没有做到的但是Opencv做的事情。PIL是轻量级的Python Image 处理工具,用于专业的数字图像处理还是不怎么适合的,在这个过程中我花费了很多时间,也算收获不少吧。

   基于手背血管进行身份识别的预处理研究  是老师给我们的一篇参考论文,作者是天津理工大学的***,这篇论文竟然跟清华大学的***写的论文

人体手背血管图像的特征提取及匹配惊人地相似,我也无法甄别其中的真伪,但有一点可以肯定的是一方过分参考另外一方,呵呵,在中国,特别是搞学术的这个大家都懂的,这其中的原因很复杂,博客园是个和谐的地方~~~中国的学术环境挺恶劣的说。

1.直方图均衡化:

     很经典,大家熟知的图像增强方法。 

# -*- coding: utf-8 -*-

# histogram equalization 还得写均衡化程序晕死

import operator
import Image
def equalize(h):
lut
= []
for b in range(0, len(h), 256):
# 步数
step = reduce(operator.add, h[b:b+256]) / 255
# 创建查找表
n = 0
for i in range(256):
lut.append(n
/ step)
n
= n + h[i+b]
return lut

#测试程序
if __name__ == "__main__":
im
= Image.open('roi.jpg')
#计算查找表
lut = equalize(im.histogram())
# 查表
im = im.point(lut)
im.save(
"roi_equalized.jpg")

2.二值化:

# -*- coding: utf-8 -*-
#
Binary operation using a given threshold
#
Author:ChenxofHit@gmail.com 16时51分31秒20110516

import Image

def fxxBinary(im, threshold): #给定阈值,返回二值图像
# convert to grey level image
Lim = im.convert('L')
Lim.save(
'roi_Level.jpg')

# setup a converting table with constant threshold
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(
255)

# convert to binary image by the table
bim = Lim.point(table, '1')
return bim

#测试代码
if __name__ =='__main__':
im
= Image.open('roi_equalized.jpg')
im.show()
threshold
= 128
bim
= fxxBinary(im, threshold)
bim.show()
bim.save(
'roi_binary.jpg')

3  Otsu阈值分割 

     matlab中的im2bw采用的就是这种阈值分割方式。借助于上面的二值化代码。

# -*- coding: utf-8 -*-
import Image,ImageEnhance,ImageFilter,ImageDraw
import fxxBinary
'''大津法由大津于1979年提出,对图像Image,记t为前景与背景的分割阈值,
前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。
图像的总平均灰度为:u=w0*u0+w1*u1。从最小灰度值到最大灰度值遍历t,
当t使得值g=w0*(u0-u)2+w1* (u1-u)2 最大时t即为分割的最佳阈值。
直接应用大津法计算量较大,因此我们在实现时采用了等价的公式g=w0*w1*(u0-u1)2。
部分计算过程如下
'''
def OtsuGrayThreshold(image):
# 创建Hist
#image = Image.open("4.f")
image.convert('L')
hist
= image.histogram()
print len(hist)
print hist

# 开始计算
# 计算总亮度
totalH = 0
for h in range(0,256):
v
=hist[h]
if v == 0 : continue
totalH
+= v*h
print h,totalH,v*h


width
= image.size[0]
height
= image.size[1]
total
= width*height
print width
print height

#print "总像素:%d;总亮度:%d平均亮度:%0.2f"%(total,totalH,totalH/total)

v
= 0

gMax
= 0.0
tIndex
= 0

# temp
n0Acc = 0.0
n1Acc
= 0.0
n0H
= 0.0
n1H
= 0.0
for t in range(1,255):
v
= hist[t-1]
if v == 0: continue

n0Acc
+= v #灰度小于t的像素的数目
n1Acc = total - n0Acc #灰度大于等于t的像素的数目
n0H += (t-1)*v #灰度小于t的像素的总亮度
n1H = totalH - n0H #灰度大于等于t的像素的总亮度

if n0Acc > 0 and n1Acc > 0:
u0
= n0H/n0Acc # 灰阶小于t的平均灰度
u1 = n1H/n1Acc # 灰阶大于等于t的平均灰度
w0 = n0Acc/total # 灰阶小于t的像素比例
w1 = 1.0-w0 # 灰阶大于等于t的像素的比例
uD = u0-u1
g
= w0 * w1 * uD * uD
# print 'g=',g
#if debug > 2: print "t=%3d; u0=%.2f,u1=%.2f,%.2f;n0H=%d,n1H=%d; g=%.2f"\
# %(t,u0,u1,u0*w0+u1*w1,n0H,n1H,g)
#
print t,u0,u1,w0,w1,g
if gMax < g:
gMax
= g
tIndex
= t

# if debug >0 : print "gMaxValue=%.2f; t = %d ; t_inv = %d"\
#
%(gMax,tIndex,255-tIndex)
#
print tIndex
return tIndex

def OtsuGray(image):
otsuthreshold
=OtsuGrayThreshold(image)
bim
= fxxBinary.fxxBinary(image, otsuthreshold)
return bim


if __name__ =='__main__':
image
= Image.open('roi.jpg')
image
= image.filter(ImageFilter.EDGE_ENHANCE())
image
= image.filter(ImageFilter.MedianFilter())
image.show()
#enhancer = ImageEnhance.Contrast(im)
otsu=OtsuGray(image)
otsu.show()

4.边缘提取

     #sobel算子 #perwit算子 #isotropic算子

# -*- coding: utf-8 -*-
from PIL import Image

def SobelSharp(image): #sobel算子
SobelX = [-1,0,1,-2,0,2,-1,0,1]
SobelY
= [-1,-2,-1,0,0,0,1,2,1]
iSobelSharp
= sharp(image,SobelX,SobelY)
return iSobelSharp

def PrewittSharp(image):#perwit算子
PrewittX = [1,0,-1,1,0,-1,1,0,-1]
PrewittY
= [-1,-1,-1,0,0,0,1,1,1]
iPrewittSharp
= sharp(image,PrewittX,PrewittY)
return iPrewittSharp

def IsotropicSharp(image):#isotropic算子
IsotropicX = [1,0,-1,1.414,0,-1.414,1,0,-1]
IsotropicY
= [-1,-1.414,-1,0,0,0,1,1.414,1]
iIsotropicSharp
= sharp(image,IsotropicX,IsotropicY)
return iIsotropicSharp

def sharp(image,arrayX,arrayY):
w
= image.size[0]
h
= image.size[1]
size
= (w,h)

iSharpImage
= Image.new('L', size)
iSharp
= iSharpImage.load()
image
= image.load()

tmpX
= [0]*9
tmpY
= [0]*9
for i in range(1,h-1):
for j in range(1,w-1):
for k in range(3):
for l in range(3):
tmpX[k
*3+l] = image[j-1+l, i-1+k]*arrayX[k*3+l]
tmpY[k
*3+l] = image[j-1+l, i-1+k]*arrayY[k*3+l]
iSharp[j,i]
= abs(sum(tmpX))+abs(sum(tmpY))
return iSharpImage


if __name__ =='__main__':
image
= Image.open('roi_open.jpg')
iSobelSharp
= SobelSharp(image)
iSobelSharp.show()
iPrewittSharp
= PrewittSharp(image)
iPrewittSharp.show()
iIsotropicSharp
= IsotropicSharp(image)
iIsotropicSharp.show()

5.形态学开闭运算

   开闭运算

# -*- coding: utf-8 -*-
'''
Morphplogical operations such as expansion and erosion

'''
import operator, Image, ImageFilter

def Corrode(image):
w
= image.size[0]
h
= image.size[1]
size
= (w, h)

iCorrodeImage
= Image.new('L',size)
iCorrode
= iCorrodeImage.load()
image
= image.load()


kH
= range(5)+range(h-5,h)
kW
= range(5)+range(w-5,w)
for i in range(h):
for j in range(w):
if i in kH or j in kW:
iCorrode[j,i]
= 0
elif image[j,i] == 255:
iCorrode[j,i]
= 255
else:
a
= []
for k in range(10):
for l in range(10):
a.append(image[j
-5+l, i-5+k])
if max(a) == 255:
iCorrode[j, i]
= 255
else:
iCorrode[j,i]
= 0
return iCorrodeImage

def Expand(image):
w
= image.size[0]
h
= image.size[1]
size
= (w,h)

iExpandImage
= Image.new('L',size)
iExpand
= iExpandImage.load()
image
= image.load()

for i in range(w):
for j in range(h):
iExpand[i,j]
= 255
for i in range(h):
for j in range(w):
if image[j,i] == 0:
for k in range(10):
for l in range(10):
if -1<(i-5+k)<h and -1<(j-5+l)<w:
iExpand[j
-5+l, i-5+k] = 0
return iExpandImage

#测试代码
if __name__ == '__main__':
image
= Image.open('fc.bmp')
iCorrodeImage
= Corrode(image)
iCorrodeImage.show()
iExpandImage
= Expand(image)
iExpandImage.show()

6.骨架抽取细化

from PIL import Image

def Two(image):
w
= image.size[0]
h
= image.size[1]
size
= (w,h)
print size
iTwoImage
= Image.new('L', size)
iTwo
= iTwoImage.load()
image
= image.load()

for i in range(h):
for j in range(w):
#print image[j, i]
iTwo[j,i] = 0 if image[j,i] > 200 else 255
return iTwoImage


def VThin(image,array):
h
= image.size[1]
w
= image.size[0]
image
= image.load()

NEXT
= 1
for i in range(h):
for j in range(w):
if NEXT == 0:
NEXT
= 1
else:
M
= image[j-1,i]+image[j,i]+image[j+1,i] if 0<j<w-1 else 1
if image[j, i] == 0 and M != 0:
a
= [0]*9
for k in range(3):
for l in range(3):
if -1<(i-1+k)<h and -1<(j-1+l)<w and image[j-1+l, i-1+k]==255:
a[k
*3+l] = 1
sum
= a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
image[j,i]
= array[sum]*255
if array[sum] == 1:
NEXT
= 0
return image

def HThin(image,array):
h
= image.size[1]
w
= image.size[0]
image
= image.load()

NEXT
= 1
for j in range(w):
for i in range(h):
if NEXT == 0:
NEXT
= 1
else:
M
= image[j, i-1]+image[j,i]+image[j, i+1] if 0<i<h-1 else 1
if image[j, i] == 0 and M != 0:
a
= [0]*9
for k in range(3):
for l in range(3):
if -1<(i-1+k)<h and -1<(j-1+l)<w and image[j-1+l, i-1+k]==255:
a[k
*3+l] = 1
sum
= a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128
image[j,i]
= array[sum]*255
if array[sum] == 1:
NEXT
= 0
return image

def Thining(image,array, num=10):
iThinnedImage
= image.copy()
for i in range(num):
VThin(iThinnedImage,array)
HThin(iThinnedImage,array)
return iThinnedImage

def Thin(image):
array
= [0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,
1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,
1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,
1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0]

image
= image.convert('L')
#image.show()
iTwo = Two(image)
#iTwo.show()
iThin = Thining(iTwo, array)
#iThin.show()
iRes = iThin.point(lambda i: 255-i)
return iRes



if __name__ == '__main__':
image
= Image.open('roi_edge.bmp')
iThinImage
= Thin(image)
iThinImage.save(
'roi_pre.bmp')
iThinImage.show()

posted on 2011-05-20 17:16  追求卓越 挑战极限  阅读(2136)  评论(4编辑  收藏  举报

导航