On the basis of the proposed iterator interface we can define itera- tors that modify the standard behavior in various ways. In many cases this allows for improving reusability by turning algorithms into itera-
tor adapters. For example, algorithms that need 1-D projections of the
image (i.e., a particular order in which all or some pixels are visited) can be generalized by encapsulating the particular projection into appropri- ate iterator adapters. By exchanging iterator adapters, different access sequences can be realized without changing the actual algorithm.
The simplest 1-D iterator adapter is, of course, the scan line iter- ator, which scans the entire image in scan line order. It can often be implemented as a normal pointer to the raw image data and this makes
128 6 Reusable Software in Computer Vision Table 6.2: Performance measurements for different implementations of the averaging algorithm Implementation Variant System 1 2 3 4 1 2.75 s (100 %) 12.6 s (460 %) 7.5 s (270 %) 3.3 s (120 %) 2 9.9 s (100 %) 42.2 s (425 %) 35.6 s (360 %) 18.5 s (190 %) 3 11.5 s (100 %) 64.8 s (560 %) 55.7 s (480 %) 17.0 s (150 %) 4 8.1 s (100 %) 38.4 s (470 %) 13.5 s (170 %) 9.1 s (112 %) System 1 SGI O2, IRIX 6.3, SGI C++ 7.1
System 2 SGI INDY, IRIX 5.3, SGI C++ 4.0 (outdated compiler) System 3 Sun SparcServer 1000, Solaris 5.5, Sun C++ 4.2 System 4 PC Pentium 90, Windows NT 4.0, Microsoft VC++ 4.0
it very fast. Thus it is best suited for internal copy and initialization operations, when we need to process the entire image very fast. 6.7.1 Row and column iterators
Row and column iterators are very useful iterator adapters because they support the implementation of separable algorithms. They provide an interface compatible with the STL’s random access iterators and restrict navigation to the specified row or column:
template <class ImageIterator> struct RowIterator
{
RowIterator(ImageIterator const & i) // position of iterator i : iter(i) // determines row to operate on {}
RowIterator & operator++() {
iter.x++; // go always in x direction return *this;
}
value_type & operator*() {
return *iter; // delegate access to enclosed image iterator }
// etc...
ImageIterator iter; };
Now, when we want to define a separable algorithm, just one im- plementation is sufficient for both directions (and in fact for any 1-D projection), because the actual direction is specified solely by the type of the iterator adapter passed to the algorithm. Consider the following 1-D algorithm for a recursive exponential filter:
6.7 Image iterator adapters 129
template <class Src1DIterator, class SrcAccessor, class Dest1DIterator, class DestAccessor> void recursiveSmoothSignal(
Src1DIterator sbegin, Src1DIterator end, SrcAccessor sa, Dest1DIterator dbegin, DestAccessor da, float scale) {
... }
If we recall that this algorithm can operate in-place (i. e., source and destination signal can be identical, so that no temporary signal must be generated), we can implement the 2-D recursive filter by simply call- ing the 1-D version twice, first using row iterators, then using column iterators:
template <class SrcImageIterator, class SrcAccessor, class DestImageIterator, class DestAccessor> void recursiveSmoothImage(
SrcImageIterator sul, SrcImageIterator slr, SrcAccessor sa, DestImageterator dul, DestAccessor da, float scale) {
int width = slr.x - sul.x; // calculate size int height = slr.y - sul.y; // of image
DestImageIterator destul = dul; // save iterator for later use for(int y=0, y<height, ++sul.y, ++dul.y, ++y)
{
RowIterator<SrcImageIterator> sr(sul); // create iterator RowIterator<DestImageIterator> dr(dul); // adapters for row // convolve current row
recursiveSmoothSignal(sr, sr+width, sa, dr, da, scale); }
for(int x=0, dul=destul; x<width; ++dul.x, ++x) {
ColumnIterator<DestImageIterator> dc(dul); // adapter for column // convolve current column (in-place)
recursiveSmoothSignal(dc, dc+height, da, dc, da, scale); }
}
6.7.2 Iterator adapters for arbitrary shapes
The idea of row and column iterators is easily generalized to arbitrarily shaped linear structures such as lines, rectangles, ellipses, and splines. For example, we can turn Bresenham’s algorithm for drawing a straight line into an iterator adapter like this:
template <class ImageIterator> struct BresenhamLineIterator {
BresenhamLineIterator(ImageIterator start, ImageIterator end) : iterator_(start), x_(0.0), y_(0.0)
{
int dx = end.x - start.x; // calculate the distance int dy = end.y - start.y; // from start to end
int dd = max(abs(dx), abs(dy)) > 0 ? max(abs(dx), abs(dy) : 1; dx_ = (float)dx / abs(dd); // init the appropriate
130 6 Reusable Software in Computer Vision
Figure 6.2:A ContourIterator (white arrows) follows the contour of the darkest region.
dy_ = (float)dy / abs(dd); // increments (Bresenham algorithm) }
BresenhamLineIterator & operator++() {
// calculte the next pixel along the line and advance // ImageIterator accordingly
} // ...
bool operator==(BresenhamLineIterator const & r) const { return iterator_ == r.iterator_; // delegate comparison to } // internal image iterators ImageIterator::PixelType & operator*() {
return *iterator_; // likewise delegate access }
ImageIterator iterator_; float x_, y_;
};
A general drawing algorithm would now look like this:
template <class Iterator, class Accessor, class Color>
void drawShape(Iterator i, Iterator end, Accessor a, Color color) {
for(; i != end; ++i) a.set(color, i); }
By passing different iterators, this algorithm can draw any kind of shape. Similarly, we can implement an algorithm to output the intensity profile along an arbitrary contour, and we can even apply the linear convolution defined here to any curved line, always using the same set of iterator adapters to determine the curve.
There are many more possible iterator adapters that we can not describe here. To mention just a few: chain code iterators proceed according to a given chain code. Contour iterators follow the contour of a labeled region in a segmented image (see Fig.6.2). Region iterators scan all pixels in a given region, which lets us calculate region statistics or fill the region with a new color. Interpolating iterators can be placed on noninteger positions and return interpolated image data there.
6.8 Conclusions 131
6.8 Conclusions
This chapter introduced a generic programming approach to the devel- opment of reusable algorithms in image processing and analysis. It is based on ideas made popular by the C++ Standard Template Library and extends its abstract iterator design to the domain of 2-D images. This approach overcomes a number of limitations of traditional ways to design reusable software:
• Programming is more efficient than with traditional methods be- cause a single algorithm implementation can be adapted to many different situations.
• There is only a small performance penalty compared to an opti- mized version of the algorithm. Once the optimizers catch up, it is expected that the performance penalty can be eliminated altogether.
• A smooth transition to generic programming is possible: iterators can be implemented for existing data structures. Switching to ge- neric programming does not influence any existing code. Existing code can be transformed into a generic form as needed.
• Implementing generic algorithms is reminiscent of the traditional structured programming paradigm which with many researches in computer vision are already familiar.
Besides the results reported here, we have successfully applied the same techniques to build and manipulate graph-based representations of image contents, such as feature adjacency graphs, feature correspon- dences across image ssequences, scene graphs, and geometric models. Our experience also showed that a relatively small number of iterator, accessor and adapter implementations suffice to support a wide variety of different environments, image data types, and applications.
It has proven very effective to combine generic methods with other software design approaches such as component-based development (Chapter4) and object-oriented design (Chapter5). The basic idea here is to use objects and components to arrange functionality and to repre- sent their relationships according to the needs of a particular applica- tion, while most of the real work is delegated to generic building blocks residing below. In this way, strengths and weaknesses of the different methods are optimally balanced.
For example, in a digital photogrammetry system under develop- ment in our institute, we have wrapped generic algorithms and data structures into an object-oriented class hierarchy. In contrast to earlier designs, a reorganization of this class hierarchy did not affect the al- gorithms’ implementations—the compiler automatically generated the new versions needed by the revised objects, thus saving us from a lot of work. In another project, we similarly wrapped generic build-
132 6 Reusable Software in Computer Vision ing blocks into PYTHON modules. PYTHON is a public domain script- ing language that can be extended by C and C++ libraries (Website at
http://www.python.org). Thus, with minimal additional effort we were able to build a simple (command driven) interactive image pro- cessing system on top of the generic VIGRA library.
Using the described approach, change and reuse of image process- ing and analysis algorithms has become much easier in our organiza- tion. Not only has programming productivity increased, but, perhaps more importantly, the psychological barrier to modify existing solu- tions has been lowered because it became so much easier and safer to adapt the existing code to new ideas. It would be highly desirable to officially standardize a common set of iterators and accessors in or- der to prevent any compatibility problems between implementations that may otherwise arise. For version 1.0 of the VIGRA library see /software/06on the CD-ROM. The latest version can be downloaded fromhttp://www.egd.igd.fhg.de/˜ulli/vigra/.
6.9 References
[1] Khoral Research Inc., (1996). KHOROS Documentation (http://www.khoros.unm.edu/).
[2] Musser, D. and Stepanov, A., (1989). Generic Programming. In 1st Intl. Joint Conf. of ISSAC-88 and AAEC-6. Berlin: Springer.
[3] Musser, D. and Stepanov, A., (1994). Algorithm-oriented generic libraries. Software - Practice and Experience,24(7):623–642.
[4] Musser, D. and Saini, A., (1996). STL Tutorial and Reference Guide. Reading, MA: Addison-Wesley.
[5] Gamma, E., Helm, R., Johnson, R., and Vlissides, J., (1994). Design Patterns. Reading, MA: Addison-Wesley.
[6] Kühl, D. and Weihe, K., (1997). Data Access Templates, C++ Report July/August.
[7] Myers, N., (1995). A New and Useful Template Technique: Traits, C++ Report, June.
7 Application-oriented Assessment
of Computer Vision Algorithms
Peter Klausmann
1,Stefan Fries
1,Dieter Willersinn
1,
Uwe Stilla
2, andUlrich Thönnessen
21Fraunhofer-Institut für Informations- und Datenverarbeitung (IITB)
Karlsruhe, Germany
2Forschungsinstitut für Informationsverarbeitung und Mustererkennung
Ettlingen, Germany
7.1 Introduction . . . 133 7.2 Analytical versus empirical performance analysis. . . 134 7.2.1 Analytical performance characterization . . . 134 7.2.2 Empirical performance characterization . . . 135 7.3 Application-oriented empirical algorithm assessment . . . 136 7.3.1 Task, performance criteria and requirement profile . 137 7.3.2 Assessment data . . . 138 7.3.3 Image data acquisition . . . 140 7.3.4 Provision of training data for development. . . 140 7.3.5 Algorithm performance characterization . . . 140 7.3.6 The assessment function. . . 141 7.3.7 Overview of the assessment procedure . . . 142 7.4 The assessment system. . . 143 7.5 Example: Assessment of a detection algorithm . . . 145 7.6 Conclusion . . . 149 7.7 References . . . 149
7.1 Introduction
The crucial question to be answered during the assessment of a com- puter vision algorithm is to what extent is the algorithm performance useful? The utility of an algorithm can only be stated with respect to an application, hence the assessment of computer vision algorithms
133
Handbook of Computer Vision and Applications Copyright © 1999 by Academic Press
Volume 3 All rights of reproduction in any form reserved.
134 7 Application-oriented Assessment of CV Algorithms is only possible if the application of the computer vision algorithm is given.
The assessment of a computer vision algorithm falls into two parts, namely, algorithm performance characterization, and the decision as to whether the attained performance is sufficient for the given application. For an application-oriented assessment of computer vision algorithms both questions must be addressed.
Section7.2presents an overview of approaches to characterize the performance of computer vision algorithms. Section7.3describes our concept for the application-oriented assessment of computer vision al- gorithms. The concept covers both the performance characterization and the assessment of algorithm performance. Our assessment system is described in Section7.4. Section7.5 describes the assessment of a detection algorithm for two different applications.