zoukankan      html  css  js  c++  java
  • 基于MFC和opencv的FFT

    在网上折腾了一阵子,终于把这个程序写好了,程序是基于MFC的,图像显示的部分和获取图像的像素点是用到了opencv的一些函数,不过FFT算法没有用opencv的(呵呵,老师不让),网上的二维的FFT程序一般都是把图像分别进行行变换后进行列变换的,在编程过程中遇到了一些问题,是这样的,FFT算法算完后得到的复数矩阵怎么imshow?问题就出现在这,我原来的程序因为归一化到0-255时,程序运行特别慢(用了个CArray,找出array里的最大值和最小值,然后(每一个复数矩阵求模后-最小值)/(最大值-最小值),不满才怪呵呵,得出FFT结果是全黑的)。参考了别人的归一化

     1     /*-----------------------------------------------------------------------------
     2      *  计算功率谱
     3      *    和归一化
     4      *
     5      *-----------------------------------------------------------------------------*/
     6     //
     7     for(i = 0; i < h; i++)
     8     {
     9         //
    10         for(j = 0; j < w; j++)
    11         {
    12             // 计算频谱
    13             dTemp = sqrt(FD[j * h + i].real() * FD[j * h + i].real() + 
    14                 FD[j * h + i].imag() * FD[j * h + i].imag()) / 100;
    15 
    16             // 判断是否超过255
    17             if (dTemp > 255)
    18             {
    19                 // 对于超过的,直接设置为255
    20                 dTemp = 255;
    21             }
    22 
    23             image.at<uchar>(i,j)=(uchar)dTemp;
    24             // 更新源图像
    25 
    26         }
    27     }

    主要代码:

      1 /*
      2  * =====================================================================================
      3  *
      4  *       Filename:  fft_dlgDlg.cpp
      5  *      Environment:opencv2.4.4 vs2010
      6  *            
      7  *    Description:  基于MFC的FFT程序
      8  *
      9  *
     10  *
     11  *        Version:  1.0
     12  *        Created:  2013/10/19 19:24:06
     13  *         Author:  yuliyang
     14 I*
     15  *             Mail:  wzyuliyang911@gmail.com
     16  *             Blog:  http://www.cnblogs.com/yuliyang
     17  *
     18  * =====================================================================================
     19  */
     20 
     21 
     22 // fft_dlgDlg.cpp : 实现文件
     23 //
     24 
     25 #include "stdafx.h"
     26 #include "fft_dlg.h"
     27 #include "fft_dlgDlg.h"
     28 #include "afxdialogex.h"
     29 
     30 #include <complex>
     31 #include <math.h>
     32 #include <stdio.h>
     33 #include <Windows.h>
     34 #include "opencvhighgui.h"
     35 #include "opencv2/core/core.hpp"  
     36 #include "opencv2/highgui/highgui.hpp"  
     37 #include "opencv2/imgproc/imgproc.hpp"  
     38 using namespace cv;
     39 using namespace std;
     40 #define PI 3.1415936;
     41 
     42 #ifdef _DEBUG
     43 #define new DEBUG_NEW
     44 #endif
     45 
     46 
     47 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
     48 
     49 class CAboutDlg : public CDialogEx
     50 {
     51 public:
     52     CAboutDlg();
     53 
     54 // 对话框数据
     55     enum { IDD = IDD_ABOUTBOX };
     56 
     57     protected:
     58     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
     59 
     60 // 实现
     61 protected:
     62     DECLARE_MESSAGE_MAP()
     63 };
     64 
     65 CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
     66 {
     67 }
     68 
     69 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
     70 {
     71     CDialogEx::DoDataExchange(pDX);
     72 }
     73 
     74 BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
     75 END_MESSAGE_MAP()
     76 
     77 
     78 // Cfft_dlgDlg 对话框
     79 
     80 
     81 
     82 
     83 Cfft_dlgDlg::Cfft_dlgDlg(CWnd* pParent /*=NULL*/)
     84     : CDialogEx(Cfft_dlgDlg::IDD, pParent)
     85 {
     86     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
     87 }
     88 
     89 void Cfft_dlgDlg::DoDataExchange(CDataExchange* pDX)
     90 {
     91     CDialogEx::DoDataExchange(pDX);
     92 }
     93 
     94 BEGIN_MESSAGE_MAP(Cfft_dlgDlg, CDialogEx)
     95     ON_WM_SYSCOMMAND()
     96     ON_WM_PAINT()
     97     ON_WM_QUERYDRAGICON()
     98     ON_BN_CLICKED(IDC_OPEN_FILE, &Cfft_dlgDlg::OnBnClickedOpenFile)
     99     
    100 END_MESSAGE_MAP()
    101 
    102 
    103 // Cfft_dlgDlg 消息处理程序
    104 
    105 BOOL Cfft_dlgDlg::OnInitDialog()
    106 {
    107     CDialogEx::OnInitDialog();
    108 
    109     // 将“关于...”菜单项添加到系统菜单中。
    110 
    111     // IDM_ABOUTBOX 必须在系统命令范围内。
    112     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    113     ASSERT(IDM_ABOUTBOX < 0xF000);
    114 
    115     CMenu* pSysMenu = GetSystemMenu(FALSE);
    116     if (pSysMenu != NULL)
    117     {
    118         BOOL bNameValid;
    119         CString strAboutMenu;
    120         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    121         ASSERT(bNameValid);
    122         if (!strAboutMenu.IsEmpty())
    123         {
    124             pSysMenu->AppendMenu(MF_SEPARATOR);
    125             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    126         }
    127     }
    128 
    129     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    130     //  执行此操作
    131     SetIcon(m_hIcon, TRUE);            // 设置大图标
    132     SetIcon(m_hIcon, FALSE);        // 设置小图标
    133 
    134     // TODO: 在此添加额外的初始化代码
    135 
    136     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
    137 }
    138 
    139 void Cfft_dlgDlg::OnSysCommand(UINT nID, LPARAM lParam)
    140 {
    141     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    142     {
    143         CAboutDlg dlgAbout;
    144         dlgAbout.DoModal();
    145     }
    146     else
    147     {
    148         CDialogEx::OnSysCommand(nID, lParam);
    149     }
    150 }
    151 
    152 // 如果向对话框添加最小化按钮,则需要下面的代码
    153 //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
    154 //  这将由框架自动完成。
    155 
    156 void Cfft_dlgDlg::OnPaint()
    157 {
    158     if (IsIconic())
    159     {
    160         CPaintDC dc(this); // 用于绘制的设备上下文
    161 
    162         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    163 
    164         // 使图标在工作区矩形中居中
    165         int cxIcon = GetSystemMetrics(SM_CXICON);
    166         int cyIcon = GetSystemMetrics(SM_CYICON);
    167         CRect rect;
    168         GetClientRect(&rect);
    169         int x = (rect.Width() - cxIcon + 1) / 2;
    170         int y = (rect.Height() - cyIcon + 1) / 2;
    171 
    172         // 绘制图标
    173         dc.DrawIcon(x, y, m_hIcon);
    174     }
    175     else
    176     {
    177         CDialogEx::OnPaint();
    178     }
    179 }
    180 
    181 //当用户拖动最小化窗口时系统调用此函数取得光标
    182 //显示。
    183 HCURSOR Cfft_dlgDlg::OnQueryDragIcon()
    184 {
    185     return static_cast<HCURSOR>(m_hIcon);
    186 }
    187 
    188 
    189 
    190 void Cfft_dlgDlg::OnBnClickedOpenFile()
    191 {
    192     // TODO: 在此添加控件通知处理程序代码
    193     
    194     /*-----------------------------------------------------------------------------
    195      *  选择文件名
    196      *-----------------------------------------------------------------------------*/
    197     
    198     CString strFileName,strszFilter,strtitle,strext;
    199     strszFilter="位图文件(*.bmp)|*.bmp|位图文件(*.jpg)|*.jpg|全部文件(*.*)|*.*||";
    200     CFileDialog bmpdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,strszFilter,NULL);
    201     if(IDOK == bmpdlg.DoModal())
    202     {
    203         strFileName = bmpdlg.GetPathName();
    204         strtitle=bmpdlg.GetFileTitle();
    205         strext=bmpdlg.GetFileExt();
    206 
    207     }
    208     if (strFileName.IsEmpty())
    209     {
    210         //MessageBox((LPCTSTR)strFileName);
    211         MessageBox("请选择一副图像");
    212 
    213         return ;
    214     }
    215 
    216     /*-----------------------------------------------------------------------------
    217      *  opencv读入图像
    218      *
    219      *
    220      *-----------------------------------------------------------------------------*/
    221     Mat image=imread(strFileName.GetBuffer(0),0);
    222 
    223     //unsigned char*    lpSrc;
    224     // 中间变量
    225     double    dTemp;
    226     // 循环变量
    227     LONG    i;
    228     LONG    j;
    229     // 进行付立叶变换的宽度和高度(2的整数次方)
    230     LONG    w;
    231     LONG    h;
    232     int        wp;
    233     int        hp;
    234     // 赋初值
    235     w = 1;
    236     h = 1;
    237     wp = 0;
    238     hp = 0;
    239 
    240     /*-----------------------------------------------------------------------------
    241      *  填充到2的幂次方
    242      *
    243      *
    244      *-----------------------------------------------------------------------------*/
    245     // 计算进行付立叶变换的宽度和高度(2的整数次方)
    246     while(w * 2 <= image.cols)
    247     {
    248         w *= 2;
    249         wp++;
    250     }
    251 
    252     while(h * 2 <= image.rows)
    253     {
    254         h *= 2;
    255         hp++;
    256     }
    257     // 分配内存
    258     complex<double> *TD = new complex<double>[w * h];
    259     complex<double> *FD = new complex<double>[w * h];
    260     //
    261     for(i = 0; i < h; i++)
    262     {
    263         //
    264         for(j = 0; j < w; j++)
    265         {
    266             // 给时域赋值
    267             TD[j + w * i] = complex<double>(image.at<uchar>(i,j), 0); /* opencv函数读取图像像素到复数矩阵里 */
    268         }
    269     }
    270     /*-----------------------------------------------------------------------------
    271      *  把二维的FFT换成分别对行方向和列方向进行一维的FFT
    272      *
    273      *
    274      *-----------------------------------------------------------------------------*/
    275     for(i = 0; i < h; i++)
    276     {
    277         // 对y方向进行快速付立叶变换
    278         FFT(&TD[w * i], &FD[w * i], wp);
    279     }
    280     // 保存变换结果
    281     for(i = 0; i < h; i++)
    282     {
    283         for(j = 0; j < w; j++)
    284         {
    285             TD[i + h * j] = FD[j + w * i];
    286         }
    287     }
    288 
    289     for(i = 0; i < w; i++)
    290     {
    291         // 对x方向进行快速付立叶变换
    292         FFT(&TD[i * h], &FD[i * h], hp);
    293     }
    294 
    295     /*-----------------------------------------------------------------------------
    296      *  计算功率谱
    297      *    和归一化
    298      *
    299      *-----------------------------------------------------------------------------*/
    300     //
    301     for(i = 0; i < h; i++)
    302     {
    303         //
    304         for(j = 0; j < w; j++)
    305         {
    306             // 计算频谱
    307             dTemp = sqrt(FD[j * h + i].real() * FD[j * h + i].real() + 
    308                 FD[j * h + i].imag() * FD[j * h + i].imag()) / 100;
    309 
    310             // 判断是否超过255
    311             if (dTemp > 255)
    312             {
    313                 // 对于超过的,直接设置为255
    314                 dTemp = 255;
    315             }
    316 
    317             image.at<uchar>(i,j)=(uchar)dTemp;
    318             // 更新源图像
    319 
    320         }
    321     }
    322 
    323     /*-----------------------------------------------------------------------------
    324      *  释放内存
    325      *
    326      *
    327      *-----------------------------------------------------------------------------*/
    328     // 删除临时变量
    329     delete TD;
    330     delete FD;
    331     
    332     /*-----------------------------------------------------------------------------
    333      *  进行图像的中心化
    334      *
    335      *
    336      *-----------------------------------------------------------------------------*/
    337     int cy = image.rows/2;                      /* 中心点位置 cx ,cy */
    338     int cx = image.cols/2;
    339     uchar tmp13,tmp24;
    340 
    341     //imshow("未中心化的功率谱",image);
    342 
    343     IplImage  center_image=IplImage(image);
    344     for( j = 0; j < cy; j++ ){  
    345         for( i = 0; i < cx; i++ ){  
    346             //中心化,将整体份成四块进行对角交换  
    347             tmp13 = CV_IMAGE_ELEM( &center_image, uchar, j, i);  
    348             CV_IMAGE_ELEM( &center_image, uchar, j, i) = CV_IMAGE_ELEM(  
    349                 &center_image, uchar, j+cy, i+cx);  
    350             CV_IMAGE_ELEM( &center_image, uchar, j+cy, i+cx) = tmp13;  
    351 
    352             tmp24 = CV_IMAGE_ELEM( &center_image, uchar, j, i+cx);  
    353             CV_IMAGE_ELEM( &center_image, uchar, j, i+cx) =  
    354                 CV_IMAGE_ELEM( &center_image, uchar, j+cy, i);  
    355             CV_IMAGE_ELEM( &center_image, uchar, j+cy, i) = tmp24;  
    356         }  
    357     }  
    358 
    359 
    360     /*-----------------------------------------------------------------------------
    361      *  用于保存FFT图像
    362      *
    363      *
    364      *-----------------------------------------------------------------------------*/
    365     Mat img(&center_image,0);
    366     if (BST_CHECKED == ::IsDlgButtonChecked(m_hWnd,IDC_CHECK_SAVE))
    367     {
    368 
    369         strtitle="FFT_"+strtitle+"."+strext;
    370         
    371         //MessageBox(strtitle.GetBuffer(0));
    372         imwrite(strtitle.GetBuffer(0),img);
    373 
    374     }
    375     imshow("中心化后的功率谱",img);
    376 
    377     waitKey();
    378     // 返回
    379     //return TRUE;
    380     
    381 
    382 
    383 }
    384 
    385 /* 
    386  * ===  FUNCTION  ======================================================================
    387  *         Name:  FFT
    388  *  Description:  计算一维FFT
    389  * =====================================================================================
    390  */
    391 void Cfft_dlgDlg::FFT(complex<double> * TD, complex<double> * FD, int r)
    392 {
    393 
    394     LONG    count;
    395     // 循环变量
    396     int        i,j,k;
    397     // 中间变量
    398     int        bfsize,p;
    399     // 角度
    400     double    angle;
    401     complex<double> *W,*X1,*X2,*X;
    402     // 计算付立叶变换点数
    403     count = 1 << r;
    404     // 分配运算所需存储器
    405     W  = new complex<double>[count / 2];
    406     X1 = new complex<double>[count];
    407     X2 = new complex<double>[count];
    408     // 计算加权系数
    409     for(i = 0; i < count / 2; i++)
    410     {
    411         angle =-2*i*PI;
    412         angle =angle/(double)count;
    413         W[i] = complex<double> (cos(angle), sin(angle));
    414     }
    415     // 将时域点写入X1
    416     memcpy(X1, TD, sizeof(complex<double>) * count);
    417 
    418     /*-----------------------------------------------------------------------------
    419      *  
    420      *                   采用蝶形算法进行快速付立叶变换
    421      *
    422      *-----------------------------------------------------------------------------*/
    423      
    424     for(k = 0; k < r; k++)
    425     {
    426         for(j = 0; j < 1 << k; j++)
    427         {
    428             bfsize = 1 << (r-k);
    429             for(i = 0; i < bfsize / 2; i++)
    430             {
    431                 p = j * bfsize;
    432                 X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
    433                 X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2]) * W[i * (1<<k)];
    434             }
    435         }
    436         X  = X1;
    437         X1 = X2;
    438         X2 = X;
    439     }
    440     // 重新排序
    441     for(j = 0; j < count; j++)
    442     {
    443         p = 0;
    444         for(i = 0; i < r; i++)
    445         {
    446             if (j&(1<<i))
    447             {
    448                 p+=1<<(r-i-1);
    449             }
    450         }
    451         FD[j]=X1[p];
    452     }
    453     // 释放内存
    454     delete W;
    455     delete X1;
    456     delete X2;
    457 }

    运行效果如下:

    提供程序一份:

    http://pan.baidu.com/s/1ehvwy

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    ifconfig详解
    ln命令总结
    2008年国外最佳Web设计/开发技巧、脚本及资源总结
    金刚经全译文
    Ifconfig网络配置工具详解
    High Availability PostgreSQL HOWTO
    女人新标准
    JFreeChart API文档
    云计算火热背后:标准及安全成首要问题 狼人:
    Adobe Reader 9.3.2发布 修补15个安全漏洞 狼人:
  • 原文地址:https://www.cnblogs.com/yuliyang/p/3378257.html
Copyright © 2011-2022 走看看