numpy 衍射图样FFT晶体学

hgqdbh6s  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(79)

我想逆(fft)我的衍射图案。

但输出始终是黑色画面,没有错误。

import cv2
from google.colab.patches import cv2_imshow
import numpy as np

A = cv2.imread(“picture.png“, cv2.IMREAD_GRAYSCALE)
B = np.fft.ifftshift(A)
C = np.fft.ifft2(B)
cv2_imshow(C)

我的代码有问题吗?
我真的不知道我能做些什么。有人能帮帮我吗。

snvhrwxg

snvhrwxg1#

嗯,我不知道你期待什么样的结果,作为一个图像来看。但它不是黑色的。
我不知道google collab的cv2_imshow是做什么的。特别是它如何“垂直”扩展数据。它是期望从0到1,还是从0到255,还是“自动缩放”它。也许这就是为什么它看起来是黑色的。但是只要打印数据,你就会看到它不全是0。
另外,另一个问题是C很复杂。所以cv2_imshow如何处理复数的图像,我不知道。
这是C的真实的和虚的部分

(使用matplotlib和具有快速变化颜色的colormap prism查看,以查看缓慢的渐变)
我不知道google collab的cv2_imshow。但我的猜测是,这只是一个观看问题。或者它不能处理复数。或者它使用固定范围的色彩Map表,无法处理实际范围的数据。或者颜色Map表的渐变太平滑,所以你没有注意到角落里的细微变化。但数据并不是全0。

s5a0g9ez

s5a0g9ez2#

该模式看起来像是空间域中矩形的FFT的频谱(幅度的对数)。为了在Python/OpenCV中正确地将其反转回空间域,您需要相应的幅度和相位图像。
然而,正如我们所知,它是一个矩形,它的属性是众所周知的。该模式看起来像Sinc(x,y)函数在每个维度上的绝对值(参见https://www.projectrhea.org/rhea/index.php/2D_Signals-Rect(x,y))。中心和第一个暗瓣之间的间距(非绝对Sinc的零交叉)加上图像的尺寸决定了矩形的大小,如下所示。
如果rh =矩形宽度,rh=矩形高度,sy= y中的前两个波瓣的间距,sx= x中的前两个波瓣的间距(通常FFT具有与空间域交换的维度),并且图像维度为W和H,则如果
Sinc(pix)= sin(pix)/(pix)在整数处有根(零)
所以Sinc(pi
xsy/W)Sinc(piysx/H)的第一个根是y,ry是
n =W/sy和ry=H/sx(以及整数倍的其他根)
在这个图像中,我们有sx=sy=16(近似值)和W=H=512,所以
=ry=512/16=32
因此,如果我们在512 x512图像的中心在黑色背景上构建一个尺寸为32 x32的白色矩形,并进行FFT并查看频谱,我们可以看到模式是否匹配。
我在Imagemagick中很容易做到这一点(但在Python/OpenCV中应该是可重复的)。

convert -size 512x512 xc:black -fill xc:white \
-draw "translate 256,256 rectangle -16,-16 +16,+16" -alpha off +write rectangle.png \
-fft +delete -evaluate log 10000 -auto-level x.png

下面是矩形的图像(在前两行代码中创建):

这是它的频谱(扩展到全动态范围):(第三行得到FFT幅度和相位,并删除相位,然后取缩放对数形成频谱)

因此,您可以看到每个维度上的叶数是相同的,这证实了矩形的尺寸(在一个像素左右的范围内,因为光谱图像的 Flink 比较显示出略有不同的间距)。
我不知道为什么你的图像在中心有一个黑点。
正常情况下,前向归一化,中心像素的大小将是输入图像的平均值。然而,一旦我们将其拉伸到全动态范围或以任何方式使其变亮,例如采用日志,我们就失去了确定矩形的平均值和亮度的能力,这将是
平均值=(32 x32)x幅度中心像素的亮度/(512 x512)
但我们没有那么大的规模。图像看起来只是一个明亮的光谱或明亮的幅度。所以我们无法确定矩形的实际亮度。

添加

下面是一个Python/OpenCV的等价物:

import cv2
import numpy as np
import skimage.exposure

# read the image as grayscale
img = cv2.imread('spectrum_unknown.jpg', cv2.IMREAD_GRAYSCALE)
hh, ww = img.shape[:2]
centx = round(ww/2)
centy = round(hh/2)

# Abs of sinc(pi*x) has roots at integers, so first root at 1
# Abs of sinc(pi*i*x*sy/W) has first root at rx=W/sy and similarly ry=H/sx
# where sx=sy=16 (approx)
rx = ww/16
ry = hh/16

#So create a white square of size rx,ry centered on a black background
square = np.zeros_like(img, dtype=np.uint8)
square[centy-16:centy+16, centx-16:centx+16] = 255

# convert square to floats and do dft saving as complex output
dft = cv2.dft(np.float32(square), flags = cv2.DFT_COMPLEX_OUTPUT)

# apply shift of origin from upper left corner to center of image
dft_shift = np.fft.fftshift(dft)

# extract magnitude and phase images
mag, phase = cv2.cartToPolar(dft_shift[:,:,0], dft_shift[:,:,1])

# get spectrum for viewing only
spec = np.log((mag+1)/255) / 30

# convert from float in range 0-1 to uint8 in range 0-255
spec = (255*spec).clip(0,255).astype(np.uint8)

# stretch spectrum to full dynamic range
spec_stretch = skimage.exposure.rescale_intensity(spec, in_range='image', out_range=(0,255)).astype(np.uint8)

# write result to disk
cv2.imwrite("square_image.png", square)
cv2.imwrite("spectrum_unknown_spectrum_opencv2.png", spec)
cv2.imwrite("spectrum_unknown_spectrum_stretch_opencv2.png", spec_stretch)

# show results
cv2.imshow("img", img)
cv2.imshow("square", square)
cv2.imshow("spectrum_of_square_image", spec)
cv2.imshow("spectrum_of_square_image_stretched", spec_stretch)
cv2.waitKey(0)
cv2.destroyAllWindows()

正方形图像:

光谱图像:

光谱图像扩展到全动态范围:

相关问题