圖像的二維頻譜圖的理解 20170622


# 1 圖像二維頻譜長什么樣子(左圖是原圖,右圖是對應的頻譜圖)

 

(圖片來源:第一組是來自matlab自帶的圖片 “cameraman.tif”;第二組是用 excel 畫的,然后截圖)

 

# 2 怎么獲得(matlab和C++調用)

  • matlaba代碼,保存為 spectrum2D.m 
function [Result] = spectrum2D(I)
% I is a gray image
% 'Input Image should be gray!' A = rgb2gray(I);

A = I; % A 要是一個灰度圖像
F = fftshift(fft2(A)); % fft2() 是快速傅里葉變換函數
                       % fftshift() 目的是為了將圖像橫縱划分成四塊,對角線互換。
                       % 經過變換以后的圖像 F 中心是低頻,往外頻率增大。

% 以下的操作是為獲得可以顯示的圖像。
% 如果直接顯示 F ,得到的很可能是一個全白的圖。
% 原因是,F內像素的值一般都很大,遠大於255.
% 而matlab的imshow函數黑白對應0-255,所以不做歸一化處理的圖像,顯示都是白色的。

B = abs(real(F)); % F 有可能是負值,而且數據是中心對稱的,中心為最亮點(可以參考C++例程中的說明)
[m, n] = size(B); % 獲得行數、列數
R = reshape(B, 1, m*n); % 將B映射成1行m*n列的矩陣
Temp = mapminmax(R, 0, 255); % 將R的像素值歸一化到0-255之間
Result = reshape(Temp, m, n); 

% imshow(Result); % 建議調用的時候使用:imshow(spectrum2D(灰度圖像矩陣))
                  % imshow(spectrum2D( rgb2gray(RGB圖像矩陣)))

end

(以上三幅圖,分別對應代碼中的:A、F、Result)

 

抱着折騰的心態,我們把matlab的這個函數在opencv里面試着來玩一下~~不感興趣的可以跳過。

使用opencv來調用matlab的目的在於可以方便的移植,而且方便我們可以數據進行處理;

  比如這后面要做的峰點濾波,使得亮點更加明顯。(為什么要這樣做呢,那就要理解亮點的含義才可以,接着往下看。)

主要思路:1 使用matlab生成dll;2 在opencv環境中調用dll

  • matlab生成dll
mex -setup
mbuild -setup
# mcc -W cpplib:名字  -T link:lib matlab文件.m
mcc -W cpplib:spectrum2D -T link:lib spectrum2D.m
  • 調用opencv
// Spectrum2D.cpp : 定義控制台應用程序的入口點。
// 配置手順:
// 1. vs2015(工程屬性設置為64bit)+opencv320,64 bit windows,配置好(不懂得話去網上搜吧,很容易)。
// 2. 加載matlab生產的dll、頭文件、lib,不需要cpp。(不懂得話,百度搜“怎么加載dll”)
// 3. 上步的頭文件應該會提示 mclmcrrt.h mclcppclass.h找不到,這是matlab安裝目錄下的文件,加載到(屬性->VC++ ->包含目錄)
// 4. 加載matlab庫文件 mclmcrrt.lib mclmcr.lib
//      (屬性->VC++ ->庫目錄)路徑:MATLAB2013a\extern\lib\win64\microsoft
// 
// 作者:路邊的十元錢硬幣
// 時間:20170630
// 最后的話,做注釋可以的話,最好還是英文,因為vs平台,漢字注釋有可能會造成編譯錯誤。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include "spectrum2D.h"

/// mwArray 是matlab用的數據類型,不論是矩陣還是數字,當需要作為參數傳遞到matlab生產的函數中時,要轉化成這種數據類型
/// 使用方法見代碼
mwArray Mat2mwArray(cv::Mat src)
{
    CV_Assert(src.type() == CV_8UC1);

    mwArray dst(src.rows, src.cols, mxUINT8_CLASS); /// 初始化,可以理解成矩陣
    cv::Mat src_t = src.t();
    dst.SetData(src_t.data, src.rows*src.cols); /// 賦值

    return dst;
}

