2D DFT与IDFT图像实现异常:IDFT输出与原图不符且反转问题排查
二维DFT/IDFT实现问题排查与修复
问题描述
实现二维离散傅里叶变换(2D DFT)和逆变换(IDFT)后,IDFT输出图像与原始图像不一致,呈现反转状态,无法正确还原原始图像,怀疑遗漏关键计算项或相位信息处理错误。
现有代码
DFT 实现代码
var i, j, k, M, N, u, v, x, y:integer; aux: extended; Real, Imaginario, Mag, IMag, Vagxy:TMatriz; Vag:TVetorE; M:=16; N:=16; SetLength(Mag, M, N); //Magnitudes ZeraMatriz(Mag, M, N); SetLength(Real, M, N); SetLength(Imaginario, M, N); aux:=2*pi; for u:=0 to M-1 do for v:=0 to N-1 do begin ZeraMatriz(Real, M, N); ZeraMatriz(Imaginario, M, N); for x:=0 to M-1 do for y:=0 to N-1 do begin Real[u,v]:=Real[u,v]+(Vagxy[x,y]*cos(aux*(((u*x)/M)+(v*y)/N))); Imaginario[u,v]:=Imaginario[u,v]-(Vagxy[x,y]*sin(aux*(((u*x)/M)+(v*y)/N))); //Form1.Memo.Lines.Add(IntToStr(Form1.Memo.Lines.Count)+' Vag: '+FloattoStr(Vagxy[x,y])+ 'x'+ InttoStr(x)+ 'y'+ InttoStr(y)); end; Mag[u,v]:=sqrt(Power(Real[u,v],2)+Power(Imaginario[u,v],2)); //Form1.Memo.Lines.Add(IntToStr(Form1.Memo.Lines.Count)+' Mag: '+FloattoStr(Mag[u,v])); end;
IDFT 实现代码
M:=16; N:=16; aux:=2*pi; SetLength(IMag, M, N); ZeraMatriz(IMag, M, N); SetLength(Real, M, N); SetLength(Imaginario, M, N); for x:=0 to M-1 do for y:=0 to N-1 do begin ZeraMatriz(Real, M, N); ZeraMatriz(Imaginario, M, N); for u:=0 to M-1 do for v:=0 to N-1 do begin Real[x,y]:=Real[x,y]+(Mag[u,v]*cos(aux*(((u*x)/M)+(v*y)/N))); Imaginario[x,y]:=Imaginario[x,y]+(Mag[u,v]*sin(aux*(((u*x)/M)+(v*y)/N))); end; IMag[x,y]:=(sqrt(Power(Real[x,y],2)+Power(Imaginario[x,y],2)))/(M*N); end; // shows image k:=0; for y := 0 to N-1 do for x := 0 to M-1 do begin Vag[k]:=IMag[x,y]; k:=k+1; end;
问题分析
- 丢失相位信息:DFT仅保存了频率域的幅度
Mag,丢弃了虚部Imaginario携带的相位信息。原始图像的还原需要幅度和相位共同作用——幅度决定频率分量的强度,相位决定分量的空间位置,仅用幅度无法还原原始信号的空间结构。 - IDFT计算逻辑错误:
- IDFT输入应为DFT输出的完整复数(实部+虚部),而非仅幅度。
- 原始图像是实数信号,IDFT计算后虚部应趋近于0,无需对实部虚部求平方根,直接取实部即可得到恢复的图像值。
- 循环冗余操作:DFT中每次计算
u,v时都全局清零Real和Imaginario矩阵,这会导致之前计算的其他u,v值被覆盖,正确做法应为每次计算新的u,v时仅清零当前Real[u,v]和Imaginario[u,v]。
修复后的代码
修正后的DFT代码
var i, j, k, M, N, u, v, x, y:integer; aux: extended; DFT_Real, DFT_Imag, Mag, IMag, Vagxy:TMatriz; Vag:TVetorE; M:=16; N:=16; SetLength(DFT_Real, M, N); SetLength(DFT_Imag, M, N); SetLength(Mag, M, N); ZeraMatriz(DFT_Real, M, N); ZeraMatriz(DFT_Imag, M, N); ZeraMatriz(Mag, M, N); aux:=2*pi; for u:=0 to M-1 do for v:=0 to N-1 do begin // 仅清零当前(u,v)的实部虚部,而非全局矩阵 DFT_Real[u,v] := 0; DFT_Imag[u,v] := 0; for x:=0 to M-1 do for y:=0 to N-1 do begin DFT_Real[u,v] := DFT_Real[u,v] + Vagxy[x,y] * cos(aux * ((u*x)/M + (v*y)/N)); DFT_Imag[u,v] := DFT_Imag[u,v] - Vagxy[x,y] * sin(aux * ((u*x)/M + (v*y)/N)); end; Mag[u,v] := sqrt(Power(DFT_Real[u,v],2) + Power(DFT_Imag[u,v],2)); end;
修正后的IDFT代码
M:=16; N:=16; aux:=2*pi; SetLength(IMag, M, N); ZeraMatriz(IMag, M, N); var IDFT_Real: extended; for x:=0 to M-1 do for y:=0 to N-1 do begin IDFT_Real := 0; for u:=0 to M-1 do for v:=0 to N-1 do begin // 使用DFT的完整复数分量计算,取实部累加 IDFT_Real := IDFT_Real + DFT_Real[u,v] * cos(aux * ((u*x)/M + (v*y)/N)) + DFT_Imag[u,v] * sin(aux * ((u*x)/M + (v*y)/N)); end; // 归一化并赋值给恢复图像 IMag[x,y] := IDFT_Real / (M*N); end; // 输出图像(确保索引顺序正确) k:=0; for y := 0 to N-1 do for x := 0 to M-1 do begin Vag[k] := IMag[x,y]; k := k+1; end;
关键修复点说明
- 保存DFT的完整复数结果(
DFT_Real和DFT_Imag),保留相位信息。 - IDFT直接使用复数分量计算,利用欧拉公式展开后仅累加实部(因原始图像为实数)。
- 移除不必要的全局矩阵清零操作,仅初始化当前计算的变量,提升效率并避免数据覆盖。
- 归一化步骤放在实部累加之后,直接得到恢复的图像像素值。
内容的提问来源于stack exchange,提问作者Lara Anoni
相关产品推荐
相关产品推荐

