OpenCV C++使用傅里叶谱和相角重建图像

关于傅里叶谱和相角的进一步说明:

在频域下,原始图像经过dft变换后,可得到两个矩阵,分别是复数的实部和虚部;Z=A+Bi

在复数坐标系下,某一点像素可由值和角度表示;

如果只保留相角信息,则只需将r=1,即实部和虚部同时缩小r倍;

如果只保留幅值信息,则只需将a值和b值同时设置为r/\sqrt{2}  都设置为45,135,225,315度

如果使用图像a的幅值图像b的相角,则按下图计算

distance1=\sqrt{r1^{2} + i1^{2}}

distance2=\sqrt{r2^{2} + i2^{2}}

distance1/distance2 = r/r2 = i/i2

同理,用a的相位和b的幅值亦可得到;

按照书中妇女图像4.27和白色矩形4.24(上篇文章实验图片)实验

4.27妇女原图和相位图                                             

使用幅值和相角分别重建图像:

使用妇女的相角和矩形的谱   -------    矩形的相角和妇女的谱   分别重建图像:

由此可见:

相角是描述图像中关键的形状特性的;谱(幅值)是描述图像灰度信息的

 

代码实现:

#include "opencv2/opencv.hpp"

using namespace cv;

//将幅度归一,相角保持不变
void one_amplitude(Mat &complex_r, Mat &complex_i, Mat &dst )
{
    Mat temp[] = {Mat::zeros(complex_r.size(),CV_32FC1), Mat::zeros(complex_r.size(),CV_32FC1)};
    float realv=0.0,imaginv=0.0;
    for(int i=0;i<complex_r.cols;i++){
        for( int j = 0; j < complex_r.rows; j++ ){
            realv   = complex_r.at<float>(i,j);
            imaginv = complex_i.at<float>(i,j);
            float distance=sqrt(realv*realv+imaginv*imaginv);
            temp[0].at<float>(i,j) =realv/distance;
            temp[1].at<float>(i,j) =imaginv/distance;
        }
    }
    merge(temp, 2, dst);
}

//将相角归一,幅值保持不变
void one_angel(Mat &complex_r, Mat &complex_i, Mat &dst)
{
    Mat temp[] = {Mat::zeros(complex_r.size(),CV_32FC1), Mat::zeros(complex_r.size(),CV_32FC1)};
    float realv=0.0,imaginv=0.0;
    for(int i=0;i<complex_r.cols;i++){
        for( int j = 0; j < complex_r.rows; j++ ){
            realv   = complex_r.at<float>(i,j);
            imaginv = complex_i.at<float>(i,j);
            float distance=sqrt(realv*realv+imaginv*imaginv);
            temp[0].at<float>(i,j) =distance/sqrt(2);
            temp[1].at<float>(i,j) =distance/sqrt(2);
        }
    }
    merge(temp, 2, dst);
}

//使用1的幅值和2的相位合并
void mixed_amplitude_with_phase(Mat &real1, Mat &imag1, Mat &real2, Mat &imag2, Mat &dst)
{
    if(real1.size() != real2.size() ){
        std::cerr << "image don't ==" << std::endl;
        return;
    }
    Mat temp[] = {Mat::zeros(real1.size(),CV_32FC1), Mat::zeros(real1.size(),CV_32FC1)};
    float realv1=0.0, imaginv1=0.0, realv2=0.0, imaginv2=0.0;
    for(int i=0;i<real1.cols;i++){
        for( int j = 0; j < real1.rows; j++ ){
            realv1   = real1.at<float>(i,j);
            imaginv1 = imag1.at<float>(i,j);
            realv2   = real2.at<float>(i,j);
            imaginv2 = imag2.at<float>(i,j);
            float distance1=sqrt(realv1*realv1+imaginv1*imaginv1);
            float distance2=sqrt(realv2*realv2+imaginv2*imaginv2);
            temp[0].at<float>(i,j) =(realv2*distance1)/distance2;
            temp[1].at<float>(i,j) =(imaginv2*distance1)/distance2;
        }
    }
    merge(temp, 2, dst);
}

//使用1的相位和2的幅值合并
void mixed_phase_with_amplitude(Mat &real1, Mat &imag1, Mat &real2, Mat &imag2, Mat &dst)
{
    if(real1.size() != real2.size() ){
        std::cerr << "image don't ==" << std::endl;
        return;
    }
    Mat temp[] = {Mat::zeros(real1.size(),CV_32FC1), Mat::zeros(real1.size(),CV_32FC1)};
    float realv1=0.0, imaginv1=0.0, realv2=0.0, imaginv2=0.0;
    for(int i=0;i<real1.cols;i++){
        for( int j = 0; j < real1.rows; j++ ){
            realv1   = real1.at<float>(i,j);
            imaginv1 = imag1.at<float>(i,j);
            realv2   = real2.at<float>(i,j);
            imaginv2 = imag2.at<float>(i,j);
            float distance1=sqrt(realv1*realv1+imaginv1*imaginv1);
            float distance2=sqrt(realv2*realv2+imaginv2*imaginv2);
            temp[0].at<float>(i,j) =(realv1*distance2)/distance1;
            temp[1].at<float>(i,j) =(imaginv1*distance2)/distance1;
        }
    }
    merge(temp, 2, dst);
}

