解决低FPS的相关代码以计算图像中的偏移

时间:2018-10-11 06:47:44

标签: c++ image-processing correlation cross-correlation

我正在尝试使用相关性跟踪对象。我正在逐帧显示较大图像中的较小补丁。为此,我正在寻找补丁的变化,并且在相关性最大的地方,用新的补丁更新补丁。

我的代码是:

cv::Mat im_float_2,imagePart_out;
cv::Mat im_floatBig;
cv::Scalar im1_Mean, im1_Std, im2_Mean, im2_Std;

double covar, correl;
int n_pixels;

void computeShift()
{
    int maxRow=0, maxCol=0, TX, TY;
    double GMAX=0;
    Mat image_window = Mat::zeros(imagePart.rows, imagePart.cols, CV_32F);

    imagePart.convertTo(im_float_2, CV_32F);
    imageBig.convertTo(im_floatBig,CV_32F);

    for(maxRow=0; maxRow<=imageBig.rows-image_window.rows;maxRow++)
    {
        for(maxCol=0; maxCol<imageBig.cols-image_window.cols;maxCol++)
        {

            image_window = im_floatBig( cv::Rect( maxCol, maxRow, 
            image_window.cols, image_window.rows ) );

            n_pixels = image_window.rows * image_window.cols;

            // Compute mean and standard deviation of both images

            meanStdDev(image_window, im1_Mean, im1_Std);
            meanStdDev(im_float_2, im2_Mean, im2_Std);

            // Compute covariance and correlation coefficient
            covar = (image_window - im1_Mean).dot(im_float_2 - im2_Mean) / n_pixels;

            correl = covar / (im1_Std[0] * im2_Std[0]);
            if (correl > GMAX)
            {
            GMAX = correl; TX = maxRow; TY=maxCol;
            image_window.convertTo(imagePart, CV_8UC1);
            }
        }
    }

            cvtColor(imagePart, imagePart_out, CV_GRAY2BGR);
            printf("\nComputed shift: [%d, %d] MAX: %f\n", TX, TY,GMAX);                

}

但是执行此操作时,即使对于较小的视频大小(帧大小-{262x240,补丁大小-25x25),我的FPS(1-2)也非常低。

有没有办法实现更高的FPS。我也在寻找相位相关的方向,但不确定如何从这里开始。可以将其转换为频域吗?

现在,我想优化上面的代码以提高速度。

1 个答案:

答案 0 :(得分:2)

是的,您可能会从使用FFT中受益。只需将im_float_2填充到im_floatBig的大小即可。在采用其中一个变换的复共轭之后,在傅立叶域中相乘会导致互相关,这与您的correl值不同(没有发生除以标准偏差的情况)。但是我认为您实际上并不需要通过标准差进行标准化才能获得良好的模板匹配。互相关本身非常有效。结果中最大值的位置可以转换为模板的位移w.r.t.图片。

通过FFT进行互相关的步骤是:

  1. 将模板(浮动图片)填充到另一个图片的大小(带有零)。
  2. 计算两者的FFT。
  3. 翻转结果之一的虚部符号(复共轭)。
  4. 将两者相乘。
  5. 计算结果的IFFT。
  6. 找到具有最大值的像素的位置。

此像素的位置指示填充模板w.r.t.另一个图像。如果它们最匹配而不进行平移,则最大像素将为(x,y)=(0,0)。如果它是(1,0),则表示沿x偏移了一个像素。方向是取决于您计算复数共轭的方向。请注意,此结果是周期性的,在相反方向上的一个像素移位由位于图像右边缘的最大像素表示。只需做一点试验,以确定如何将位置转换为模板的移位。

关于您的代码:

  1. meanStdDev(im_float_2, im2_Mean, im2_Std);是在循环中计算的,即使im_float_2不变。

  2. 但是无论如何您都可以不对其进行归一化,因为您只是在寻找最大的相关性,并且将搜索中的所有值除以相同的数字不会改变哪个是最大的。 n_pixels除法也是如此。

  3. image_window.convertTo(imagePart, CV_8UC1)移动到循环之外。在最终找到实际最大值之前,您可能会多次更新当前最大值。如果仅使用最后一个子窗口,那么将这么多子窗口转换为CV_U8毫无意义。在循环内,您可以更新最大值的(x,y)坐标。仅投射最终位置。

  4. 您可能不需要在整个图像中搜索模板。物体可能仅移动相对较小的量。您应该只在先前已知位置周围的一小部分区域内查看。这个概念也适用于FFT方法:裁剪大图像的区域,然后将模板填充到该大小。较小的FFT计算便宜。

  5. OpenCV按行存储图像。将循环放在行上作为内部循环以优化缓存的使用。