Решить низкий FPS для кода корреляции для вычисления сдвига в изображении - PullRequest
0 голосов
/ 11 октября 2018

Я пытаюсь отследить объект, используя корреляцию.Я нахожу меньший участок на большом изображении, кадр за кадром.Для этого я нахожу сдвиг в патче, и там, где корреляция максимальна, обновите патч новым патчем.

Мой код:

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

}

Но при выполнении этого яЯ получаю очень низкий FPS (1-2) даже для видео небольшого размера (Размер кадра- 262x240, Размер патча- 25x25).

Есть ли способ добиться более высокого FPS.Я также смотрю в направлении фазовой корреляции, но не знаю, как это сделать отсюда.Может преобразование в частотную область поможет?

А пока я хочу оптимизировать приведенный выше код для скорости.

1 Ответ

0 голосов
/ 11 октября 2018

Да, вы, вероятно, выиграете от использования БПФ.Просто вставьте im_float_2 до размера im_floatBig.Умножение в области Фурье после получения комплексного сопряжения одного из преобразований приводит к кросс-корреляции, которая не совпадает с вашим значением correl (деление на стандартные отклонения не происходит).Но я не думаю, что вам нужно нормализовать по стандартным отклонениям, чтобы получить хорошее соответствие шаблону.Кросс-корреляция работает очень хорошо сама по себе.Расположение максимума в результате может быть переведено в смещение шаблона относительно изображения.

Шаги для взаимной корреляции через БПФ:

  1. Дополнение шаблона (плавающее изображение) до размера другого изображения (с нулями).
  2. Вычисление БПФ для обоих.
  3. Отразить знак мнимой составляющей одного из результатов (комплексное сопряжение).
  4. Умножьте их на два.
  5. Вычислите IFFT результата.
  6. Найдите расположение пикселя с наибольшим значением.

Theрасположение этого пикселя указывает перевод дополненного шаблона по сравнению с другим изображением.Если они лучше всего соответствуют без перевода, максимальный пиксель будет в (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. Возможно, вам не нужно искать все изображение для вашего шаблона.Вполне вероятно, что объект движется только относительно небольшое количество.Вы должны смотреть только в небольшом регионе вокруг предыдущего известного местоположения.Эта концепция применима и к методу БПФ: обрезать область вашего большого изображения и добавить шаблон к этому размеру.Меньшее БПФ дешевле для вычисления.

  5. OpenCV хранит изображения построчно.Поместите цикл над строками как внутренний цикл, чтобы оптимизировать использование кэша.

...