基礎學習筆記之opencv(15):離散傅里葉變換


  本文主要介紹怎樣使用opencv來對圖片進行傅里葉變換,其核心函數是opencv自帶的dft()DFT這個技術手段是將空間域映射到頻率域中去,在圖像處理有着舉足輕重的地位。這里我們只是得到其變換的結果並看看貧域圖有什么特點。

  開發環境:opencv2.4.2+Qt4.8.2+ubuntu12.04+QtCreator2.5

 

  實驗功能:

  1. 單擊Open Image按鈕,手動選擇打開一副圖片,不管其是否是彩色圖片,這里統一將其轉換成灰度圖像顯示,因為需要加快DFT運算速度。

  2. 將鼠標移動到圖片顯示區域,單擊圖片,這時會顯示DFT中間結果圖,也就是沒有將低頻域的點移動到圖片的中心而已。顯示的圖片有文字提示。

  3. 繼續單擊圖片,會顯示最后重新布局后的DFT結果圖,當然也有相應的文字提示。

  4. 繼續單擊圖片時,則原圖,dft未調整圖,dft調整圖這3幅圖片會進行輪流切換顯示。

  5. 如果沒有打開圖片就在圖片顯示區域單擊,則會在圖片顯示區域顯示相應的提示文字,提示需先打開圖片。

     

  實驗說明:

  1. 1維的離散序列的DFT變換公式為:

     

    2維的離散矩陣的DFT變換公式為:

     

  2. QTextBrowser中怎樣相應鼠標單擊事件呢?

    QTextBrowser來顯示圖片(不用顯示文本),當圖片顯示好了后想單擊該圖片轉到某一個圖像處理過程函數中去(這里就是進行離散傅里葉變換),但是在QTextBrowsersingal/slot中找不到其對應的鼠標單擊的信號。因此只能自己寫該信號函數了,可是對應捕捉鼠標單擊的函數庫中應該有,那該怎么寫呢?網上有篇不錯的文章:http://www.embedu.org/Column/Column421.htm

    仿照上面的文章,自己重新寫一個類MyTextBrowser,從基類QTextBrowser中繼承而來,然后重寫該類的mousePressEvent函數,其實類似這樣的函數是系統提供的,有點類似MFC中的消息響應機制,在該函數中發出信號即可。這樣當鼠標按下時,就發出了一個clicked()的信號,然后在主界面中響應該信號對應的槽函數就ok了。

    當要使用新建的MyTextBrowser類代替原先的QTextBrowser時,只需打開.ui設計文件,在Object欄中找到對應的object,然后右鍵選擇進入Promoted Widgets,add一個MyTextBrwoser即可。

  3. int getOptimalDFTSize(int vecsize)

    該函數是為了獲得進行DFT計算的最佳尺寸。因為在進行DFT時,如果需要被計算的數字序列長度vecsize2n次冪的話,那么其運行速度是非常快的。如果不是2n次冪,但能夠分解成2,3,5的乘積,則運算速度也非常快。這里的getOptimalDFTSize()函數就是為了獲得滿足分解成2,3,5的最小整數尺寸。很顯然,如果是多維矩陣需要進行DFT,則每一維單獨用這個函數獲得最佳DFT尺寸。

  4. void copyMakeBorder(InuptArray src, OutputArray dst, int top , int bottom, int left, int right, int borderType, const Scalar& value=Scalar())

    該函數是用來擴展一個圖像的邊界的,第36個參數分別為原始圖像的上下左右各擴展的像素點的個數,第7個參數表示邊界的類型,如果其為BORDER_CONSTANT,則擴充的邊界像素值則用第8個參數來初始化。將src圖像擴充邊界后的結果保存在dst圖像中。

  5. merge()函數是把多個但通道數組連接成1個多通道數組,而split()函數則相反,把1個多通道函數分解成多個但通道函數。

  6. Void magnitude(InputArray x, InputArray y, OutPutArray magnitude)

    該函數是計算輸入矩陣xy對應該的每個像素平方求和后開根號保存在輸出矩陣magnitude中。

  7. 函數log(InputArray src, OutputArray dst)是對輸入矩陣src中每個像素點求log,保存在輸出矩陣dst的相對應的位置上。

  8. 因為Qt中顯示圖片,如果圖片類型為亮度圖像,即其像素值為01之間,則顯示出來的是全黑的圖像。所以為了似圖片顯示正常,必須全部擴大255被,使之在0255之間。當然了,如果是opencv自帶的imshow()函數,對於這樣的值在01之間圖像它會自動識別,並且有個術語稱之為亮度圖像。

     

  實驗結果:

  打開一張圖片,並灰度顯示如下:

  

 

 

  DFT中間結果圖,未重新排列的效果:

  

 

 

  DFT最終排列后的效果圖:

  

 

  

 

 

  如果沒有打開圖片單擊圖片顯示區域,提示如下:

  

 

 

實驗主要部分代碼及其注釋(附錄有工程code下載鏈接地址)

