TMS320C6455二维FFT和IFFT实现

参考资料:

  1. Rafael C. Gonzalez, Richard E. Woods, 数字图像处理(第三版)4.11,配套书内资源
  2. Alan V.Oppenheim, Ronald W.Schafer, 离散时间信号处理(第三版)9.5
  3. SPRUEB8B - TMS320C64x+ DSP Little-Endian DSP Library Programmer’s Reference
  4. CCS Doc, 7.8 Image Analyzer

FFT原理简介

  FFT的计算在任意一本《数字信号处理》的书中肯定都有讲,我看的是《离散时间信号处理》这本书。整个第9章对DFT和FFT做了详细的介绍。
  最开始讲的Goertzel算法,引入一个数字序列,通过这一序列的递推公式求第N个值,等价于计算相应的DFT的结果。虽然这一算法的计算量仍然正比于 N 2 N^2 N2,但也在一定程度上降低了计算复杂度。
  而后的按时间抽取和按频率抽取的FFT算法在后面又归结为N为复合数的更为一般的FFT算法。按时间抽取的算法是比较好理解的。一个数字序列,根据标号的奇偶性分为两个序列,分别计算DFT,再由它们的结果计算整个序列的DFT就非常方便。其中可以灵活运用旋转因子的对称性和周期性,最后表示成一个“蝶形运算”。
蝶形运算

  FFT的计算中,数据存储也是一个需要审慎考虑的问题。蝶形运算两端的数据索引如果不需要发生改变,那样就可以把计算结果再存回原来的位置,而不需要额外开辟空间,这就被称为“同址计算(in-place)”。经过观察可以发现,如果输入是到位序的,然后用同址计算得到的结果就是正序的;如果输入是正序的,再用同址计算得到的结果就是到位序的。也有那种输入输出都是正序的算法,那样就没有采用同址计算。
  我们熟悉的FFT算法,把序列分成奇偶序列递归地运算,就要求序列长度是2的幂次,这种算法称为“radix-2”算法;而如果按照类似的方法,把整个序列分成4组,即x[4n]、x[4n+1]、x[4n+2]、x[4n+3],这被称为“radix-4”算法。那样所需要的级数( l o g 4 N log_4N log4N)就更少,同时也要求序列的的长度是4的幂次。当然,还有将两种算法结合,主要采用radix-4,而在最后根据情况采用radix-2或者radix-4。

DSPLib配置

  DSP库安装在哪也都无所谓,在Window->Preferences->Code Composer Studio->Products页面下可以找到安装的DSP库。
  但是这个Product我不知道怎么用,就是我在实际的工程里即使勾选这个product好像也没啥用。
  在跑例程的时候,我看到源文件中只包含了dsplib.h,所以只要包含它的路径和对应的静态库就行。
  可以在Window->Preferences->Code Composer Studio->Build->Environment页面下添加DSP的安装路径。方便在工程中设置相应的包含路径和包含的静态库。
dsplib

图像数据生成

  用opencv-python读图像数据,调整图像分辨率,长宽同比例缩放,并在空白区域填充“0”,用于满足FFT对2的整数次幂的要求。生成输出.h文件和调整分辨率后的图像。

import cv2

img = cv2.imread("Fig0431(d)(blown_ic_crop).tif",cv2.IMREAD_GRAYSCALE)
fp_code = open('..\\FFT2\\image.h','w') #the path should adjust as your need

# the destinate image size
dst_height = 1024
dst_width = 1024

# the image size of raw image
height = img.shape[0]
width = img.shape[1]

#calculate the scale
scale = min(dst_height/height,dst_width/width)

#resize the image, using the same scale for both width and height
res = cv2.resize(img, None, fx=scale, fy=scale,interpolation=cv2.INTER_AREA)

#fill the reigon where is blank with black
res = cv2.copyMakeBorder(res,0,round(dst_height-height*scale), 0, round(dst_width-width*scale),cv2.BORDER_CONSTANT,value=[0])

# write data to .h file
linestride = int(dst_width/4)
fp_code.write('#pragma DATA_ALIGN(img_src, 8);\n')
fp_code.write('int img_src[] = {\n    ')
for i in range(dst_height):
    for k in range(4):
        for j in range(linestride):
            if(i==dst_height-1 and k == 3 and j == linestride-1):
                fp_code.write(str(res[i][k*linestride+j]) + ', 0')
            else:
                fp_code.write(str(res[i][k*linestride+j]) + ', 0, ')
        fp_code.write('\n    ')
