最近,我曾在一个项目中使用过TDD(测试驱动开发)。该项目是一个用Java开发的Web应用程序,虽然单元测试Web应用程序may not be trivial,但可以使用模拟(我们使用Mockito框架)。
现在我将开始一个项目,我将使用C ++处理图像处理(主要是图像分割),我不确定使用TDD是否是一个好主意。问题在于很难判断分割的结果是否正确,同样的问题也适用于许多其他图像处理算法。
所以,我想知道的是,如果有人在这里成功使用TDD和图像分割算法(不一定是分割算法)。
答案 0 :(得分:10)
至少可以使用测试进行回归测试。例如,假设您有5个特定分段算法的测试图像。您通过代码运行5个图像并手动验证结果。如果结果正确,结果将存储在某个磁盘上,并且将来执行这些测试会将生成的结果与存储的结果进行比较。
这样,如果你做了一个突破性的改变,你就会抓住它,但更重要的是你只需要经过一次(正确的)手动测试周期。答案 1 :(得分:9)
每当我做任何与计算机视觉相关的开发时,TDD几乎都是标准做法。您有图像和想要测量的东西。第一步是手工标记图像的(大)子集。这为您提供了测试数据。然后,过程(完全正确)将您的测试集分成两部分,即“开发集”和“验证集”。在应用于开发集时,您需要重复开发循环,直到算法足够准确。然后验证验证集上的结果(这样你就不会在开发集的某些奇怪方面过度训练。 这是最纯粹的测试驱动开发。
请注意,在开发像这样的大量算法相关软件时,您正在测试两种不同的东西。
根据(1),程序可以是无bug的,但不完全符合(2)。例如,一个非常简单的图像分割算法说:“图像的左半部分是一个部分,右半部分是另一个部分。这个程序可以很容易地根据(1)制作无错误。这是完全另一个问题。它满足了你的性能需求。不要混淆这两个方面,不要让一方干涉另一方。
更具体地说,我建议你首先开发算法,有缺陷的疣和所有,然后使用TDD和算法(不是代码!)以及软件的其他要求作为单独的TDDevelopment过程的规范。在重度开发中对一些相当复杂的算法深入进行小型临时辅助函数的单元测试是浪费时间和精力。
答案 2 :(得分:5)
我认为你能做的最好的事情就是测试算法所包含的简单,数学上定义明确的构建块,如线性滤波器,形态学运算,FFT,小波变换等。这些通常很难有效地实现所有边境案件,以便验证它们确实有意义。
对于像图像分割这样的实际算法,TDD没有多大意义恕我直言。我甚至认为单元测试在这里没有意义。当然,你可以编写测试,但这些测试总是非常脆弱。典型的图像处理算法需要一些必须根据所需结果进行调整的参数(一个不能自动化的过程,并且在算法运行之前无法完成)。分割算法的结果也没有很好地定义,但是你的单元测试只能测试一些明确定义的属性。算法可以具有该属性而无需执行您想要的操作,反之亦然,因此您的测试结果不是非常有用。此外,要测试分割算法的结果,您需要编写大量相当难的代码,而在视觉上验证结果非常简单,无论如何都必须这样做。
我认为在某种程度上它与单元测试用户界面类似:测试实际明确定义的功能(例如,当用户单击此按钮时,某些项目将添加到此列表中,此标签显示该文本...)相对容易,可以节省大量的工作和调试。但是世界上没有任何测试可以告诉你你的UI是否可用,可理解或漂亮,因为这些东西没有很好地定义。
答案 3 :(得分:4)
我认为TDD在这样的应用程序中比在Web应用程序中更容易 。你有一个完全确定的算法,你必须测试。您不必担心用户输入和HTML呈现等模糊内容。
您的算法包含许多步骤。可以测试这些步骤中的每一个。如果你给它们固定的已知输入,它们应该产生固定的已知输出。所以写一个测试。您通常无法测试算法“是否正确”,但您可以为其提供已经预先计算出正确结果的数据,因此您可以验证它在中产生正确的输出案例。
答案 4 :(得分:4)
您在问题中描述的图像处理测试的级别远高于您使用TDD编写的大多数测试。
在真正的Test Driven Development过程中,您首先会在向软件添加任何新功能之前编写失败的测试,然后编写导致测试通过,冲洗和重复的代码。
此过程会产生一个Unit Tests的大型库,有时会比功能代码有更多LOC个测试!
由于您的分析算法具有结构化行为,因此它们非常适合TDD方法。
但我认为你真正要问的问题是“如何针对模糊图像处理软件执行一套Integration Tests?”您可能认为我正在分裂,但单元测试和集成测试之间的这种区别确实是测试驱动开发意味着什么的核心。 TDD流程的好处来自于单元测试的丰富支持结构。
在您的情况下,我会将Integration Test套件与针对Web应用程序的自动性能指标进行比较。我们希望累积执行时间的历史记录,但我们可能不希望显式地使构建失败,因为执行效果不佳(可能受网络拥塞,磁盘I / O等因素影响)。您可以针对测试套件的性能设置一些宽松的容差,并让Continuous Integration服务器启动每日报告,以便您高度了解算法的性能。
答案 5 :(得分:4)
图像处理中的TDD仅对确定性问题有意义,例如:
然而,TDD不适用于以下特征提取算法:
...因为没有算法可以完美地解决所有图像的这种问题。
答案 6 :(得分:3)
我们就同样的问题进行了一些讨论"你的评论中提到的许多评论都来自这里的答案。
我们走到了尽头,计算机视觉/图像处理中的TDD(关于分段,检测或类似的全球目标)可能是:
获取应处理的图像/序列,并为该图像创建测试:所需的输出和指标,以告知您的结果可能与“#34;基础事实”#34;的差异。
获取另一个图像/序列以用于不同的设置(不同的光照,不同的对象或类似的东西),算法失败并为此编写测试。
以一种解决以前所有测试的方式改进算法。
回到2。
不知道这是否适用,创建测试将比传统TDD复杂得多,因为可能很难定义基础事实与算法输出之间允许的差异。
可能最好只使用一些QualityDrivenDevelopment,你的改变不应该让事情变得更糟糕" (你必须再次找到一个指标),而不是之前。
很明显,你仍然可以对这些算法的确定性部分使用传统的单元测试,但这并不是" TDD信号处理的真正问题"
答案 7 :(得分:2)
我并没有真正解决你的问题,所以我不知道它的热点。但是,您的算法的最终结果有望具有确定性,因此您可以对其执行功能测试。当然,您必须确定“已知良好”结果。我知道TDD在图形库上执行(确切地说是VTK)。比较是在最终结果图像上逐个像素地进行的。如果你有一个已知的好结果,你可以执行测试结果的md5并将其与已知商品的md5进行比较。
对于单元测试,我很确定你可以测试个别例程。这将迫使您拥有非常细粒度的开发风格。
答案 8 :(得分:1)
可能想看看this paper
答案 9 :(得分:1)
如果您的目标是优化算法而不是验证正确性,则需要使用指标。一个好的指标可以衡量算法中潜在的性能标准。对于分割算法,这可以是每个分段内像素数据的标准偏差的总和。使用该指标,您可以使用该算法的接受阈值级别或等级版本。
答案 10 :(得分:1)
您可以使用统计方法,其中许多示例和正确的结果,并且测试运行所有这些并在其上评估算法。然后它产生一个数字,即所有数字的组合成功率。
通过这种方式,您对特定故障不太敏感,并且您的测试更加强大。
然后,您可以使用成功率的阈值来查看测试是否失败。