MeshFlow-Online-Video-Stabilization
src/Optimization.cpp
cpp
double Optimizer::computeDefaultLambda(int windowSize, int bufferSize) {
int half = windowSize / 2;
double totalRowSum = 0.0;
for (int t = 0; t < bufferSize; ++t) {
double rowSum = 0.0;
for (int d = -half; d <= half; ++d) {
if (d == 0) continue;
int r = t + d;
if (r < 0 || r >= bufferSize) continue;
double w = exp(-9.0 * d * d / (windowSize * windowSize));
rowSum += w;
}
totalRowSum += rowSum;
}
double avgRowSum = totalRowSum / bufferSize;
double lambda = 10.0 / avgRowSum;
// 限制范围
lambda = std::max(2.0, std::min(20.0, lambda));
return lambda;
}
void Optimizer::onlinePathOptimization(const vector<Mat>& cameraPath,
vector<Mat>& optimizedPath,
int bufferSize,
int iterations,
int windowSize,
int beta) {
double lambda_t = 100; // TODO: make lambda adaptive
//double lambda_t = computeDefaultLambda(windowSize, bufferSize);
optimizedPath.reserve(cameraPath.size());
for (int i = 0; i < cameraPath.size(); ++i) {
optimizedPath.push_back(Mat::zeros(cameraPath.back().rows, cameraPath.back().cols, CV_64F));
}
/// Fill in the weights
Mat W(bufferSize, bufferSize, CV_64F);
for (int i = 0; i < W.rows; ++i) {
for (int j = 0; j < W.cols; ++j) {
W.at<double>(i, j) = gauss(i, j, windowSize);
}
}
/// Iterative optimization process
for (int i = 0; i < cameraPath.back().rows; ++i) {
for (int j = 0; j < cameraPath.back().cols; ++j) {
// y = []; d = None
vector<double> y;
Mat d, P;
// Real-time optimization
for (int t = 1; t < cameraPath.size() + 1; ++t) {
if (t < bufferSize + 1) {
Mat camPath = getCamPath(cameraPath, i, j, t);
camPath.copyTo(P);
if (!d.empty()) {
for (int k = 0; k < iterations; ++k) {
Mat Wt = getW(W, t);
Mat alpha = camPath + lambda_t * Wt * P;
Mat gamma = 1 + lambda_t * getW(W, t) * Mat::ones(t, 1, CV_64F);
for (int m = 0; m < alpha.cols - 1; ++m) {
alpha.at<double>(m) += beta * d.at<double>(m);
gamma.at<double>(m) += beta;
}
P = alpha / gamma;
}
}
}
else {
Mat camPath = getCamPath(cameraPath, i, j, t - bufferSize, t);
camPath.copyTo(P);
for (int k = 0; k < iterations; ++k) {
Mat alpha = camPath + lambda_t * W * P;
Mat gamma = 1 + lambda_t * W * Mat::ones(bufferSize, 1, CV_64F);
for (int m = 0; m < alpha.cols - 1; ++m) {
alpha.at<double>(m) += beta * d.at<double>(m + 1);
gamma.at<double>(m) += beta;
}
P = alpha / gamma;
}
}
d = P;
y.push_back(P.at<double>(P.rows - 1));
}
for (int m = 0; m < y.size(); ++m) {
optimizedPath[m].at<double>(i, j) = y[m];
}
}
}
vector<Mat> cameraPath2;
vector<Mat> optimizedPath2;
optimizedPath2.reserve(cameraPath.size());
cameraPath2.reserve(cameraPath.size());
for (int i = 0; i < cameraPath.size(); ++i) {
cameraPath2.push_back(cameraPath[i].clone());
optimizedPath2.push_back(Mat::zeros(cameraPath.back().rows, cameraPath.back().cols, CV_64F));
}
for (int i = 0; i < cameraPath.back().rows; ++i) {
for (int j = 0; j < cameraPath.back().cols; ++j) {
// y = []; d = None
vector<double> y;
Mat d, P;
// Real-time optimization
for (int t = 1; t < cameraPath.size() + 1; ++t) {
if (t < bufferSize + 1) {
Mat camPath = getCamPath(cameraPath, i, j, t);
camPath.copyTo(P);
if (!d.empty()) {
for (int k = 0; k < iterations; ++k) {
Mat Wt = getW(W, t);
Mat alpha = camPath + lambda_t * Wt * P;
Mat gamma = 1 + lambda_t * getW(W, t) * Mat::ones(t, 1, CV_64F);
for (int m = 0; m < alpha.cols - 1; ++m) {
alpha.at<double>(m) += beta * d.at<double>(m);
gamma.at<double>(m) += beta;
}
P = alpha / gamma;
}
}
}
else {
auto refV = cameraPath[t - bufferSize].at<double>(i, j);
auto prevRefV = cameraPath[t - bufferSize - 1].at<double>(i, j);
for (int kk = t - bufferSize, jj = 0; kk < t; ++kk, ++jj) {
cameraPath2[kk].at<double>(i, j) = cameraPath[t - bufferSize + jj].at<double>(i, j) - refV;
}
/*Mat camPath(bufferSize, 1, CV_64F);
for (int kk = 0; kk < bufferSize; ++kk) {
camPath.at<double>(kk) = cameraPath[t - bufferSize + kk].at<double>(i, j) - refV;
}*/
double deltaRef = refV - prevRefV;
for (int kk = 0; kk < d.rows; ++kk) {
d.at<double>(kk) -= deltaRef;
}
/*for (int kk = 0;kk < d.rows;++kk)
{
d.at<double>(kk) -= refVPrev;
}*/
Mat camPath = getCamPath(cameraPath2, i, j, t - bufferSize, t);
camPath.copyTo(P);
//P = camPath.clone();
for (int k = 0; k < iterations; ++k) {
Mat alpha = camPath + lambda_t * W * P;
Mat gamma = 1 + lambda_t * W * Mat::ones(bufferSize, 1, CV_64F);
for (int m = 0; m < alpha.cols - 1; ++m) {
alpha.at<double>(m) += beta * d.at<double>(m + 1);
gamma.at<double>(m) += beta;
}
P = alpha / gamma;
}
}
d = P;
y.push_back(P.at<double>(P.rows - 1));
}
for (int m = 0; m < y.size(); ++m) {
optimizedPath2[m].at<double>(i, j) = y[m];
}
}
}
vector<std::pair<double, double>> OPathA(cameraPath.size());
vector<std::pair<double, double>> OPathB(cameraPath.size());
vector<std::pair<double, double>> OPathC(cameraPath.size());
cv::Point pos(cameraPath[0].cols/2, cameraPath[0].rows / 2);
for (int i = 0;i < OPathA.size();i++) {
OPathA[i] = std::make_pair<>(i, cameraPath[i].at<double>(pos));
OPathB[i] = std::make_pair<>(i, optimizedPath[i].at<double>(pos));
OPathC[i] = std::make_pair<>(i, optimizedPath2[i].at<double>(pos));
if(i>=bufferSize)
OPathC[i].second+= cameraPath[i- bufferSize+1].at<double>(pos);
}
}