fp_code.write('};\n')

# write image
cv2.imwrite("img.png",res)

DSPLib中的FFT和IFFT

  DSPLib中的函数可以从源文件中的注释进行理解,也可以直接看SPRUEB8B这个文档。FFT根据输入和输出数据的位宽也分好多种,我实现的是那种输入输出都是32位的fft,没有缩放系数,也就是在"dsplib安装路径\packages\ti\dsplib\src"路径下的DSP_fft32x32和DSP_ifft32x32。
  在上面的路径下有四个测试例程的文件夹还有三种FFT的实现方式,分别是纯C语言实现(_cn)、带有编译器指令的C语言实现(_i)和汇编实现(_sa)。这三种方式中,直接采用汇编实现的代码效率最高,速度最快。而DSP库默认调用的也就是这个汇编的FFT。
  这三种实现方式,采用的计算方式都是相同的,只是采用专门的汇编指令有更高的效率。所以想要理解这个代码可以直接看_cn版本的。蝶形运算的示意图大概是下面这个样子:
在这里插入图片描述

  输入输出都是正序,没有同址计算。采用radix-4的算法,一个蝶形运算需要4个数。在第一级运算中,这四个数的标号间隔为N/4(类比图里radix-2是N/2),这在代码中用变量stride表示,后续每级逐级减小。
IFFT的计算和FFT非常像,我们可以用类似的方式计算IFFT,《数字图像处理》的4.11.2给出了计算方法。
N x ∗ [ n ] = ∑ n = 0 N − 1 X ∗ [ k ] e − j 2 π k n / N N{x^*}[n] = \sum\limits_{n = 0}^{N - 1} {{X^*}[k]{e^{ - j2\pi kn/N}}} Nx[n]=n=0N1X[k]ej2πkn/N
  一般情况下 x ∗ [ n ] = x [ n ] x^*[n]=x[n] x[n]=x[n],所以我们只需要对原复数序列取共轭后做DFT,再把得到的结果除以“N”就能得到IFFT的结果。

二维FFT和IFFT实现

  在《数字图像处理》4.11.1中介绍了二维DFT的可分性,即要实现二维DFT,可以对行列两个维度分别做DFT。在代码中实现时,可以先对行做FFT,再将结果转置,之后再对行做FFT,最后再转置回去就能够得到对应的二维DFT的结果。\

/*
 * @func	fft2, because of transpose function, this function can be only used when width is equal to height!!!
 *
 * @param	w	=	twiddle factors
 * @param	psrc	=	source pointer, point to the image data to be processed
 * @param	ptmp	=	a pointer point to a data space, witch size is as same as the source image, just for temporary use
 * @param	width	=	image width
 * @param	height	=	image height
 */
void DSP_fft2(int *w, int *psrc, int *ptmp, int width, int height){
    int *ps = psrc;
    int *pd = ptmp;
    int i;

    // fft for the row
    for(i=0;i<height;i++){
        DSP_fft32x32(w, width, ps, pd);
        ps = ps + 2*width;
        pd = pd + 2*width;
    }

    //transpose
    transpose(ptmp, width, height);

    //fft for the column
    ps = ptmp;
    pd = psrc;
    for(i=0;i<width;i++){
        DSP_fft32x32(w, width, ps, pd);
        ps = ps + 2*width;
        pd = pd + 2*width;
    }

    //transpose
    transpose(psrc, width, height);
}

  这里的转置就是一般的转置,不是共轭转置。如果图像的行和列长度是相等的,转置只需要交换行列坐标相对的两个位置的数据。而如果图像的行和列的长度不相等,则需要额外开辟空间用来存放转置的数据,额外的存储开销较大,因此我就没写这部分代码,而是要求图像行列等长。
  DSP库中提供的IFFT仅是在FFT的基础上进行了一点修改,改了一些符号,实现了取复共轭的计算,但是没有除以序列长度。因此在每次调用DSP_ifft32x32后需要对结果再除以“N”才是IFFT的结果。

