openCV的fftshift c ++实现

时间:2015-03-24 06:44:58

标签: c++ matlab opencv image-processing

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

我正在尝试从matlab实现 fftshift

这是来自matlab 函数的代码,用于1D数组

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<float>我似乎无法创建平面垫以分割复数?

你能想到如何在cv :: mat数据结构中交换值的更好方法吗?

6 个答案:

答案 0 :(得分:3)

好的,这个帖子可能在此期间过时了,但也许对其他用户来说..看看样本:

  

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);

我认为对于不同的维度来说,这是一种简短而干净的方式。

答案 1 :(得分:1)

如何使用adjustROI和copyTo代替.at()?它肯定会更有效率:

(1D案例)中的某些内容:

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情况,应添加另外两行,并修改行范围......

答案 2 :(得分:1)

我知道,这是一个很旧的线程,但是我今天在寻找解决方法来转移fft结果时发现了它。也许我在此站点和其他资源的帮助下编写的小功能可能对将来的读者搜索网络并最终在这里有用。

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 :(得分:0)

这是为了将来参考: 经过测试,对于1D

有点准确
    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;

答案 4 :(得分:0)

我一直在根据这篇文章实现它,我使用了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;

答案 5 :(得分:-1)

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

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

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