views:

321

answers:

8

Recently, I have worked in a project were TDD (Test Driven Development) was used. The project was a web application developed in Java and, although unit-testing web applications may not be trivial, it was possible using mocking (we have used the Mockito framework).

Now I will start a project where I will use C++ to work with image processing (mostly image segmentation) and I'm not sure whether using TDD is a good idea. The problem is that is very hard to tell whether the result of a segmentation is right or not, and the same problem applies to many other image processing algorithms.

So, what I would like to know is if someone here have successfully used TDD with image segmentation algorithms (not necessarily segmentation algorithms).

+2  A: 

I am not really into your problem, so I don't know its hot spots. However, the final result of your algorithm is hopefully deterministic, so you can perform functional testing on it. Of course, you will have to determine a "known good" result. I know of TDD performed on graphic libraries (VTK, to be precise). The comparison is done on the final result image, pixel by pixel. Without going in so much detail, if you have a known good result, you can perform an md5 of the test result and compare it against the md5 of the known-good.

For unit testing, I am pretty sure you can test individual routines. This will force you to have a very fine-grained development style.

Stefano Borini
The problem I think is to get known good result... maybe I will research how the guys of VTK did that (if VTK is a open source library). Testing individual routines rather than the resulting segmented image may be a good idea also.
Alceu Costa
Well, I guess that there's a way to validate your result. I agree that it could not be trivial. I am a quantum chemist, and I know how hard is to know if a given result is correct, because... you don't know "a priori". it just either make sense or not, but a subtle bug would lead to a wrong result which "makes sense" and would be taken as good. The best strategy in this case is to compare your result with the same algorithm implemented by someone else. If two completely different programs give you the same result, you can put a reasonable confidence on it.
Stefano Borini
That only works if you implement a known algorithm someone else has already implemented. In image processing, this is not often the case.
nikie
+4  A: 

I'd say TDD is much easier in such an application than in a web one. You have a completely deterministic algorithm you have to test. You don't have to worry about fuzzy stuff like user input and HTML rendering.

Your algorithm consists of a number of steps. Each of these steps can be tested. If you give them fixed, known input, they should yield fixed, known output. So write a test for that. You can't test that the algorithm "is correct" in general, but you can give it data for which you've already precomputed the correct result, so you can verify that it yields the correct output in that case.

jalf
It may be a silly question, but how can I get the precomputed result when there is no implementation available for the algorithm I will have to write?
Alceu Costa
I don't know the algorithm, so hard to answer for sure. But you don't need a result for the full algorithm, just for individual steps of it. And those can be computed either by hand, or perhaps in Matlab or similar. You might feed your code some predetermined data, and then verify by hand that the output is correct. And then you've got your precomputed result you can use in future tests.
jalf
+5  A: 

at a minimum you can use the tests for regression testing. For example, suppose you have 5 test images for a particular segmentation algorithm. You run the 5 images through the code and manually verify the results. The results, when correct, are stored on disk somewhere, and future executions of these tests compare the generated results to the stored results.

that way, if you ever make a breaking change, you'll catch it, but more importantly you only have to go through a (correct) manual test cycle once.

Steven A. Lowe
No, you can't. You might find an algorithm that works better in general, but yields different results on the 5 unit-test images. So your tests would be extremely fragile if you continue improving your algorithm. (And if you won't try to improve it, than why would you need regression tests.)
nikie
@[nikie]: if you change your algorithm so that it produces different results, then the tests are **supposed** to break. You /want/ regression tests to be fragile, like a canary in a coal mine.
Steven A. Lowe
But that's my point: Regression tests make sense for problems that are clearly defined, like a graph algorithm. Once it does what it's supposed to do, it's behavior shouldn't change, so you make regression tests. But for many image processing problems, you never reach that level of "correctness". There *is* no segmentation algorithm that works for all cases. So you will probably have to adjust your algorithm (and that means different results) to optimize it some day. So regression tests will be in your way, unless you choose to stop development. And then your don't need regression tests either
nikie
@[nikie]: I think I see what you're getting at, the outputs may be too fragile for the tests to survivie even the simplest of improvements. So, if possible, test something less fragile. For example, if your segmentation algorithm is intended to identify something in the image like a set of lines or a tumor or a face, then test for that, not the pixel-level values of the aggregated outputs which might vary as the algorithm is improved. The latter would be testing the math used in the algorithm, and not the application of the algorithm (the "feature" implemented by the algorithm)
Steven A. Lowe
You can use TDD in such a way: got one algorithm, created some unit tests for it. Then you checked what output it produces for several images. You can be sure this algo returns this thing if works well. Make a test for that. then you can continue doing anything in other places and running this test will tell you that it still works as it did (no side effects). When need to improve it - update your tests. Sure, more work but you can be sure algoruthm always works as you expect of it to work.
Yaroslav Yakovlev
+3  A: 