MainWindo.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <iostream>
#include <QFileDialog>

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->textBrowser->setFont( QFont("Times New Roman", 30) );

    display_num = 0;
    QObject::connect( ui->textBrowser, SIGNAL(clicked()), this, SLOT(on_mytextBrowser_clicked()) );
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_openButton_clicked()
{
    /*讀入圖片並顯示,將圖片以灰度形式讀入*/
    QString img_name = QFileDialog::getOpenFileName( this, "Open Image", "../dft", tr("Image Files(*.png *.jpg *.bmp *.jpeg)") );
    src = imread( img_name.toAscii().data(), CV_LOAD_IMAGE_GRAYSCALE );
    src.copyTo( src_1 );
    //
    putText( src_1, "The original image:", Point(0, 50), 2, 1, Scalar::all(0), 2 );
    imwrite( "../dft/src_1.jpg", src_1 );
    ui->textBrowser->setFixedHeight( src.rows );
    ui->textBrowser->setFixedWidth( src.cols );
    ui->textBrowser->clear();
    ui->textBrowser->append( "<img src=../dft/src_1.jpg>" );

    display_num = 1;
}

void MainWindow::on_closeButton_clicked()
{
    close();
}

void MainWindow::on_mytextBrowser_clicked()
{
    display_num ++;

    //擴展成為DFT最佳運算尺寸;
    Mat padded;
    int opw = getOptimalDFTSize( src.cols );
    int oph = getOptimalDFTSize( src.rows );
    copyMakeBorder( src, padded, 0, oph-src.rows, 0, opw-src.cols, BORDER_CONSTANT, Scalar::all(0) );

    //為計算出的虛數增加1個通道
    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexI;
    merge( planes, 2, complexI );

    dft( complexI, complexI );//支持圖像原地計算,調用opencv的dtf函數進行DFT計算

    //得到賦值圖像,取了對數
    split( complexI, planes );
    magnitude( planes[0], planes[1], planes[0] );
    Mat log_img = planes[0];
    log_img += Scalar::all(1);
    cv::log( log_img, log_img );
    log_img = log_img(Rect(0, 0, log_img.cols & -2, log_img.rows & -2 ));

    //DFT結果
    dst = log_img.clone();
    cv::normalize( dst, dst, 0, 1, CV_MINMAX );
    dst =  255.*dst;

    if( 1 == display_num )
    {
        if( src.empty() )
        {
            ui->textBrowser->setTextColor( Qt::red );
            ui->textBrowser->append("Please open one image first!");
        }
        else
        {
            ui->textBrowser->clear();
            ui->textBrowser->append( "<img src =../dft/src_1.jpg>");
        }
    }
    else if( 2 == display_num )
    {
        /*7. 因為Qt中顯示圖片,如果圖片類型為亮度圖像,即其像素值為0~1之間,則顯示出來的是全黑的圖像。
         *所以為了似圖片顯示正常,必須全部擴大255被,使之在0~255之間。當然了,如果是opencv自帶的imshow()函數,
         *對於這樣的值在0~1之間圖像它會自動識別,並且有個術語稱之為亮度圖像。*/
        dst.copyTo( dst_1 );
        putText( dst_1, "DFT without rearranged image:", Point(0, 50), 3, 0.8, Scalar::all(0), 2 );

        imwrite( "../dft/dst_1.jpg", dst_1 );
        ui->textBrowser->clear();
        ui->textBrowser->append( "<img src=../dft/dst_1.jpg>" );
    }
    else if( 3 == display_num )
    {
        display_num = 0;//原圖,dft未調整圖,dft調整圖3幅圖片進行輪流切換。

        dst.copyTo( dst_2 );
        int cx = dst_2.cols/2;
        int cy = dst_2.rows/2;
        Mat q0( dst_2, Rect(0, 0, cx, cy) );
        Mat q1( dst_2, Rect(cx, 0, cx, cy) );
        Mat q2( dst_2, Rect(0, cy, cx, cy) );
        Mat q3( dst_2, Rect(cx, cy, cx, cy) );

        Mat temp;
        //因為是共用數據的,所以下面的q0,q1,q2,q3的改變也會導致dst_2的改變。
        q0.copyTo( temp );
        q3.copyTo( q0 );
        temp.copyTo( q3 );

        q1.copyTo( temp );
        q2.copyTo( q1 );
        temp.copyTo( q2 );

        putText( dst_2, "DFT with rearranged image", Point(0, 50), 1, 2, Scalar::all(0), 2, 8 );
        imwrite( "../dft/dst_2.jpg", dst_2 );
        ui->textBrowser->clear();
        ui->textBrowser->append( "<img src=../dft/dst_2.jpg>" );
    }

}

 

 

mytextbrowser.cpp:

#include "mytextbrowser.h"

MyTextBrowser::MyTextBrowser(QWidget *parent) :
    QTextBrowser(parent)
{
    this->setMouseTracking( true );
}

void MyTextBrowser::mousePressEvent(QMouseEvent *ev)
{
 //   this->setCursor( Qt::PointingHandCursor );//設置光標的形狀為手型。但感覺貌似不起作用
    emit this->clicked();
}

void MyTextBrowser::mouseMoveEvent(QMouseEvent *ev)
{
  //  this->setCursor( Qt::SizeAllCursor );//設置光標的形狀為手型。
}

 

  實驗總結:

  通過本次實驗,對Qt中的信號與槽機制有了更深入的認識。另外對圖像的DFT計算有了進一步的理解。


  附:工程code下載

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM