[Insight-developers] Vigra data accessors

Luis Ibanez ibanez at cs.unc.edu
Fri Oct 27 14:31:15 EDT 2000


Hi,

These are some extracts from the article

http://kogs-www.informatik.uni-hamburg.de/~koethe/papers/handbook.ps.gz

from the  Vigra package home page:

http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/

The method used here is what Bill proposed during the tcon,
that is, adding another template parameter to the filter. 
This extra parameter is a class that will specify which
part of the pixel structure will be used as input, and
what part of the output pixel structure will be written on.



======== "Begin of extract 1 from the paper" ===============

6.2.5 Data accessors 
 
The idioms reported so far (generic data structures and algorithms, it­ 
erators, and functors) are the basis of the STL. However, experience has 
shown that algorithms and data structures are not su#ciently indepen­ 
dent as long as we have only a single function 

   iterator::operator*() 

to access the iterator's current data item. There are two fundamental 
problems with this function: First, it assumes that all algorithms want 
to see the entire data at the current position. This makes it
problematic 
to operate on a subset of the actual data structure (such as a single 
color band of an RGB image). Second, *iterator must be used for 
both reading and writing the data. This means, operator*() must 
return the data by reference if we want to overwrite it. This is di#cult 
to implement for certain container implementations (e. g., a multiband 
RGB image). 

Therefore, additional interface objects, called data accessors, are 
needed to encapsulate actual data access (Kühl and Weihe [3]). A data 
accessor reads data at the current iterator position via a get()
function, 
and writes them via a set() function. Within these functions, arbitrary 
adaptations (such as extracting just the red band of an RGB pixel, of 
transforming RGB to gray) can be performed. In general, a data accessor 
looks like this: 

template <typename VALUETYPE, typename ITERATOR> 
struct SomeAccessor 
{ 
  typedef VALUETYPE value_type;               // advertise your value
type 
  value_type get(ITERATOR & i) const;         // read an item 
  void set(value_type v, ITERATOR & i) const; // write an item 
};

 
Using this data accessor, we can implement a more general version 
of the linear copy() algorithm like this: 


template <typename SrcIterator, typename SrcAccessor, 
          typename DestIterator, typename SrcAccessor> 
void copy(SrcIterator s, SrcIterator end, SrcAccessor sa, 
DestIterator d, DestAccessor da) 
{ 
   for(; s != end; ++s, ++d) da.set(sa.get(s), d); // read/write via
accessor 
} 

Although it is probably hard to see the advantages of accessors 
(and generic programming in general) in an algorithm as simple as 
copy(), the same techniques can be applied to arbitrary complicated 
algorithms, where reuse will really pay 


===========  " end of extract 1 " ==========================

======== "Begin of extract 2 from the paper" ===============

Image data accessors 

When we implemented an image iterator for the AbstractImage we 
saw that it was impossible to provide data access operators (operator* 
and operator()) that returned the current data item by reference. An­ 
other common example for a data structure suffering from this prob­ 
lem is the multiband RGB image. In a multiband RGB image, pixel val­ 
ues are stored in three separate images (bands) for each of the three 
color components, rather than in one image of compound RGBStructs 
(as, for example, the RGBStructImage defined in section ``Generic pro­ 
gramming''). A typical implementation of a multiband RGB image could 
look like this: 

class MultibandRGBImage 
{ 
  public: 
  unsigned char & red(int x, int y); 
  unsigned char & green(int x, int y); 
  unsigned char & blue(int x, int y); 
  //... 
private: 
  unsigned char * redband, * greenband, * blueband; 
};
 

The corresponding image iterator would simply mirror the access 
functions of the image: 


struct MultibandRGBImageIterator 
{ 
  // navigation functions not shown ... 
  unsigned char & red(); 
  unsigned char & green(); 
  unsigned char & blue(); 
  /* this is difficult or impossible to implement 
  RGBStruct<unsigned char> & operator*(); 
  RGBStruct<unsigned char> & operator()(int dx, int dy); 
*/ 
};
 
Once again we can not implement the standard access functions 
used within the STL, because the desired return type 

RGBStruct<unsigned char>& 

does not physically exist in the underlying image data structure. Thus, 
while it is easy to define a uniform navigation interface for the itera­ 
tors, we can not guarantee that all iterators have a uniform data access 
interface. Kühl and Weihe [3] proposed an additional level of indirec­ 
tion, the data accessor, to recover the desired uniform interface. As
was 
mentioned earlier, data accessors provide a pair of get() and set() 
functions which are INLINED by the compiler so that the additional in­ 
direction does not a#ect performance. In cases where the iterator pro­ 
vides operator*, get and set simply call it: 


template <typename VALUETYPE, typename STANDARDITERATOR> 
struct StandardAccessor 
{ 
  typedef VALUETYPE value_type; // advertise your value type 
  value_type get(STANDARDITERATOR & i) const { 
  return *i; // read current item 
} 


void set(value_type v, STANDARDITERATOR & i) const { 
   *i = v; // write current item 
}; 


Since the AbstractImageIterator does not work this way, it needs 
a different accessor that could look like this: 

struct AbstractImageAccessor 
{ 
  typedef unsigned char value_type; 
  value_type get(AbstractImageIterator & i) const { 
  return i.get(); 
} 

void set(value_type v, AbstractImageIterator & i) const { 
  i.set(v); 
} 

}; 


In addition to the standard get() and set() functions, an RGB ac­ 
cessor provides functions to access each color separately. These func­ 
tions will be used by algorithms which explicitly require RGB pixels. 
For the multiband RGB image, such an accessor could be defined as 
follows: 


struct MultibandRGBImageAccessor 
{ 
  typedef RGBStruct<unsigned char> value_type; 
  typedef unsigned char component_type; 
  value_type get(MultibandRGBImageIterator & i) const { 
  return value_type(i.red(), i.green(), i.blue()); 
} 

void set(value_type rgb, MultibandRGBImageIterator & i) const { 
  i.red() = v.red; // assume that the iterator 
  i.reen() = v.green; // mirrors the red(), green(), 
  i.blue() = v.blue; // blue() function of the image 
} // which return data by reference 


component_type getRed(MultibandRGBImageIterator & i) const { 
   return i.red(); 
} 

void setRed(component_type v, MultibandRGBImageIterator & i) const { 
   i.red() = v; 
} 

// ... 
}; 


Providing a uniform data access interface regardless of the under­ 
lying image implementation is not the only advantage of introducing 
accessors: they can also be used to perform an arbitrary transforma­ 
tion before the algorithm actually sees the data (for instance, color to 
gray conversion), or to restrict access to just a part of the current
item, 
such as one color component of an RGB pixel. For example, we could 
select just the red band of the RGBStructImage by using the following 
accessor: 

struct RedComponentAccessor 
{ 
  typedef unsigned char value_type; 
  value_type get(RGBStructImage::Iterator & i) { 
  return (*i).red; 
} 

void set(value_type v, RGBStructImage::Iterator & i) const { 
  (*i).red = v; 
} 
};

 
For example, we could now apply a scalar convolution to each color 
component separately by calling the convolution algorithm (Sect. 6.5.3) 
with red, green, and blue band accessors in turn. Without accessors, 
this behavior would be di#cult to implement for the RGBStructImage, 
whereas it would be easy for a MultibandRGBImage. Hence accessors 
serve to smooth out the di#erences between various implementation 
choices for the image data structures which would otherwise make uni­ 
versally reusable algorithm implementations impossible. 


===========  " end of extract 2 " ==========================

Luis

______________________________________________________________________

Luis Ibanez
Research Assistant Professor - Division of Neurosurgery
University of North Carolina at Chapel Hill
CB# 7060, Chapel Hill, NC 27599
email : ibanez at cs.unc.edu       home  : http://www.cs.unc.edu/~ibanez
phone : (919)-843-9961          fax   : (919)-966-6627
______________________________________________________________________




More information about the Insight-developers mailing list