I think the best you can do is test the simple, mathematically well-defined building blocks your algorithm consists of, like linear filters, morphological operations, FFT, wavelet transforms etc. These are often tricky enough to implement efficiently and correctly for all border cases so verifying them does make sense.

For an actual algorithm like image segmentation, TDD doesn't make much sense IMHO. I don't even think unit-tests make sense here. Sure, you can write tests, but those will always be extremely fragile. A typical image processing algorithm needs a few parameters that have to be adjusted for the desired results (a process that can't be automated, and can't be done before the algorithm is working). The results of a segmentation algorithm aren't well defined either, but your unit test can only test for some well-defined property. An algorithm can have that property without doing what you want, or the other way round, so your test result isn't very informative. Also, to test the results of a segmentation algorithm you need to write a lot of pretty hard code, while verifying the results visually is pretty easy and you have to do it anyway.

I think in a way it's similar to unit-testing user interfaces: Testing the actual well-defined functionality (e.g. when the user clicks this button, some item is added to this list and this label shows that text...) is relatively easy and can save a lot of work and debugging. But no test in the world will tell you if your UI is usable, understandable or pretty, because these things just aren't well defined.

nikie
+2  A: 

Whenever I do any computer-vision related development TDD is almost standard practice. You have images and something you want to measure. Step one is to hand-label a (large) subset of the images. This gives you test data. The process (for full correctness) is then to divide your test-set in two, a "development set" and a "verification set". You do repeated development cycles until your algorithm is accurate enough when applied to the development set. Then you verify the result on the veriication set (so that you're not overtraining on some weird aspect of your development set. This is test driven development at its purest.

Note that you're testing two different things when developing heavily algorithm dependent software like this.

  1. The regular bugs you'll get in your software. These can be tested using "normal" TDD techniques
  2. The performance of your algorithm, for which you need a system outlined above.

A program can be bug free according to (1) but not quite according to (2). For example, a very simple image segmentation algorithm says: "the left half of the image is one segment, the right half is another segment. This program can be made bug free according to (1) quite easily. It is another matter entirely wether it satisfies your performance needs. Don't confuse the two aspects, and don't let one interfere with the other.

More specifically, I'd advice you to develop the algorithm first, buggy warts and all, and then use TDD with the algorithm (not the code!) and perhaps other requirements of the software as specification for a separate TDDevelopment process. Doing unit tests for small temporary helper functions deep within some reasonably complex algorithm under heavy development is a waste of time and effort.

jilles de wit
A: 

Might want to take a look at this paper

Maleev
+1  A: 

The image processing tests that you describe in your question take place at a much higher level than most of the tests that you will write using TDD.

In a true Test Driven Development process you will first write a failing test before adding any new functionality to your software, then write the code that causes the test to pass, rinse and repeat.

This process yields a large library of Unit Tests, sometimes with more LOC of tests than functional code!

Because your analytic algorithms have structured behavior, they would be an excellent match for a TDD approach.

But I think the question you are really asking is "how do I go about executing a suite of Integration Tests against fuzzy image processing software?" You might think I am splitting hairs, but this distinction between Unit Tests and Integration Tests really gets to the heart of what Test Driven Development means. The benefits of the TDD process come from the rich supporting fabric of Unit Tests more than anything else.

In your case I would compare the Integration Test suite to automated performance metrics against a web application. We want to accumulate a historical record of execution times, but we probably don't want to explicitly fail the build for a single poorly performing execution (which might have been affected by network congestion, disk I/O, whatever). You might set some loose tolerances around performance of your test suite and have the Continuous Integration server kick out daily reports that give you a high level overview of the performance of your algorithm.

marshally
+1  A: 

TDD in image processing only makes sense for deterministic problems like:

  • image arithmetic
  • histogram generation
  • and so on..

However TDD is not suitable for feature extraction algorithms like:

  • edge detection
  • segmentation
  • corner detection

... since no algorithm can solve this kind of problems for all images perfectly.

Amro