泽尼克多项式被广泛用作图像矩的基函数。由于泽尼克多项式彼此正交,泽尼克矩可以表示图像的属性,且矩之间没有冗余或信息重叠。尽管泽尼克矩很大程度上取决于感兴趣区域中对象的缩放和平移,但其幅度与对象的旋转角度无关。因此,它们可用于从图像中提取描述对象形状特征的特征。例如,泽尼克矩被用作形状描述符,以对良性和恶性乳腺肿块进行分类或振动盘的表面。泽尼克矩还被用于在单细胞水平上量化骨肉瘤癌细胞系的形状。此外,泽尼克矩已用于早期发现阿尔茨海默病,方法是从阿尔茨海默病、轻度认知障碍和健康人群的 MR 图像中提取判别信息。
泽尼克矩是一种图像描述符,用于表征图像中对象的形状。要描述的形状可以是分割的二值图像,也可以是对象的边界(即形状的“轮廓”或“轮廓”)。在大多数应用中,最好使用分割的二值图像而不仅仅是轮廓,因为分割的二值图像不易受噪声影响。
泽尼克矩使用复泽尼克多项式作为矩基组。二维泽尼克矩 $Z_{n m}$,阶数 $n$,重复 $m$,在单位圆内的极坐标 $(r, θ)$ 中定义为
$$ \begin{gathered} Z_{n m}=\frac{n+1}{\pi} \int_0^1 \int_0^{2 \pi} R_m(r) e^{-j m \theta} f(r, \theta) r d r d \theta, 0 \leq|m| \leq n, n-|m| \text { 是偶数 } \end{gathered} $$
其中 $R_{n m}(r)$ 是泽尼克径向多项式的 $n$ 阶,由下式给出
$$ \begin{gathered} R_{n m}(r)= \\ \sum_{k=0}^{(n-|m|) / 2}(-1)^k \frac{(n-k)!}{k!\lfloor(n-2 k+|m|) / 2\rfloor!\lfloor(n-2 k-|m|) / 2\rfloor!} r^{n-2 k} \end{gathered} $$
与旋转矩和复矩一样,泽尼克矩的大小在图像旋转变换下是不变的。图像可以使用 M 阶矩的集合来重建为
$$ f(r, \theta) \approx \sum_{n=0}^M \sum_m Z_{n m} R_{n m}(r) e^{j m \theta} $$
示例一:4
_slow_zernike_poly
函数构造二维泽尼克基函数。在 zernike_reconstruct
函数中,我们将图像投影到 _slow_zernike_poly
返回的基函数上并计算矩。然后我们使用重建公式。
import numpy as np
from math import atan2
from numpy import cos, sin, conjugate, sqrt
def _slow_zernike_poly(Y,X,n,l):
def _polar(r,theta):
x = r * cos(theta)
y = r * sin(theta)
return 1.*x+1.j*y
def _factorial(n):
if n == 0: return 1.
return n * _factorial(n - 1)
y,x = Y[0],X[0]
vxy = np.zeros(Y.size, dtype=complex)
index = 0
for x,y in zip(X,Y):
Vnl = 0.
for m in range( int( (n-l)//2 ) + 1 ):
Vnl += (-1.)**m * _factorial(n-m) / \\\\
( _factorial(m) * _factorial((n - 2*m + l) // 2) * _factorial((n - 2*m - l) // 2) ) * \\\\
( sqrt(x*x + y*y)**(n - 2*m) * _polar(1.0, l*atan2(y,x)) )
vxy[index] = Vnl
index = index + 1
return vxy
def zernike_reconstruct(img, radius, D, cof):
idx = np.ones(img.shape)
cofy,cofx = cof
cofy = float(cofy)
cofx = float(cofx)
radius = float(radius)
Y,X = np.where(idx > 0)
P = img[Y,X].ravel()
Yn = ( (Y -cofy)/radius).ravel()
Xn = ( (X -cofx)/radius).ravel()
k = (np.sqrt(Xn**2 + Yn**2) <= 1.)
frac_center = np.array(P[k], np.double)
Yn = Yn[k]
Xn = Xn[k]
frac_center = frac_center.ravel()
npix = float(frac_center.size)
reconstr = np.zeros(img.size, dtype=complex)
accum = np.zeros(Yn.size, dtype=complex)
for n in range(D+1):
for l in range(n+1):
if (n-l)%2 == 0:
vxy = _slow_zernike_poly(Yn, Xn, float(n), float(l))
a = sum(frac_center * conjugate(vxy)) * (n + 1)/npix
accum += a * vxy
reconstr[k] = accum
return reconstr
if __name__ == '__main__':
import cv2
import pylab as pl
from matplotlib import cm
D = 12
img = cv2.imread('fl.bmp', 0)
rows, cols = img.shape
radius = cols//2 if rows > cols else rows//2
reconst = zernike_reconstruct(img, radius, D, (rows/2., cols/2.))
reconst = reconst.reshape(img.shape)
pl.figure(1)
pl.imshow(img, cmap=cm.jet, origin = 'upper')
pl.figure(2)
pl.imshow(reconst.real, cmap=cm.jet, origin = 'upper')
示例二:
我们将学习应用泽尼克矩矩实际识别图像中的对象。我们需要 2 张图像:第一个图像将是我们要检测的对象的参考图像。第二张图像将是一个干扰物图像,其中包含 (1) 我们想要查找和识别的对象,以及 (2) 一堆旨在“迷惑”我们的算法的“干扰物”对象。我们的目标是成功检测第二张图像中的参考图像。
from scipy.spatial import distance as dist
import numpy as np
import cv2
import imutils
def describe_shapes(image):
shapeFeatures = []
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (13, 13), 0)
thresh = cv2.threshold(blurred, 50, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=4)
thresh = cv2.erode(thresh, None, iterations=2)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
for c in cnts:
mask = np.zeros(image.shape[:2], dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1)
(x, y, w, h) = cv2.boundingRect(c)
roi = mask[y:y + h, x:x + w]
features = zerni_moments(roi, cv2.minEnclosingCircle(c)[1], degree=8)
shapeFeatures.append(features)
return (cnts, shapeFeatures)
refImage = cv2.imread("pokemon_red.png")
(_, gameFeatures) = describe_shapes(refImage)
shapesImage = cv2.imread("shapes.png")
(cnts, shapeFeatures) = describe_shapes(shapesImage)
D = dist.cdist(gameFeatures, shapeFeatures)
i = np.argmin(D)
for (j, c) in enumerate(cnts):
if i != j:
box = cv2.minAreaRect(c)
box = np.int0(cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box))
cv2.drawContours(shapesImage, [box], -1, (0, 0, 255), 2)
box = cv2.minAreaRect(cnts[i])
box = np.int0(cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box))
cv2.drawContours(shapesImage, [box], -1, (0, 255, 0), 2)
(x, y, w, h) = cv2.boundingRect(cnts[i])
cv2.putText(shapesImage, "FOUND!", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9,
(0, 255, 0), 3)
cv2.imshow("Input Image", refImage)
cv2.imshow("Detected Shapes", shapesImage)
cv2.waitKey(0)
要查看实际效果,只需执行以下命令:
$ python detect.py
https://embed.notionlytics.com/wt/ZXlKM2IzSnJjM0JoWTJWVWNtRmphMlZ5U1dRaU9pSlhiRWhvWlV4VVQxbHNjMlZYV2tKbU9URndaU0lzSW5CaFoyVkpaQ0k2SWpJek9USmlOVE5tWWpreVl6UXlOMk01WWpkbE5XUTVOamRoTXpZM1l6Wm1JbjA9