Farneback光流 - 处理像素在视野外,具有错误流动结果的像素,不同大小的图像
问题描述:
我正在写论文,其中一部分任务是插值图像之间以创建中间图像。这项工作必须在C++中使用openCV 2.4.13来完成。 迄今为止找到的最佳解决方案是计算光流和重新映射。但这种解决方案有我无法解决我自己两个问题:Farneback光流 - 处理像素在视野外,具有错误流动结果的像素,不同大小的图像
- 有应该去拿出来看(例如图像的底部)像素,但他们没有。
- 一些像素不动,创造了扭曲的结果(沙发上的右上部)
是什么使得流动&重映射方法更好:
- 均衡强度。这我可以做。您可以通过比较沙发形式(重新映射的图像的中心和原始)来检查结果。
- 缩小图像的大小。我不允许这样做,因为我需要相同尺寸的输出。有没有一种方法来重新调整光流结果得到更大的重映射图像?
其他方法尝试和失败:
- CUDA :: interpolateFrames。创造令人难以置信的重影。
- 与cv :: addWeighted混合图像。更糟的是鬼影。
下面是我目前使用的代码。和图像:dropbox link with input and result images
INT主(){
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图片?
- 如何处理像素,像像我的图像底部(棕色的木质部分应该消失)。
- 如何处理失真这是因为没有为那些像素计算光流,而在那里的许多像素有运动? (沙发右上角,&狮子雕像在重映像中有一只鬼手)。
答
随着OpenCV中的Farneback光流,你只会得到像素位移的粗略估计,因此出现在结果图像的扭曲。
我不认为光流是你想要实现恕我直言的路。相反,我建议你看看图片/象素登录为instace这里:http://docs.opencv.org/trunk/db/d61/group__reg.html
图片/象素登录是匹配两个图像的像素的科学。对这个尚未准确解决的复杂非平凡问题正在进行积极的研究。
谢谢,但除非我非常错 - 我不能使用这种方法,因为它不存在于opencv 2.4.13中。 –
@ZaneZake我的不好。事实上,我刚刚讨论的_registration_模块仅在[opencv_contrib](https://github.com/opencv/opencv_contrib)仓库中可用。 –