Gabor 变换是一种短时加窗Fourier变换,本文记录相关内容。
https://developer-public-1258344699.cos.ap-guangzhou.myqcloud.com/column/column/10335061/20230218-68017941.png
参数 | 简介 | 含义 |
---|---|---|
$\lambda$ | 波长 | 表示正弦因子的波长,它的值以像素为单位制定,通常大于等于2,但不能大于输入图像尺寸的1/5. |
$\theta$ | 方向 | 表示法线到 Gabor 函数的平行条纹的方向 |
$\phi$ | 相位偏移 | 相位偏移 |
$\sigma$ | 标准差 | 高斯分布的标准差 |
$\gamma$ | 长宽比 | 空间纵横比,指定 Gabor 函数支持的椭圆度 |
https://developer-public-1258344699.cos.ap-guangzhou.myqcloud.com/column/column/10335061/20230218-09de0c8d.png
其中 B 和 C 是要确定的标准化因子。
参数 | 含义 |
---|---|
$f$ | 定义在纹理中查找的频率。 |
$ \theta$ | 查找纹理的方向 |
$\sigma$ | 标准差,可以调整被分析图像区域的尺寸 |
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Gabor 滤波器实现
# K_size:Gabor核大小 K_size x K_size
# Sigma : σ
# Gamma: γ
# Lambda:λ
# Psi : ψ
# angle: θ
defGabor_filter(K_size=111, Sigma=10, Gamma=1.2, Lambda=10, Psi=0, angle=0):
# get half size
d = K_size // 2
# prepare kernel
gabor = np.zeros((K_size, K_size), dtype=np.float32)
# each value
for y inrange(K_size):
for x inrange(K_size):
# distance from center
px = x - d
py = y - d
# degree -> radian
theta = angle / 180. * np.pi
# get kernel x
_x = np.cos(theta) * px + np.sin(theta) * py
# get kernel y
_y = -np.sin(theta) * px + np.cos(theta) * py
# fill kernel
gabor[y, x] = np.exp(-(_x**2 + Gamma**2 * _y**2) / (2 * Sigma**2)) * np.cos(2*np.pi*_x/Lambda + Psi)
# kernel normalization
gabor /= np.sum(np.abs(gabor))
return gabor
# define each angle
As = [0, 45, 90, 135]
# prepare pyplot
plt.subplots_adjust(left=0, right=1, top=1, bottom=0, hspace=0, wspace=0.2)
# each angle
for i, A inenumerate(As):
# get gabor kernel
gabor = Gabor_filter(K_size=111, Sigma=10, Gamma=1.2, Lambda=10, Psi=0, angle=A)
# normalize to [0, 255]
out = gabor - np.min(gabor)
out /= np.max(out)
out *= 255
out = out.astype(np.uint8)
plt.subplot(1, 4, i+1)
plt.imshow(out, cmap='gray')
plt.axis('off')
plt.title("Angle "+str(A))
plt.savefig("out.png")
plt.show()
cv.getGaborKernel( ksize, sigma, theta, lambd, gamma[, psi[, ktype]] ) -> retval
参数 | 含义 |
---|---|
ksize | 返回的筛选器大小。 |
sigma | 高斯分布标准差。 |
theta | Gabor 函数法向平行条纹的方向。 |
lambd | 正弦因子波长。 |
gamma | 空间长宽比,表示椭圆形状。 |
psi | 相位偏移。 |
ktype | 滤波器系数的类型。它可以是 CV_32F 或 CV_64F。 |
getGaborKernel
函数的代码实现如下:cv::Mat cv::getGaborKernel( Size ksize, double sigma, double theta,
double lambd, double gamma, double psi, int ktype )
{
double sigma_x = sigma;
double sigma_y = sigma/gamma;
int nstds = 3;
int xmin, xmax, ymin, ymax;
double c = cos(theta), s = sin(theta);
if( ksize.width > 0 )
xmax = ksize.width/2;
else
xmax = cvRound(std::max(fabs(nstds*sigma_x*c), fabs(nstds*sigma_y*s)));
if( ksize.height > 0 )
ymax = ksize.height/2;
else
ymax = cvRound(std::max(fabs(nstds*sigma_x*s), fabs(nstds*sigma_y*c)));
xmin = -xmax;
ymin = -ymax;
CV_Assert( ktype == CV_32F || ktype == CV_64F );
Mat kernel(ymax - ymin + 1, xmax - xmin + 1, ktype);
double scale = 1;
double ex = -0.5/(sigma_x*sigma_x);
double ey = -0.5/(sigma_y*sigma_y);
double cscale = CV_PI*2/lambd;
for( int y = ymin; y <= ymax; y++ )
for( int x = xmin; x <= xmax; x++ )
{
double xr = x*c + y*s;
double yr = -x*s + y*c;
double v = scale*std::exp(ex*xr*xr + ey*yr*yr)*cos(cscale*xr + psi);
if( ktype == CV_32F )
kernel.at<float>(ymax - y, xmax - x) = (float)v;
else
kernel.at<double>(ymax - y, xmax - x) = v;
}
return kernel;
}
import mtutils as mt
import cv2 as cv
retval = cv.getGaborKernel(ksize=(111,111), sigma=10, theta=60, lambd=10, gamma=1.2)
image1 = mt.cv_rgb_imread('test.jpg')
result = cv.filter2D(image1,-1,retval)
mt.PIS([image1, 'origin image'], [result, 'gabor image'])
pip install mtutils
import mtutils as mt
import numpy as np
import cv2 as cv
image = mt.cv_rgb_imread('bmx.jpg', 1)
kernel_size = (5, 5)
sigma = 1
lambd = np.pi / 2
gamma = 0.5
psi = 0
theta_list = [0, np.pi * 0.25, np.pi * 0.5, np.pi * 0.75]
sum_result = np.zeros_like(image, dtype='float32')
kernel_list = list()
result_list = list()
for theta in theta_list:
kernel = cv.getGaborKernel(kernel_size, sigma, theta, lambd, gamma, psi)
kernel_list.append(kernel)
result = cv.filter2D(image, -1, kernel)
result_list.append(result)
sum_result += result
mt.PIS(*kernel_list, row_num=1)
mt.PIS([result_list[0], '0°'], [result_list[1], '45°'], [result_list[2], '90°'], [result_list[3], '135°'], [sum_result, 'fea_sum'], row_num=1, axis_off=True)
dst = cv.convertScaleAbs(sum_result, alpha=0.2, beta=0)
_, thr_res = cv.threshold(dst, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
mt.PIS(255 - thr_res)
pass