cv::Mat fourior_inverser( Mat &_complexim )
{
    Mat dst;
    Mat iDft[]={Mat::zeros(_complexim.size(),CV_32F),Mat::zeros(_complexim.size(),CV_32F)};//创建两个通道,类型为float,大小为填充后的尺寸
    idft(_complexim,_complexim);//傅立叶逆变换
    split(_complexim,iDft);//结果貌似也是复数
    magnitude(iDft[0],iDft[1],dst);//分离通道,主要获取0通道
//    dst += Scalar::all(1);                    // switch to logarithmic scale
//    log(dst, dst);
    //归一化处理,float类型的显示范围为0-255,255为白色,0为黑色
    normalize(dst, dst, 0, 255, NORM_MINMAX);
    dst.convertTo(dst, CV_8U);
    return dst;
}

void move_to_center( Mat &center_img)
{
    int cx = center_img.cols/2;
    int cy = center_img.rows/2;
    Mat q0(center_img, Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
    Mat q1(center_img, Rect(cx, 0, cx, cy));  // Top-Right
    Mat q2(center_img, Rect(0, cy, cx, cy));  // Bottom-Left
    Mat q3(center_img, Rect(cx, cy, cx, cy)); // Bottom-Right

    Mat tmp;                           // swap quadrants (Top-Left with Bottom-Right)
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);

    q1.copyTo(tmp);                    // swap quadrant (Top-Right with Bottom-Left)
    q2.copyTo(q1);
    tmp.copyTo(q2);
}

void fast_dft( cv::Mat &src_img, cv::Mat &real_img, cv::Mat &ima_img  )
{
    src_img.convertTo(src_img,CV_32FC1);

    ///////////////////////////////////////快速傅里叶变换/////////////////////////////////////////////////////
    int oph = getOptimalDFTSize(src_img.rows);
    int opw = getOptimalDFTSize(src_img.cols);
    Mat padded;
    copyMakeBorder(src_img, padded, 0, oph-src_img.rows, 0, opw-src_img.cols,
                   BORDER_CONSTANT, Scalar::all(0));

    Mat temp[] = {padded, Mat::zeros(padded.size(),CV_32FC1)};
    Mat complexI;
    merge(temp, 2, complexI);
    dft(complexI, complexI);    //傅里叶变换
    split(complexI, temp);      //显示频谱图
    temp[0].copyTo(real_img);
    temp[1].copyTo(ima_img);
}

int main( int argc, char *argv[] )
{
    const char* filename = argc >=2 ? argv[1] : "427.tif";

    Mat image = imread( filename, IMREAD_GRAYSCALE);
    Mat image2 = imread( "424.tif", IMREAD_GRAYSCALE);
    if( image.empty() || image2.empty())
        return -1;
    imshow("woman_src",image);
    resize( image2, image2, cv::Size(), 0.5, 0.5);
    imshow("sqrt_src",image2);

    Mat woman_real, woman_imag;
    Mat sqrt_real, sqrt_imag;

    fast_dft( image, woman_real, woman_imag );
    fast_dft( image2, sqrt_real, sqrt_imag );

    Mat img_range, img_angle;
    one_amplitude(woman_real, woman_imag, img_range );        //原图像的幅值归一化
    one_angel(woman_real, woman_imag, img_angle );            //原图像的相位归一化

    Mat woman_amp2sqrt_angle, sqrt_amp2woman_angle;
    mixed_amplitude_with_phase(woman_real,woman_imag,
                               sqrt_real,  sqrt_imag, woman_amp2sqrt_angle);
    mixed_phase_with_amplitude(woman_real,woman_imag,
                               sqrt_real,  sqrt_imag, sqrt_amp2woman_angle);
    Mat amplitude, angle, amplitude_src;
    magnitude(woman_real, woman_imag, amplitude);             //计算原图像幅值
    phase(woman_real, woman_imag, angle);                     //计算原图像相位
//    cartToPolar(temp[0], temp[1],amplitude, angle);

    move_to_center(amplitude);                                //幅值亮度集合到中心

    divide(amplitude, amplitude.cols*amplitude.rows, amplitude_src );
    imshow("amplitude_src",amplitude_src);

    amplitude += Scalar::all(1);                    // switch to logarithmic scale
    log(amplitude, amplitude);
    normalize(amplitude, amplitude, 0, 255, NORM_MINMAX); //归一化 方便显示,和实际数据没有关系
    amplitude.convertTo(amplitude, CV_8U);
    imshow("amplitude",amplitude);

    normalize(angle, angle, 0, 255, NORM_MINMAX); //归一化 方便显示,和实际数据没有关系
    angle.convertTo(angle, CV_8U);
    imshow("angle",angle);

//*******************************************************************

    Mat inverse_amp = fourior_inverser(img_range);      //傅里叶逆变换
    Mat inverse_angle= fourior_inverser(img_angle);
    Mat inverse_dst1 = fourior_inverser(woman_amp2sqrt_angle);
    Mat inverse_dst2 = fourior_inverser(sqrt_amp2woman_angle);
    move_to_center(inverse_angle);
    imshow("inverse_angle", inverse_amp);
    imshow("inverse_amp", inverse_angle);
    imshow("woman_amp2sqrt_angle", inverse_dst1);
    imshow("sqrt_amp2woman_angle", inverse_dst2);

    imwrite("phase.jpg", angle);
    waitKey(0);

    return 1;
}

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/88231590