编辑:添加了最少的代码和进一步的说明:
我正在研究图像空间中的周期性模式。当我们在傅里叶空间中看到它们时,我看到一个十字形光谱,其旋转角度与图像空间中的光谱相同。
我尝试过的:
import cv2
import numpy as np
# Read Image:
frame= cv2.imread("ImageSpace.png")[:,:,0]
size= frame.shape[0]
#compute DFT and shift it:
dft= cv2.dft(np.float32(frame),flags=cv2.DFT_COMPLEX_OUTPUT)
mag= cv2.magnitude(dft[:,:,0],dft[:,:,1])
mag= np.fft.fftshift(mag)
# Filter lower frequencies:
mag[size//2-3:size//2+3,size//2-3:size//2+3]= np.zeros((6,6))
# We focus on the right bottom quadrant for simplification
quarterMag= mag[size//2:,size//2:]
#Search for a local maxima:
XYmax= np.unravel_index(quarterMag.argmax(), quarterMag.shape)
if XYmax[0]!=0 and XYmax[1]!=0:
theta_hat= np.arctan(XYmax[1]/XYmax[0])*180/np.pi
else:
theta_hat= 90
srcTri= np.array([
[size//2,size//2],
[size,size//2],
[size//2,size]
]).astype(np.float32)
dstTri= np.array([
[size//2,size//2],
[size//2-size//2*np.cos(theta_hat*np.pi/180),
size//2-size//2*np.sin(theta_hat*np.pi/180)],
[size//2+size//2*np.sin(theta_hat*np.pi/180),
size//2-size//2*np.cos(theta_hat*np.pi/180)]
]).astype(np.float32)
warp_Mat= cv2.getAffineTransform(srcTri, dstTri)
correctedFrame= cv2.warpAffine(frame,warp_Mat,(frame.shape[0],frame.shape[0]))
#Normalize function in order to display it
mag= cv2.normalize((mag),None,255, 0, cv2.NORM_MINMAX, cv2.CV_8UC1)
cv2.imwrite("CorrectedFrame.png", correctedFrame)
while True:
cv2.imshow("Frame",frame)
cv2.imshow("Magnitude Spectrum",mag)
cv2.imshow("Corrected Frame", correctedFrame)
cv2.waitKey(1)
此代码产生以下结果:
我的问题是,由于我仅使用第一个局部最大值来查找角度,因此我的分辨率很差,这取决于输入图像的分辨率。
对于一组模拟图像,我得到这样的结果,其中蓝色实线是我旋转的角度,十字是使用这种方法测量的角度:
您会看到存在约 4-5° 的“非线性阶梯”效果。
我想做(或知道)的是,是否有一种方法可以仅“过滤”傅立叶中“主线”中的值,将它们放入 fitLine 函数中,以便我获得最大分辨率的角度,而无需增加输入图像的大小。
感谢您的帮助!
您的输入图像分辨率是计算角度量化背后的主要问题。您必须增加 dft 输出的大小,使其对较小的频率更加敏感。
由于 dft 是像素大小不变的(意味着频率是根据宽度而不是像素数量),因此您不能简单地调整输入大小,而是必须对其进行填充。
pad=250
frame = cv2.copyMakeBorder(frame, pad, pad, pad, pad, cv2.BORDER_CONSTANT, value=0)
为什么会有4-5度的误差?
局部最大值仅落在距中心 27 像素处,在 90 度范围内留下 21 (= 2 π r/4) 像素,产生 4.3 度 (90/21) 间隙。