/*
 * @func	ifft2, because of transpose function, this function can be only used when width is equal to height!!!
 *
 * @param	w		=	twiddle factors
 * @param	psrc	=	source pointer, point to the image data to be processed
 * @param	ptmp	=	a pointer point to a data space, witch size is as same as the source image, just for temporary use
 * @param	width	=	image width
 * @param	height	=	image height
 */
void DSP_ifft2(int *w, int *psrc, int *ptmp, int width, int height){
	int *ps = psrc;
	int *pd = ptmp;
	int i;

	//ifft for the row
	for(i=0;i<height;i++){
		DSP_ifft32x32(w, width, ps, pd);
		ps = ps + 2*width;
		pd = pd + 2*width;
	}
	for(i=0;i<2*width*height;i++){
		ptmp[i] = ptmp[i]/width;
	}

	//transpose
	transpose(ptmp, width, height);

	//ifft for the column
	ps = ptmp;
	pd = psrc;
	for(i=0;i<width;i++){
		DSP_ifft32x32(w, width, ps, pd);
		ps = ps + 2*width;
		pd = pd + 2*width;
	}
	for(i=0;i<2*width*height;i++){
		psrc[i] = psrc[i]/width;
	}

	//transpose
	transpose(psrc, width, height);
}

图像分析工具(Image Analyzer)

  CCS自带图像分析工具。在调试界面,从Tools->Image Analyzer打开,电梯Image窗口内的区域,可以编辑Properties窗口中的属性。
imageanalyzer

  • Image Format: 输入图像格式,取决于具体的数据格式
  • Number of pixels per line: 每行像素
  • Number of lines: 图像行数
  • Data format: 数据格式,packed就是一个像素的数据是连续存放的,还有一种planar的就是同一通道的数据是连续存放的
  • Pixel stride (bytes): 像素步进,就是每个像素占几个字节
  • Red/Green/Blue/Alpha mask: “1”有效,可以让ARGB从几个字节中找到对应位置的值,可以重叠,RGB三个通道重叠就是灰度图像。
  • Line stride (bytes): 每行占多少字节
  • Start address: 图像起始地址
  • Read data as: 读数据的格式,根据图像的数据格式设置,int(32bit), short(16bit), char(8bit)
  • Start address: 图像起始地址
  • Read data as: 读数据的格式,根据图像的数据格式设置,int(32bit), short(16bit), char(8bit)

   设置完成后在Image窗口中点刷新按钮,即可刷新显示图像。

测试结果

  预先存入的图像:
step1
  经过FFT变换,实际数据已经超出灰度范围,无法显示正常的FFT频谱:
step2
  IFFT变换后的图像:
step3

相关资源链接

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
TMS320C6455是Texas Instruments(TI)公司推出的一款数字信号处理器(DSP)芯片,是TI公司TMS320C6000系列中的一员。TMS320C6455开发板则是基于TMS320C6455芯片设计的一款开发板,用于开发和测试基于该芯片的应用。 该开发板主要用于高性能数字信号处理和实时控制应用的原型设计、算法验证以及系统集成。它提供了丰富的接口,包括以太网接口、USB接口、串口接口、存储器接口等,使得用户可以方便地与外部设备进行通信和数据交换。另外,该开发板还具备高速时钟、优化的电源管理和可拓展的扩展接口,为用户提供了更多的开发和调试选项。 TMS320C6455开发板上预装了针对TMS320C6455芯片的完整开发环境,包括实时操作系统、编译器、调试器等。用户可以使用这些工具进行软件的开发、调试和性能优化。此外,TI还提供了丰富的文档和示例代码,供用户参考和学习。 对于开发者来说,使用TMS320C6455开发板可以快速开发出高性能的数字信号处理和实时控制应用。无论是音视频处理、图像处理、通信系统还是工业自动化等领域,该开发板都能提供强大的计算能力和丰富的接口,帮助开发者实现创新的应用方案。同时,TI公司也提供了全面的技术支持和培训,确保开发者能够有效地利用TMS320C6455开发板进行开发工作。 总之,TMS320C6455开发板是一款功能强大的开发工具,为开发者提供了丰富的接口和完整的开发环境,帮助他们快速、高效地开发和测试基于TMS320C6455芯片的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值