通过图像减法进行分割的优化算法

8

我希望您能为OpenCV项目担任翻译,我想尽可能好地分割移动对象,并当然要尽量减少噪音。

为此,我想使用图像减法算法。 我已经有一个运行程序,但今天没有找到获得足够好结果的方法。

我已经有以下(灰度)图像:

IplImage* grayScale;
IplImage* lastFrame;
IplImage* secondLastFrame;
IplImage* thirdLastFrame;

到目前为止,我已经尝试使用cvSub()cvAbsDiff()来减去当前帧图像和上一帧图像,以获取移动部分。但不幸的是,我仍然有很多噪音(例如在风吹时稍微移动的树),如果移动的物体相当大并且具有均匀的颜色(比如穿着白色或黑色衬衫的人),减法只会检测到人的左右两侧的图像变化,而不是身体本身的变化,因此有时会将一个对象检测为两个对象...
cvAbsDiff(this->lastFrame,grayScale,output);
cvThreshold(output,output,10,250, CV_THRESH_BINARY);
cvErode(output,output, NULL, 2);
cvDilate(output,output, NULL, 2);

为了消除这种噪声,我尝试使用cvErode()cvDilate()来侵蚀和扩张图像,但这非常缓慢,如果屏幕上的移动对象很小,则侵蚀会删除相当多的对象,因此在扩张后,我并不总是得到一个良好的结果或分裂的对象。
然后,我使用cvFindContours()来获取轮廓,检查大小并绘制移动对象周围的矩形。但由于坏的分割,结果往往是不理想的,经常将一个对象分成几个矩形。
现在,我的一个朋友告诉我,我可以尝试使用两个以上的连续帧进行减法,因为这可能已经减少了噪音...但我不知道他的意思是什么,以及我应该如何添加/减去帧以获得几乎没有噪音但显示足够大的对象斑点的图像。
有人能帮我吗?我如何使用多个帧来获得尽可能少的噪音但足够大的斑点,以显示移动对象?我将感谢任何提示...
补充说明:
我在这里上传了一个当前视频:http://temp.tinytall.de/。也许有人想在那里试试...
这是其中一个帧:左图显示了我从cvFindContours()中得出的结果,右图则是分割后的图像,在其上我尝试找到轮廓...
所以,如果它们移动得足够快,一个大对象就可以很好地工作...例如自行车...但对于步行的人来说,它并不总是得到良好的结果...有什么想法吗?

1
http://en.wikipedia.org/wiki/Motion_estimation - rwong
3个回答

2

看起来你的背景是固定的。 一种可能的解决方案是让计算机学习背景,例如通过随时间取平均值。然后计算平均图像与当前图像之间的差异。差异很可能来自移动物体。


这听起来像是个好主意...实际上也许可以加快整个检测过程,因为我不需要再计算那么多图像差异之类的东西了...只需偶尔更新一下平均背景图像即可...为此,我可以写一些代码,每隔10帧计算出几个新的平均值...我会尝试并回来查看的...到目前为止谢谢你... - florianbaethge
这个很好用...我想做一个稳定更新的平均图像,当前帧总是在其他帧的基础上添加一点影响...我发现cvRunningAvg()已经实现了这个功能,并且效果非常好...分割结果更好。但它仍然有一些缺点:静止不动几秒钟的人会被“烧”到平均图像中,并且如果他们再次移动,阈值仍然会在旧位置检测到他们,因为平均图像需要一些时间才能“摆脱它们”。有什么改进的想法吗? - florianbaethge

2
给定三个相邻的帧A、B、C,您可以得到两个帧差X和Y。通过组合X和Y(例如,通过阈值处理然后逻辑“AND”操作),您可以减少噪声的影响。一个不想要的副作用是,检测到的运动区域将略小于理想值(“AND”操作将减少该区域)。
由于图像序列运动估计已经有数十年的研究历史,您可能想了解更复杂的运动检测方法,例如使用运动矢量场。在这种情况下,Google Scholar会是您的朋友。

到目前为止,非常感谢!我现在尝试将当前帧与上一帧相减,当前帧与倒数第二帧相减以及当前帧与倒数第三帧相减,然后对其应用二进制阈值,并使用cvAnd()将它们相加。这个方法效果还不错,但结果仍然不是很好。虽然没有检测到太多噪声,但对象本身并不总是被检测为一个单独的斑点(仍然分裂)。有没有其他想法可以改善结果?(我已经将我的当前代码添加到你的答案中) - florianbaethge
由于您已经成功消除了大部分噪声,您可以尝试使用形态学闭合操作,并使用较大的自定义内核大小来处理预期斑点大小的近似区域(对于静态图像我已经尝试过这种方法)。这应该可以连接分割图像上附近的线条。 - AruniRC
谢谢...我已经尝试使用这些操作来消除噪声,但cvErode()和cdDilate()速度相当慢,所以我宁愿少用它们... - florianbaethge

1

这是一个非常微妙的问题。运动估计相当复杂。所以请尽量寻找好的文献,避免发明算法 :)

我的建议是:

搜索捆绑图像进行运动估计。捆绑是使用多个图像来降低噪声和误差率。

如果您想要更强健的话,可以研究一下所谓的卡尔曼滤波器。如果您要跟踪物体,则不希望它们在帧之间进行“无限速度跳跃”(通常是噪声或错过)。这是我强烈推荐的一个C ++库Kalman filter

最后,MonoSLAM,我稍微推一下 :) Andrew Davison: Research


实际上,我的目标是实现多对象跟踪的粒子滤波器... 但为了做到这一点,我至少需要足够好的分割结果来获取物体的位置,以便在跟踪算法的更新阶段进行更新... 我现在尝试使用多帧相减来实现它...(请参见对Misha答案的评论) - florianbaethge
当你谈论噪声时,你指的是什么类型的噪声?不同类型的噪声需要不同类型的滤波。如果是相机噪声(几乎为白噪声),您可以在捕获图像后立即进行cvSmooth处理。您能放一些图片吗,这会使它变得不那么通用。毕竟这是计算机视觉;) - code-gijoe
你应该真正关注一下安德鲁·戴维森的研究。你需要追踪移动的人,因此需要更新跟踪模型,这可能很困难。一旦检测到移动的“斑点”,你需要创建一个简单的对象模型并在帧之间进行跟踪。寻找“好的特征进行跟踪”。其中一种简单的方法是通过在具有速度和方向的搜索窗口中使用SAD来完成。所以你将需要卡尔曼 :) - code-gijoe
我会看一下...实际上我不想创建基于模型的分割,但也许这个方法可行...到目前为止谢谢... - florianbaethge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接