Inverse Flow - Forward Warping or Bilinear "Splatting"
I am interested in the inverse or backward flow given the forward flow. The following code does this forward warping or bilinear splatting, but it is annoyingly slow (~8ms @VGA on my i7-7820HK). It seems likely to me that this could/should be closer to 1-2ms. Any insights into speeding this up?
inline bool isOnImage(const cv::Point& pt, const cv::Size& size)
{
return pt.x >= 0 && pt.x < size.width && pt.y >= 0 && pt.y < size.height;
}
cv::Mat img_proc::inverseFlow(const cv::Mat& flow)
{
cv::Mat inverse_flow = cv::Mat::zeros(flow.size(), CV_32FC2);
cv::Mat weights = cv::Mat::zeros(flow.size(), CV_32FC2);
const int rows = flow.rows;
const int cols = flow.cols;
for(int i = 0; i < rows; ++i)
{
auto flow_ptr = flow.ptr<cv::Vec2f>(i);
for(int j = 0; j < cols; ++j)
{
const float du = flow_ptr[j][0];
const float dv = flow_ptr[j][1];
const int u = j + std::round(du);
const int v = i + std::round(dv);
if(!isOnImage({u,v}, flow.size()))
{
continue;
}
const int du_floor = (int) std::floor(du);
const int du_ceil = (int) std::ceil(du);
const int dv_floor = (int) std::floor(dv);
const int dv_ceil = (int) std::ceil(dv);
const int u_min = std::min(cols-1, std::max(0, j + du_floor));
const int u_max = std::min(cols-1, std::max(0, j + du_ceil));
const int v_min = std::min(rows-1, std::max(0, i + dv_floor));
const int v_max = std::min(rows-1, std::max(0, i + dv_ceil));
const float uf = j + du;
const float vf = i + dv;
const float w0 = (u_max - uf) * (v_max - vf); // TL
const float w1 = (uf - u_min) * (v_max - vf); // TR
const float w2 = (uf - u_min) * (vf - v_min); // BR
const float w3 = (u_max - uf) * (vf - v_min); // BL
weights.at<cv::Vec2f>(v_min, u_min) += cv::Vec2f{w0,w0};
weights.at<cv::Vec2f>(v_min, u_max) += cv::Vec2f{w1,w1};
weights.at<cv::Vec2f>(v_max, u_min) += cv::Vec2f{w3,w3};
weights.at<cv::Vec2f>(v_max, u_max) += cv::Vec2f{w2,w2};
inverse_flow.at<cv::Vec2f>(v_min, u_min) += w0 * cv::Vec2f{-du,-dv};
inverse_flow.at<cv::Vec2f>(v_min, u_max) += w1 * cv::Vec2f{-du,-dv};
inverse_flow.at<cv::Vec2f>(v_max, u_min) += w3 * cv::Vec2f{-du,-dv};
inverse_flow.at<cv::Vec2f>(v_max, u_max) += w2 * cv::Vec2f{-du,-dv};
}
}
cv::divide(inverse_flow, weights, inverse_flow);
return inverse_flow;
}
I now see that "frame interpolation" is a worthwhile search string. Estimating an intermediate frame given an optical flow, either just forward or forward and backward is very similar. Perhaps getting good results is non-trivial and somewhat costly.