Я пытаюсь отслеживать объект, используя корреляцию. Я нахожу маленькое пятно на большом изображении, кадр за кадром. Для этого я нахожу сдвиг в патче, и там, где корреляция максимальна, обновите патч новым патчем.
Мой код:
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. Я также смотрю в направлении фазовой корреляции, но не знаю, как это сделать отсюда. Может преобразование его в частотную область поможет?
Сейчас я хочу оптимизировать приведенный выше код по скорости.
Да, вы, вероятно, выиграете от использования БПФ. Просто колодка im_float_2
в размере im_floatBig
, Умножение в области Фурье после взятия комплексного сопряжения одного из преобразований приводит к взаимной корреляции, которая не совпадает с вашей correl
значение (деления на стандартные отклонения не происходит). Но я не думаю, что вам нужно нормализовать по стандартным отклонениям, чтобы получить хорошее соответствие шаблону. Кросс-корреляция работает очень хорошо сама по себе. Расположение максимума в результате может быть переведено в смещение шаблона w.r.t. изображение.
Шаги для взаимной корреляции через БПФ:
Расположение этого пикселя указывает перевод дополненного шаблона w.r.t. другое изображение. Если они лучше всего соответствуют без перевода, максимальный пиксель будет в (x, y) = (0,0). Если он равен (1,0), это указывает на сдвиг в один пиксель по оси x. Каково направление зависит от того, для какого из двух вы вычислили комплексное сопряжение. Обратите внимание, что этот результат является периодическим, однопиксельное смещение в противоположном направлении указывается тем, что максимальный пиксель находится на правом краю изображения. Просто поэкспериментируйте немного, чтобы определить, как перевести местоположение в сдвиг вашего шаблона.
Что касается вашего кода:
meanStdDev(im_float_2, im2_Mean, im2_Std);
вычисляется в цикле, хотя im_float_2
не меняется
Но в любом случае вы можете обойтись без нормализации, поскольку вы просто ищете максимальную корреляцию, и деление всех значений в вашем поиске на одно и то же число не меняет, какое из них является наибольшим. То же самое относится к делению на n_pixels
,
Переехать image_window.convertTo(imagePart, CV_8UC1)
вне петли. Вполне вероятно, что вы обновляете свой текущий максимум много раз, прежде чем, наконец, найдете фактический максимум. Нет смысла конвертировать так много вложенных окон в CV_U8
, если вы только в конечном итоге использовать последний. Внутри цикла вы обновляете (x, y) координаты макс. В ролях только окончательное местоположение.
Вам, вероятно, не нужно искать все изображение для вашего шаблона. Вполне вероятно, что объект движется только относительно небольшое количество. Вы должны смотреть только в небольшом регионе вокруг предыдущего известного местоположения. Эта концепция применима и к методу БПФ: обрезать область вашего большого изображения и добавить шаблон к этому размеру. Меньшее БПФ дешевле вычислить.
OpenCV хранит изображения построчно. Поместите цикл над строками как внутренний цикл, чтобы оптимизировать использование кэша.
Других решений пока нет …