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

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

Мой код:

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. Я также смотрю в направлении фазовой корреляции, но не знаю, как это сделать отсюда. Может преобразование его в частотную область поможет?

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

2

Решение

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

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

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

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

2

Другие решения

Других решений пока нет …