cv::Mat mwArry2Mat(mwArray src, int rows, int cols)
{
    if(src.IsEmpty()) /// 是否為空
        return cv::Mat();

    cv::Mat dst = cv::Mat::zeros(rows, cols, CV_64FC1);
    for(int j(0); j<rows; ++j)
    {
        double* pdata = dst.ptr<double>(j);
        for(int i(0); i<cols; ++i)
        {
            pdata[i] = src(j+1,i+1); /// 元素訪問(行號,列號)
        }
    }
    
    return dst;    
}



int _tmain(int argc, _TCHAR* argv[])
{
    cv::Mat src = cv::imread("1.JPG", CV_LOAD_IMAGE_GRAYSCALE);
    cv::imshow("src", src);

    /// matlab mwArray 初始化,必須要做,不然報錯
    if( !spectrum2DInitialize())
    {
        std::cout << "Could not initialize!" << std::endl;
        return -1; 
    }

    mwArray mlImg = Mat2mwArray(src);
    mwArray mlResult ;

    spectrum2D(1,mlResult, mlImg);

    /**
    簡單說下mwArray的用法:
    mwArray a_int_varible(1, 1, mxINT8_CLASS); /// 定義
    mwArray a_double_varible(1, 1, mxDOUBLE_CLASS);

    a_int_varible(1,1) = 10; /// 賦值
    a_double_varible(1,1) = 10.0;

    int a = a_int_varible(1,1);

    **/

    cv::Mat result = mwArry2Mat(mlResult, src.rows, src.cols);

    cv::imshow("FFT2", result);
    cv::waitKey(0);

    return 0;
}

設置斷點可以查看result矩陣中的數值。

vs需要安裝插件 Image Watch

 原圖是#1中的第二組圖,這是其對應頻譜的中心亮點的局部放大圖。其中255是中心亮點,6.8616是次亮點,注意左右是對稱的。

規律一:中心是最大亮點

規律二:次亮點6.8616到255的距離是6,正好等於#1第二組圖黑白條紋的重復次數。這不是巧合

 

# 3 圖的含義

  • 先看黑白條紋的圖,把圖像想象成波浪,將像素點值當成起伏高度,於是獲得一個水平往右(往左也無所謂)傳播的“黑色波浪”。
  • 在一維中,一條曲線可以被表示成很多不同頻率的sin或者cos的疊加。(要問為什么的話,百度搜搜傅里葉變換相關的東西。)注意,這里的sin或者cos是二維波,只是線(y=sin(x)的圖像)

  • 類似的,在圖像中,每個“波浪”也可以被表示成很多不同頻率的sin或者cos的疊加。注意,這里的sin或者cos函數是三維波,是曲面(y=sin(x),z=任意數)(波浪)

  • 想象一幅擁有最大頻率波浪的圖應該是什么樣的,看圖。

是不是應該到最后,黑或者白條紋的寬度=1個像素?對的。這就是一幅圖頻率的極限。

所以,得到重要結論:

  • 頻譜圖的中心亮點,是0頻率點。往外,頻率增大;同一圓周上的點,頻率相同。
  • 頻譜圖的x軸的最右邊點(無論是不是亮點),表示圖像水平方向上的最大頻率(波長是2個像素)。
  • 頻譜圖的任意點A到中心點O的距離|OA|表示頻率

  大家應該是有疑惑的,就是這里的關於“頻率”的理解。這里說到的“頻率”,可以理解成條紋出現的次數,看下圖說明。

 

    上圖藍色的為頻譜圖區域。其上的點A到中心點O的距離|AO|(單位像素),表示波的頻率w=|OA|;其A點的像素值,表示圖像中該方向(矢量OA的方向)上,頻率為|AO|的比重(這里說比重而不說數量,因為頻譜圖的點的像素值只是響應值,只能用於對比多少。而且一般需要歸一化。談相差比例才有意義)

 

  • 總結:

頻譜圖上任意點A,中心點O,A點像素值PA

A點的含義是:原圖像上,(矢量OA)方向上的,頻率為|OA|的平面波的“比重”是PA。

 

 

# 4 圖的作用

|OA| = 對應A點的波浪在原圖上出現的次數。

濾去某些噪聲等。

 

能力有限,錯誤或不全之處請不吝賜教。

路邊的十元錢硬幣

end.

 


免責聲明!

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



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