-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpyzernikemoment.py
100 lines (90 loc) · 3.3 KB
/
pyzernikemoment.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
# -------------------------------------------------------------------------
# Copyright C 2015 Gefu Tang
# tanggefu@gmail.com
#
# License Agreement: To acknowledge the use of the code please cite the
# following papers:
#
# [1] A. Tahmasbi, F. Saki, S. B. Shokouhi,
# Classification of Benign and Malignant Masses Based on Zernike Moments,
# Comput. Biol. Med., vol. 41, no. 8, pp. 726-735, 2011.
#
# [2] F. Saki, A. Tahmasbi, H. Soltanian-Zadeh, S. B. Shokouhi,
# Fast opposite weight learning rules with application in breast cancer
# diagnosis, Comput. Biol. Med., vol. 43, no. 1, pp. 32-41, 2013.
# -------------------------------------------------------------------------
import numpy as np
from math import factorial
# -------------------------------------------------------------------------
# Function to compute Zernike Polynomials:
#
# rad = radialpoly(r,n,m)
# where
# r = radius
# n = the order of Zernike polynomial
# m = the repetition of Zernike moment
# -------------------------------------------------------------------------
def radialpoly(r, n, m):
rad = np.zeros(r.shape, r.dtype)
P = int((n - abs(m)) / 2)
Q = int((n + abs(m)) / 2)
for s in range(P + 1):
c = (-1) ** s * factorial(n - s)
c /= factorial(s) * factorial(Q - s) * factorial(P - s)
rad += c * r ** (n - 2 * s)
return rad
# -------------------------------------------------------------------------
# Function to find the Zernike moments for an N x N binary ROI
#
# Z, A, Phi = Zernikmoment(src, n, m)
# where
# src = input image
# n = The order of Zernike moment (scalar)
# m = The repetition number of Zernike moment (scalar)
# and
# Z = Complex Zernike moment
# A = Amplitude of the moment
# Phi = phase (angle) of the mement (in degrees)
#
# Example:
# 1- calculate the Zernike moment (n,m) for an oval shape,
# 2- rotate the oval shape around its centeroid,
# 3- calculate the Zernike moment (n,m) again,
# 4- the amplitude of the moment (A) should be the same for both images
# 5- the phase (Phi) should be equal to the angle of rotation
# -------------------------------------------------------------------------
def Zernikemoment(src, n, m):
if src.dtype != np.float32:
src = np.where(src > 0, 0, 1).astype(np.float32)
if len(src.shape) == 3:
print('the input image src should be in gray')
return
H, W = src.shape
if H > W:
src = src[int((H - W) / 2): int((H + W) / 2), :]
elif H < W:
src = src[:, int((W - H) / 2): int((H + W) / 2)]
N = src.shape[0]
if N % 2:
src = src[:-1, :-1]
N -= 1
x = range(N)
y = x
X, Y = np.meshgrid(x, y)
R = np.sqrt((2 * X - N + 1) ** 2 + (2 * Y - N + 1) ** 2) / N
Theta = np.arctan2(N - 1 - 2 * Y, 2 * X - N + 1)
R = np.where(R <= 1, 1, 0) * R
# get the radial polynomial
Rad = radialpoly(R, n, m)
Product = src * Rad * np.exp(-1j * m * Theta)
# calculate the moments
Z = Product.sum()
# count the number of pixels inside the unit circle
cnt = np.count_nonzero(R) + 1
# normalize the amplitude of moments
Z = (n + 1) * Z / cnt
# calculate the amplitude of the moment
A = abs(Z)
# calculate the phase of the mement (in degrees)
Phi = np.angle(Z) * 180 / np.pi
return Z, A, Phi