【问题标题】:fftshift c++ implemetation for openCVopenCV的fftshift c ++实现
【发布时间】:2015-05-27 09:36:19
【问题描述】:

我已经看过这个问题了 fftshift/ifftshift C/C++ source code

我正在尝试从 matlab 实现 fftshift

这是一维数组的代码来自 matlab 函数

numDims = ndims(x);
    idx = cell(1, numDims);
    for k = 1:numDims
        m = size(x, k);
        p = ceil(m/2);
        idx{k} = [p+1:m 1:p];
    end
y = x(idx{:});

我的 c++/openCV 代码是,fftshift 基本上做的是交换某个枢轴位置的值。
因为我似乎无法理解如何在 opencv 中为复数构建矩阵。
这里说
http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#dft
CCS(复共轭对称
我认为将复数拆分为实数和虚数并交换它们会更容易。然后合并回一个矩阵。

cv::vector<float> distanceF (f.size());

//ff = fftshift(ff);
cv::Mat ff;
cv::dft(distanceF, ff, cv::DFT_COMPLEX_OUTPUT);

//Make place for both the complex and the real values
cv::Mat planes[] = {cv::Mat::zeros(distanceF.size(),1, CV_32F), cv::Mat::zeros(distanceF.size(),1, CV_32F)};
cv::split(ff, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))

int numDims = ff.dims;
for (int i = 0; i < numDims; i++)
{
    int m = ff.rows;
    int p = ceil(m/2);

}

我的问题是,由于我对 DFT 的输入是 vector&lt;float&gt;,我似乎无法创建平面垫来拆分复数?

你能想出一种更好的方法来交换 cv::mat 数据结构中的值吗?

