import numpy as np
from Segmentation import IrisLocalization
from line import findline, linecoords
import multiprocessing as mp
def segment(eyeim, eyelashes_thres=80, use_multiprocess=True):
ciriris,cirpupil = IrisLocalization(eyeim)
row = np.round(ciriris[0]).astype(int)
col = np.round(ciriris[1]).astype(int)
r = np.round(ciriris[2]).astype(int)
rowp = np.round(cirpupil[0]).astype(int)
colp = np.round(cirpupil[1]).astype(int)
rp = np.round(cirpupil[2]).astype(int)
imsz = eyeim.shape
irl = np.round(row - r).astype(int)
iru = np.round(row + r).astype(int)
icl = np.round(col - r).astype(int)
icu = np.round(col + r).astype(int)
if irl < 0:
irl = 0
if icl < 0:
icl = 0
if iru >= imsz[0]:
iru = imsz[0] - 1
if icu >= imsz[1]:
icu = imsz[1] - 1
imageiris = eyeim[irl: iru + 1, icl: icu + 1]
if use_multiprocess:
ret_top = mp.Manager().dict()
ret_bot = mp.Manager().dict()
p_top = mp.Process(
target=findTopEyelid,
args=(imsz, imageiris, irl, icl, rowp, rp, ret_top),
)
p_bot = mp.Process(
target=findBottomEyelid,
args=(imsz, imageiris, rowp, rp, irl, icl, ret_bot),
)
p_top.start()
p_bot.start()
p_top.join()
p_bot.join()
mask_top = ret_top[0]
mask_bot = ret_bot[0]
else:
mask_top = findTopEyelid(imsz, imageiris, irl, icl, rowp, rp)
mask_bot = findBottomEyelid(imsz, imageiris, rowp, rp, irl, icl)
imwithnoise = eyeim.astype(float)
imwithnoise = imwithnoise + mask_top + mask_bot
ref = eyeim < eyelashes_thres
coords = np.where(ref == 1)
imwithnoise[coords] = np.nan
return ciriris, cirpupil, imwithnoise
def findTopEyelid(imsz, imageiris, irl, icl, rowp, rp, ret_top=None):
"""
Description:
Mask for the top eyelid region.
Input:
imsz - Size of the eye image.
imageiris - Image of the iris region.
irl -
icl -
rowp - y-coordinate of the inner circle centre.
rp - radius of the inner circle centre.
ret_top - Just used for returning result when using multiprocess.
Output:
mask - Map of noise that will be masked with NaN values.
"""
topeyelid = imageiris[0: rowp - irl - rp, :]
lines = findline(topeyelid)
mask = np.zeros(imsz, dtype=float)
if lines.size > 0:
xl, yl = linecoords(lines, topeyelid.shape)
yl = np.round(yl + irl - 1).astype(int)
xl = np.round(xl + icl - 1).astype(int)
yla = np.max(yl)
y2 = np.arange(yla)
mask[yl, xl] = np.nan
grid = np.meshgrid(y2, xl)
mask[grid] = np.nan
if ret_top is not None:
ret_top[0] = mask
return mask
def findBottomEyelid(imsz, imageiris, rowp, rp, irl, icl, ret_bot=None):
"""
Description:
Mask for the bottom eyelid region.
Input:
imsz - Eye image.
imageiris - Image of the iris region.
rowp - y-coordinate of the inner circle centre.
rp - radius of the inner circle centre.
irl -
icl -
ret_bot - Just used for returning result when using multiprocess.
Output:
mask - Map of noise that will be masked with NaN values.
"""
if rowp - irl + rp -1 >= imageiris.shape[0]:
bottomeyelid = imageiris[imageiris.shape[0]-2 : imageiris.shape[0], :]
else:
bottomeyelid = imageiris[rowp - irl + rp -1: imageiris.shape[0], :]
lines = findline(bottomeyelid)
mask = np.zeros(imsz, dtype=float)
if lines.size > 0:
xl, yl = linecoords(lines, bottomeyelid.shape)
yl = np.round(yl + rowp + rp - 3).astype(int)
xl = np.round(xl + icl - 2).astype(int)
yla = np.min(yl)
y2 = np.arange(yla-1, imsz[0])
mask[yl, xl] = np.nan
grid = np.meshgrid(y2, xl)
mask[grid] = np.nan
if ret_bot is not None:
ret_bot[0] = mask
return mask
处理文件
import numpy as np
from scipy.ndimage import convolve
from skimage.transform import radon
def findline(img):
"""
Description:
Find lines in an image.
Linear Hough transform and Canny edge detection are used.
Input:
img - The input image.
Output:
lines - Parameters of the detected line in polar form.
"""
I2, orient = canny(img, 2, 0, 1)
I3 = adjgamma(I2, 1.9)
I4 = nonmaxsup(I3, orient, 1.5)
edgeimage = hysthresh(I4, 0.2, 0.15)
theta = np.arange(180)
R = radon(edgeimage, theta, circle=False)
sz = R.shape[0] // 2
xp = np.arange(-sz, sz+1, 1)
maxv = np.max(R)
if maxv > 25:
i = np.where(R.ravel() == maxv)
i = i[0]
else:
return np.array([])
R_vect = R.ravel()
ind = np.argsort(-R_vect[i])
u = i.shape[0]
k = i[ind[0: u]]
y, x = np.unravel_index(k, R.shape)
t = -theta[x] * np.pi / 180
r = xp[y]
lines = np.vstack([np.cos(t), np.sin(t), -r]).transpose()
cx = img.shape[1] / 2 - 1
cy = img.shape[0] / 2 - 1
lines[:, 2] = lines[:,2] - lines[:,0]*cx - lines[:,1]*cy
return lines
def linecoords(lines, imsize):
"""
Description:
Find x-, y- coordinates of positions along a line.
Input:
lines - Parameters (polar form) of the line.
imsize - Size of the image.
Output:
x,y - Resulting coordinates.
"""
xd = np.arange(imsize[1])
yd = (-lines[0,2] - lines[0,0] * xd) / lines[0,1]
coords = np.where(yd >= imsize[0])
coords = coords[0]
yd[coords] = imsize[0]-1
coords = np.where(yd < 0)
coords = coords[0]
yd[coords] = 0
x = xd
y = yd
return x, y
def canny(im, sigma, vert, horz):
"""
Description:
Canny edge detection.
Input:
im - The input image.
sigma - Standard deviation of Gaussian smoothing filter.
vert - Weighting for vertical gradients.
horz - Weighting for horizontal gradients.
Output:
grad - Edge strength (gradient amplititude)
orient - Orientation image (0-180, positive, anti-clockwise)
"""
def fspecial_gaussian(shape=(3, 3), sig=1):
m, n = [(ss - 1) / 2 for ss in shape]
y, x = np.ogrid[-m:m + 1, -n:n + 1]
f = np.exp(-(x * x + y * y) / (2 * sig * sig))
f[f < np.finfo(f.dtype).eps * f.max()] = 0
sum_f = f.sum()
if sum_f != 0:
f /= sum_f
return f
hsize = [6 * sigma + 1, 6 * sigma + 1]
gaussian = fspecial_gaussian(hsize, sigma)
im = convolve(im, gaussian, mode='constant')
rows, cols = im.shape
h = np.concatenate([im[:, 1:cols], np.zeros([rows,1])], axis=1) - \
np.concatenate([np.zeros([rows, 1]), im[:, 0: cols - 1]], axis=1)
v = np.concatenate([im[1: rows, :], np.zeros([1, cols])], axis=0) - \
np.concatenate([np.zeros([1, cols]), im[0: rows - 1, :]], axis=0)
d11 = np.concatenate([im[1:rows, 1:cols], np.zeros([rows - 1, 1])], axis=1)
d11 = np.concatenate([d11, np.zeros([1, cols])], axis=0)
d12 = np.concatenate([np.zeros([rows-1, 1]), im[0:rows - 1, 0:cols - 1]], axis=1)
d12 = np.concatenate([np.zeros([1, cols]), d12], axis=0)
d1 = d11 - d12
d21 = np.concatenate([im[0:rows - 1, 1:cols], np.zeros([rows - 1, 1])], axis=1)
d21 = np.concatenate([np.zeros([1, cols]), d21], axis=0)
d22 = np.concatenate([np.zeros([rows - 1, 1]), im[1:rows, 0:cols - 1]], axis=1)
d22 = np.concatenate([d22, np.zeros([1, cols])], axis=0)
d2 = d21 - d22
X = (h + (d1 + d2) / 2) * vert
Y = (v + (d1 - d2) / 2) * horz
gradient = np.sqrt(X * X + Y * Y)
orient = np.arctan2(-Y, X)
neg = orient < 0
orient = orient * ~neg + (orient + np.pi) * neg
orient = orient * 180 / np.pi
return gradient, orient
def adjgamma(im, g):
"""
Description:
Adjust image gamma.
Input:
im - The input image.
g - Image gamma value.
Range (0, 1] enhances contrast of bright region.
Range (1, inf) enhances contrast of dark region.
Output:
newim - The adjusted image.
"""
newim = im
newim = newim - np.min(newim)
newim = newim / np.max(newim)
newim = newim ** (1 / g)
return newim
def nonmaxsup(in_img, orient, radius):
"""
Description:
Perform non-maxima suppression on an image using an orientation image
Input:
in_img - The input image
orient - Image containing feature normal orientation angles
radius - Distance to be looked at on each side of each pixel when
determining whether it is a local maxima or not (1.2 - 1.5)
Output:
im_out - The suppressed image
"""
rows, cols = in_img.shape
im_out = np.zeros([rows, cols])
iradius = np.ceil(radius).astype(int)
angle = np.arange(181) * np.pi / 180
xoff = radius * np.cos(angle)
yoff = radius * np.sin(angle)
hfrac = xoff - np.floor(xoff)
vfrac = yoff - np.floor(yoff)
orient = np.fix(orient)
col, row = np.meshgrid(np.arange(iradius, cols - iradius),
np.arange(iradius, rows - iradius))
ori = orient[row, col].astype(int)
x = col + xoff[ori]
y = row - yoff[ori]
fx = np.floor(x).astype(int)
cx = np.ceil(x).astype(int)
fy = np.floor(y).astype(int)
cy = np.ceil(y).astype(int)
tl = in_img[fy, fx]
tr = in_img[fy, cx]
bl = in_img[cy, fx]
br = in_img[cy, cx]
upperavg = tl + hfrac[ori] * (tr - tl)
loweravg = bl + hfrac[ori] * (br - bl)
v1 = upperavg + vfrac[ori] * (loweravg - upperavg)
map_candidate_region = in_img[row, col] > v1
x = col - xoff[ori]
y = row + yoff[ori]
fx = np.floor(x).astype(int)
cx = np.ceil(x).astype(int)
fy = np.floor(y).astype(int)
cy = np.ceil(y).astype(int)
tl = in_img[fy, fx]
tr = in_img[fy, cx]
bl = in_img[cy, fx]
br = in_img[cy, cx]
upperavg = tl + hfrac[ori] * (tr - tl)
loweravg = bl + hfrac[ori] * (br - bl)
v2 = upperavg + vfrac[ori] * (loweravg - upperavg)
map_active = in_img[row, col] > v2
map_active = map_active * map_candidate_region
im_out[row, col] = in_img[row, col] * map_active
return im_out
def hysthresh(im, T1, T2):
"""
Description:
Hysteresis thresholding.
Input:
im - The input image.
T1 - The upper threshold value.
T2 - The lower threshold value
Output:
bw - The binarized image.
"""
rows, cols = im.shape
rc = rows * cols
rcmr = rc - rows
rp1 = rows + 1
bw = im.ravel()
pix = np.where(bw > T1)
pix = pix[0]
npix = pix.size
stack = np.zeros(rows * cols)
stack[0:npix] = pix
stp = npix
for k in range(npix):
bw[pix[k]] = -1
O = np.array([-1, 1, -rows - 1, -rows, -rows + 1, rows - 1, rows, rows + 1])
while stp != 0:
v = int(stack[stp-1])
stp -= 1
if rp1 < v < rcmr:
index = O + v
for l in range(8):
ind = index[l]
if bw[ind] > T2:
stp += 1
stack[stp-1] = ind
bw[ind] = -1
bw = (bw == -1)
bw = np.reshape(bw, [rows, cols])
return bw