Farneback光流 - 处理视图之外的像素,具有错误流动结果的像素,不同尺寸的图像

时间:2017-04-20 06:41:14

标签: c++ opencv image-processing opticalflow remap

我正在撰写我的论文,其中一部分任务是在图像之间进行插值以创建中间图像。这项工作必须使用openCV 2.4.13在c ++中完成。 到目前为止,我发现的最佳解决方案是计算光流和重新映射。但是这个解决方案有两个我自己无法解决的问题:

  • 有些像素应该不在视野(例如图像的底部),但它们没有。
  • 有些像素无法移动,会产生扭曲的结果(沙发的右上角)

什么使流量和重新映射方法更好

  • 均衡强度。我可以这样做。您可以通过比较沙发形式(重新映射的图像的中心和原始图像)来检查结果。
  • 缩小图像尺寸。我不允许这样做,因为我需要相同大小的输出。有没有办法重新缩放光流结果以获得更大的重映射图像?

尝试了其他方法失败

  • CUDA :: interpolateFrames。创造令人难以置信的重影。
  • 将图像与cv :: addWeighted混合。更糟糕的重影。

以下是我目前使用的代码。和图片:dropbox link with input and result images

int main(){

cv::Mat second, second_gray, cutout, cutout_gray, flow_n;
second = cv::imread( "/home/zuze/Desktop/forstack/second_L.jpg", 1 );
cutout = cv::imread("/home/zuze/Desktop/forstack/cutout_L.png", 1);
cvtColor(second, second_gray, CV_BGR2GRAY);
cvtColor(cutout, cutout_gray, CV_RGB2GRAY );

///----------COMPUTE OPTICAL FLOW AND REMAP -----------///
cv::calcOpticalFlowFarneback( second_gray, cutout_gray, flow_n, 0.5, 3, 15, 3, 5, 1.2, 0 );
cv::Mat remap_n; //looks like it's drunk.
createNewFrame(remap_n, flow_n, 1, second, cutout );
cv::Mat cflow_n;
cflow_n = cutout_gray;
cvtColor(cflow_n, cflow_n, CV_GRAY2BGR);
drawOptFlowMap(flow_n, cflow_n, 10, CV_RGB(0,255,0));

///--------EQUALIZE INTENSITY, COMPUTE OPTICAL FLOW AND REMAP ----///
cv::Mat cutout_eq, second_eq;
cutout_eq= equalizeIntensity(cutout);
second_eq= equalizeIntensity(second);

cv::Mat flow_eq, cutout_eq_gray, second_eq_gray, cflow_eq;
cvtColor( cutout_eq, cutout_eq_gray, CV_RGB2GRAY );
cvtColor( second_eq, second_eq_gray, CV_RGB2GRAY );

cv::calcOpticalFlowFarneback( second_eq_gray, cutout_eq_gray, flow_eq, 0.5, 3, 15, 3, 5, 1.2, 0 );
cv::Mat remap_eq;
createNewFrame(remap_eq, flow_eq, 1, second, cutout_eq );
cflow_eq = cutout_eq_gray;
cvtColor(cflow_eq, cflow_eq, CV_GRAY2BGR);
drawOptFlowMap(flow_eq, cflow_eq, 10, CV_RGB(0,255,0));

cv::imshow("remap_n", remap_n);
cv::imshow("remap_eq", remap_eq);
cv::imshow("cflow_eq", cflow_eq);
cv::imshow("cflow_n", cflow_n);
cv::imshow("sec_eq", second_eq);
cv::imshow("cutout_eq", cutout_eq);
cv::imshow("cutout", cutout);
cv::imshow("second", second);

cv::waitKey();

return 0;

}

重映射功能,用于中间图像创建:

void createNewFrame(cv::Mat & frame, const cv::Mat & flow, float shift, cv::Mat & prev, cv::Mat &next){
    cv::Mat mapX(flow.size(), CV_32FC1);
    cv::Mat mapY(flow.size(), CV_32FC1);
    cv::Mat newFrame;
    for (int y = 0; y < mapX.rows; y++){
        for (int x = 0; x < mapX.cols; x++){
            cv::Point2f f = flow.at<cv::Point2f>(y, x);
            mapX.at<float>(y, x) =  x + f.x*shift;
            mapY.at<float>(y, x) =  y + f.y*shift;
        }
    }
    remap(next, newFrame, mapX, mapY, cv::INTER_LANCZOS4);
    frame = newFrame;
    cv::waitKey();
}

以矢量形式显示光流的功能:

void drawOptFlowMap (const cv::Mat& flow, cv::Mat& cflowmap, int step, const cv::Scalar& color) {
    cv::Point2f sum; //zz
    std::vector<float> all_angles;
    int count=0; //zz
    float angle, sum_angle=0; //zz
    for(int y = 0; y < cflowmap.rows; y += step)
        for(int x = 0; x < cflowmap.cols; x += step)
        {
            const cv::Point2f& fxy = flow.at< cv::Point2f>(y, x);
            if((fxy.x != fxy.x)||(fxy.y != fxy.y)){ //zz, for SimpleFlow
                //std::cout<<"meh"; //do nothing
            }
            else{
                line(cflowmap, cv::Point(x,y), cv::Point(cvRound(x+fxy.x), cvRound(y+fxy.y)),color);
                circle(cflowmap, cv::Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), 1, color, -1);
                sum +=fxy;//zz
                angle = atan2(fxy.y,fxy.x);
                sum_angle +=angle;
                all_angles.push_back(angle*180/M_PI);
                count++; //zz
            }
        }
}

均衡图像强度的功能,以获得更好的效果:

cv::Mat equalizeIntensity(const cv::Mat& inputImage){
    if(inputImage.channels() >= 3){
        cv::Mat ycrcb;
        cvtColor(inputImage,ycrcb,CV_BGR2YCrCb);
        std::vector<cv::Mat> channels;
        cv::split(ycrcb,channels);
        cv::equalizeHist(channels[0], channels[0]);
        cv::Mat result;
        cv::merge(channels,ycrcb);
        cvtColor(ycrcb,result,CV_YCrCb2BGR);
        return result;
    }
    return cv::Mat();
}

回顾一下,我的问题

  • 是否可以调整Farneback光流量以应用于2xbigger图像?
  • 如何处理视线外的像素,就像在我的图片底部(棕色木制部分应该消失)。
  • 如何处理由于没有为这些像素计算光流而创建的失真,而周围的许多像素都有运动? (右上方的沙发,&amp; lion雕像在重新映射的图像中有一个鬼手)。

1 个答案:

答案 0 :(得分:0)

使用OpenCV的 Farneback光流,您只能获得像素位移的粗略估计,因此会出现在结果图像上的失真。

我不认为光流是你想要实现恕我直言的方法。相反,我建议您在此处查看图像/像素注册http://docs.opencv.org/trunk/db/d61/group__reg.html

图像/像素注册是匹配两个图像的像素的科学。关于这个尚未准确解决的复杂的非平凡主题正在积极研究。