Я пытаюсь стабилизировать видео с помощью фильтра Калмана для сглаживания. Но у меня есть некоторые проблемы
Каждый раз у меня есть два кадра: один текущий и другой.
Вот мой рабочий процесс:
Но я думаю, что с Калманом что-то не так, потому что в конце мое видео все еще не стабилизировано и совсем не гладкое, оно даже хуже оригинала …
Вот мой код Кальмана
void StabilizationTestSimple2::init_kalman(double x, double y)
{
KF.statePre.at<float>(0) = x;
KF.statePre.at<float>(1) = y;
KF.statePre.at<float>(2) = 0;
KF.statePre.at<float>(3) = 0;
KF.transitionMatrix = *(Mat_<float>(4,4) << 1,0,1,0, 0,1,0,1, 0,0,1,0, 0,0,0,1);
KF.processNoiseCov = *(Mat_<float>(4,4) << 0.2,0,0.2,0, 0,0.2,0,0.2, 0,0,0.3,0,
0,0,0,0.3);
setIdentity(KF.measurementMatrix);
setIdentity(KF.processNoiseCov,Scalar::all(1e-6));
setIdentity(KF.measurementNoiseCov,Scalar::all(1e-1));
setIdentity(KF.errorCovPost, Scalar::all(.1));
}
и вот как я это использую. Я ставлю только интересную часть. Весь этот код находится внутри цикла flor.
cornerPrev2 и cornerCurr2 содержит все характерные точки, обнаруженные непосредственно перед (с помощью calcOpticalFlowPyrLK ())
/// Transformation
Mat transformMatrix = estimateRigidTransform(cornersPrev2,cornersCurr2 ,false);
// in rare cases no transform is found. We'll just use the last known good transform.
if(transformMatrix.data == NULL) {
last_transformationmatrix.copyTo(transformMatrix);
}
transformMatrix.copyTo(last_transformationmatrix);
// decompose T
double dx = transformMatrix.at<double>(0,2);
double dy = transformMatrix.at<double>(1,2);
double da = atan2(transformMatrix.at<double>(1,0), transformMatrix.at<double>(0,0));
// Accumulated frame to frame transform
x += dx;
y += dy;
a += da;
std::cout << "accumulated x,y: (" << x << "," << y << ")" << endl;
if (compteur==0){
init_kalman(x,y);
}
else {vector<Point2f> smooth_feature_point;
Point2f smooth_feature=kalman_predict_correct(x,y);
smooth_feature_point.push_back(smooth_feature);
std::cout << "smooth x,y: (" << smooth_feature.x << "," << smooth_feature.y << ")" << endl;
// target - current
double diff_x = smooth_feature.x - x;//
double diff_y = smooth_feature.y - y;
dx = dx + diff_x;
dy = dy + diff_y;
transformMatrix.at<double>(0,0) = cos(da);
transformMatrix.at<double>(0,1) = -sin(da);
transformMatrix.at<double>(1,0) = sin(da);
transformMatrix.at<double>(1,1) = cos(da);
transformMatrix.at<double>(0,2) = dx;
transformMatrix.at<double>(1,2) = dy;
warpAffine(currFrame,outImg,transformMatrix,prevFrame.size(), INTER_NEAREST|WARP_INVERSE_MAP, BORDER_CONSTANT);
namedWindow("stabilized");
imshow("stabilized",outImg);
namedWindow("Original");
imshow("Original",originalFrame);}
Может у кого-то есть идея, почему она не работает?
Поблагодарить
KF.transitionMatrix = *(Mat_<float>(4,4) << 1,0,1,0, 0,1,0,1, 0,0,1,0, 0,0,0,1);
KF.processNoiseCov = *(Mat_<float>(4,4) << 0.2,0,0.2,0, 0,0.2,0,0.2, 0,0,0.3,0,
0,0,0,0.3);
setIdentity(KF.measurementMatrix);
setIdentity(KF.processNoiseCov,Scalar::all(1e-6));
setIdentity(KF.measurementNoiseCov,Scalar::all(1e-1));
setIdentity(KF.errorCovPost, Scalar::all(.1));
Ваш processNoiseCov
не является симметричным, и я сомневаюсь, что у вас есть правильные недиагональные члены. Я бы придерживался там диагональной матрицы, пока ты не поймешь KF лучше.
С другой стороны, вы, кажется, немедленно перезаписываете это setIdentity
с крошечными значениями, что, вероятно, является ошибкой. Может быть, вы добавили это после проблем с неверной матрицей выше?
Если вы опишите частоту кадров и единицы вашего состояния (метры? Пиксели?), Мы можем поговорить о том, как выбрать хорошие значения для processNoiseCov
а также measurementNoiseCov
,
РЕДАКТИРОВАТЬ:
Хорошо, учитывая, что ваше состояние [ x_pixels, y_pixels, dx_pixels, dy_pixels ]
Вот несколько советов:
I
таким образом, вы говорите, что измеряете те же самые вещи, что и в вашем состоянии (это несколько необычно: часто вы измеряете только некоторое подмножество вашего состояния, например, у вас не будет оценки скорости в ваших измерениях).I
значение processNoiseCov
а также measurementNoiseCov
похожи, так что я буду обсуждать их вместе. Ваш processNoiseCov
должна быть диагональная матрица, где каждый член является дисперсия (квадрат стандартного отклонения) того, как эти значения могут меняться между кадрами. Например, если есть вероятность 68% (см. нормальное распределение) что ваши пиксельные смещения находятся в пределах 100 пикселей в каждом кадре, диагональная запись для позиции должна быть 100 * 100 = 10000
(помните, дисперсия в квадрате стандартного ввода). Вы должны сделать аналогичную оценку того, как изменится скорость. (Дополнительно: должны присутствовать ко-меняющиеся (недиагональные) термины, потому что изменение скорости связано с изменением положения, но вы можете обойтись без этого, пока это не будет иметь смысла для вас. Я объяснил это в других ответах).processNoiseCov
добавляется каждый Рамка так что имейте ввиду, что представленные изменения составляют более 1/25 секунды.measurementNoiseCov
имеет такие же единицы измерения (опять же, матрица измерений идентична), но должна отражать, насколько точны ваши измерения по сравнению с непознаваемыми фактическими истинными значениями.errorCovPost
это ваша первоначальная неопределенность, выраженная точно так же, как ваша аддитивная ковариация для каждого кадра, но это описание того, насколько вы уверены в правильности вашего начального состояния.