【问题讨论】:

    标签: c++ matlab opencv image-processing


    【解决方案1】:

    这是我做的(又快又脏,可以优化):

    // taken from the opencv DFT example (see opencv/samples/cpp/dft.cpp within opencv v440 sourcecode package)
    cv::Mat fftshift(const cv::Mat& mat){
        
        // create copy to not mess up the original matrix (ret is only a "window" over the provided matrix)
        cv::Mat cpy;
        mat.copyTo(cpy);
    
        // crop the spectrum, if it has an odd number of rows or columns
        cv::Mat ret = cpy(cv::Rect(0, 0, cpy.cols & -2, cpy.rows & -2));
    
        // rearrange the quadrants of Fourier image so that the origin is at the image center
        int cx = ret.cols/2;
        int cy = ret.rows/2;
        cv::Mat q0(ret, cv::Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
        cv::Mat q1(ret, cv::Rect(cx, 0, cx, cy));  // Top-Right
        cv::Mat q2(ret, cv::Rect(0, cy, cx, cy));  // Bottom-Left
        cv::Mat q3(ret, cv::Rect(cx, cy, cx, cy)); // Bottom-Right
    
        cv::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);
    
        return ret;
    }
    
    // reverse the swapping of fftshift. (-> reverse the quadrant swapping)
    cv::Mat ifftshift(const cv::Mat& mat){
    
        // create copy to not mess up the original matrix (ret is only a "window" over the provided matrix)
        cv::Mat cpy;
        mat.copyTo(cpy);
    
        // crop the spectrum, if it has an odd number of rows or columns
        cv::Mat ret = cpy(cv::Rect(0, 0, cpy.cols & -2, cpy.rows & -2));
    
        // rearrange the quadrants of Fourier image so that the origin is at the image center
        int cx = ret.cols/2;
        int cy = ret.rows/2;
        cv::Mat q0(ret, cv::Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
        cv::Mat q1(ret, cv::Rect(cx, 0, cx, cy));  // Top-Right
        cv::Mat q2(ret, cv::Rect(0, cy, cx, cy));  // Bottom-Left
        cv::Mat q3(ret, cv::Rect(cx, cy, cx, cy)); // Bottom-Right
    
        cv::Mat tmp; // swap quadrants (Bottom-Right with Top-Left)
        q3.copyTo(tmp);
        q0.copyTo(q3);
        tmp.copyTo(q0);
        q2.copyTo(tmp); // swap quadrant (Bottom-Left with Top-Right)
        q1.copyTo(q2);
        tmp.copyTo(q1);
    
        return ret;
    }
    

    【讨论】:

      【解决方案2】:

      我知道,这是一个相当古老的线程,但我今天在寻找改变 fft-result 的解决方案时发现了它。也许我在这个网站和其他资源的帮助下编写的这个小功能,可能对未来的读者搜索网络并最终来到这里有所帮助。

      bool FftShift(const Mat& src, Mat& dst)
      {
        if(src.empty()) return true;
      
        const uint h=src.rows, w=src.cols;        // height and width of src-image
        const uint qh=h>>1, qw=w>>1;              // height and width of the quadrants
      
        Mat qTL(src, Rect(   0,    0, qw, qh));   // define the quadrants in respect to
        Mat qTR(src, Rect(w-qw,    0, qw, qh));   // the outer dimensions of the matrix.
        Mat qBL(src, Rect(   0, h-qh, qw, qh));   // thus, with odd sizes, the center
        Mat qBR(src, Rect(w-qw, h-qh, qw, qh));   // line(s) get(s) omitted.
      
        Mat tmp;
        hconcat(qBR, qBL, dst);                   // build destination matrix with switched
        hconcat(qTR, qTL, tmp);                   // quadrants 0 & 2 and 1 & 3 from source
        vconcat(dst, tmp, dst);
      
        return false;
      }
      

      【讨论】:

        【解决方案3】:

        我一直根据这篇文章自己实现它,我使用了运行良好的 Fabian 实现。但是当存在奇数行或奇数列时,就会出现移位不正确的问题。

        然后您需要填充矩阵,然后删除多余的行或列。

           {bool flag_row = false;
            bool flag_col = false;
        
            if( (inputMatrix.rows % 2)>0)
            {
                cv::Mat row = cv::Mat::zeros(1,inputMatrix.cols, CV_64F);  
                inputMatrix.push_back(row);
                flag_row =true;
            }
        
            if( (inputMatrix.cols % 2)>0)
            {
                cv::Mat col = cv::Mat::zeros(1,inputMatrix.rows, CV_64F);  
                cv::Mat tmp;
                inputMatrix.copyTo(tmp);
                tmp=tmp.t();
                tmp.push_back(col);
                tmp=tmp.t();
                tmp.copyTo(inputMatrix);
        
                flag_col = true;
            }
        
            int cx = inputMatrix.cols/2.0;
            int cy = inputMatrix.rows/2.0;
        
            cv::Mat outputMatrix;
            inputMatrix.copyTo(outputMatrix);
        
            // rearrange the quadrants of Fourier image
            // so that the origin is at the image center
            cv::Mat tmp;
            cv::Mat q0(outputMatrix, cv::Rect(0, 0, cx, cy));
            cv::Mat q1(outputMatrix, cv::Rect(cx, 0, cx, cy));
            cv::Mat q2(outputMatrix, cv::Rect(0, cy, cx, cy));
            cv::Mat q3(outputMatrix, cv::Rect(cx, cy, cx, cy));
        
            q0.copyTo(tmp);
            q3.copyTo(q0);
            tmp.copyTo(q3);
        
            q1.copyTo(tmp);
            q2.copyTo(q1);
            tmp.copyTo(q2);
        
            int row = inputMatrix.rows;
            int col = inputMatrix.cols;
            if(flag_row)
            {
                outputMatrix = Tools::removerow(outputMatrix,row/2-1);
            }
            if(flag_col)
            {
                outputMatrix = Tools::removecol(outputMatrix,col/2-1);
            }
        
            return outputMatrix;
        

        【讨论】:

          【解决方案4】:

          好的,这个帖子可能已经过时了,但可能对其他用户..看看示例:

          opencv/samples/cpp/dft.cpp(第 66 - 80 行)

          int cx = mag.cols/2;
          int cy = mag.rows/2;
          
          // rearrange the quadrants of Fourier image
          // so that the origin is at the image center
          Mat tmp;
          Mat q0(mag, Rect(0, 0, cx, cy));
          Mat q1(mag, Rect(cx, 0, cx, cy));
          Mat q2(mag, Rect(0, cy, cx, cy));
          Mat q3(mag, Rect(cx, cy, cx, cy));
          
          q0.copyTo(tmp);
          q3.copyTo(q0);
          tmp.copyTo(q3);
          
          q1.copyTo(tmp);
          q2.copyTo(q1);
          tmp.copyTo(q2);
          

          我认为对于不同的维度来说,这是一种简洁明了的方式。

          【讨论】:

          • 如果图片大小奇数,可能会漏掉一列一行
          【解决方案5】:

          使用 adjustROI 和 copyTo 代替 .at() 怎么样?它肯定会更有效:

          类似于(对于您的一维案例):

          Mat shifted(ff.size(),ff.type());
          pivot = ff.cols / 2;
          ff(Range::all(),Range(pivot + 1, ff.cols)).copyTo(shifted(Range::all(),Range(0,pivot)));
          ff(Range::all(),Range(0,pivot+1)).copyTo(shifted(Range::all(),Range(pivot,ff.cols)));
          

          对于 2D 的情况,应该再添加两行,并修改行范围...

          【讨论】:

            【解决方案6】:

            在Matlab的实现中,主要代码有两行:

            idx{k} = [p+1:m 1:p];
            y = x(idx{:});
            

            第一个相对于原始的获得正确的索引顺序;然后第二个根据索引顺序分配输出数组。因此,如果要在不进行数据交换的情况下重新编写Matlab的实现,则需要分配一个新数组并分配该数组。

            【讨论】:

              【解决方案7】:

              这是供将来参考: 已经过测试,对于一维来说有点准确

                  cv::Mat ff;
                  cv::dft(distanceF, ff, cv::DFT_ROWS|cv::DFT_COMPLEX_OUTPUT);
              
                  //Make place for both the complex and the real values
                  cv::Mat planes[] = {cv::Mat::zeros(distanceF.size(),1, CV_32F), cv::Mat::zeros(distanceF.size(),1, CV_32F)};
                  cv::split(ff, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
              
                  int m = planes[0].cols;
                  int pivot = ceil(m/2);
                  //duplicate FFT results with Complex conjugate in order to get exact matlab results
              
                  for (int i = pivot + 1, k = pivot; i < planes[1].cols; i++, k--)
                  {
                       planes[1].at<float>(i) = planes[1].at<float>(k) * -1; 
                       planes[0].at<float>(i) = planes[0].at<float>(k);
                  }   
              
                  //TODO maybe we need to see what happens for pair and odd ??
                  float im  = planes[1].at<float>(0);
                  float re = planes[0].at<float>(0);
              
                  for (int i = 0; i < pivot; i++)
                  {   
                      //IM
                      planes[1].at<float>(i) = planes[1].at<float>(pivot + i +1); 
                      planes[1].at<float>(pivot +i +1) = planes[1].at<float>(i +1);
              
                      //Real
                      planes[0].at<float>(i) = planes[0].at<float>(pivot + i +1); 
                      planes[0].at<float>(pivot +i +1) = planes[0].at<float>(i +1);
                  }
                  planes[1].at<float>(pivot) = im;
                  planes[0].at<float>(pivot) = re;
              

              【讨论】:

              • 用adjustROI和copyTo代替.at()怎么样?它肯定会更有效 - 请参阅下面的答案。 (虽然它不处理共轭)
              猜你喜欢
              • 2017-06-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-02-12
              • 2019-11-25
              • 2015-03-16
              • 1970-01-01
              • 2014-07-02
              相关资源
              最近更新 更多