-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathdaugman.py
101 lines (84 loc) · 4.12 KB
/
daugman.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import cv2
import numpy as np
import itertools
import math
from typing import Tuple, List
def daugman(gray_img: np.ndarray, center: Tuple[int, int],
start_r: int, end_r: int, step: int = 1) -> Tuple[float, int]:
""" The function will calculate pixel intensities for the circles
in the ``range(start_r, end_r, step)`` for a given ``center``,
and find a circle that precedes the biggest intensity drop
:param gray_img: grayscale picture
:param center: center coordinates ``(x, y)``
:param start_r: bottom value for iris radius in pixels
:param end_r: top value for iris radius in pixels
:param step: step value for iris radii range in pixels
.. attention::
Input grayscale image should be a square, not a rectangle
:return: intensity_value, radius
"""
x, y = center
intensities = []
mask = np.zeros_like(gray_img)
# for every radius in range
radii = list(range(start_r, end_r, step)) # type: List[int]
for r in radii:
# draw circle on mask
cv2.circle(mask, center, r, 255, 1)
# get pixel from original image, it is faster than np or cv2
diff = gray_img & mask
# normalize, np.add.reduce faster than .sum()
# diff[diff > 0] faster than .flatten()
intensities.append(np.add.reduce(diff[diff > 0]) / (2 * math.pi * r))
# refresh mask
mask.fill(0)
# calculate delta of radius intensitiveness
# mypy does not tolerate var type reload
intensities_np = np.array(intensities, dtype=np.float32)
del intensities
# circles intensity differences, x5 faster than np.diff()
intensities_np = intensities_np[:-1] - intensities_np[1:]
# aply gaussian filter
# GaussianBlur() faster than filter2D() with custom kernel
# original kernel:
# > The Gaussian filter in our case is designedin MATLAB and
# > is a 1 by 5 (rows by columns) vector with intensity values
# > given by vector A = [0.0003 0.1065 0.7866 0.1065 0.0003]
intensities_np = abs(cv2.GaussianBlur(intensities_np, (1, 5), 0))
# get maximum value
idx = np.argmax(intensities_np) # type: int
# return intensity value, radius
return intensities_np[idx], radii[idx]
def find_iris(gray: np.ndarray, *,
daugman_start: int, daugman_end: int,
daugman_step: int = 1, points_step: int = 1,) -> Tuple[Tuple[int, int], int]:
""" The function will apply :func:`daugman` on every pixel in the calculated image slice.
Basically, we are calculating where lies set of valid circle centers.
It is assumed that iris center lies within central 1/3 of the image.
:param gray: graysacale **square** image
:param points_step: it will run daugman for each ``points_step``th point.
It has linear correlation with overall iris search speed
:param daugman_start: bottom value for iris radius in pixels for :func:``daugman``
:param daugman_end: top value for iris radius in pixels for :func:``daugman``
:param daugman_step: step value for iris radii range in pixels for :func:``daugman``.
It has linear correlation with overall iris search speed
:return: radius with biggest intensiveness delta on image as ``((xc, yc), radius)``
"""
h, w = gray.shape
if h != w:
print('Your image is not a square!')
# reduce step for better accuracy
# we will look only on dots within central 1/3 of image
single_axis_range = range(int(h / 3), h - int(h / 3), points_step)
all_points = itertools.product(single_axis_range, single_axis_range)
intensity_values = []
coords = [] # List[Tuple[Tuple(int, int), int]]
for point in all_points:
val, r = daugman(gray, point, daugman_start, daugman_end, daugman_step)
intensity_values.append(val)
coords.append((point, r))
# return the radius with biggest intensiveness delta on image
# ((xc, yc), radius)
# x10 faster than coords[np.argmax(values)]
best_idx = intensity_values.index(max(intensity_values))
return coords[best_idx]