Next: , Up: Customized Arrays


5.1 Multicomponent and complex arrays

Multicomponent arrays have elements which are vectors. Examples of such arrays are vector fields, colour images (which contain, say, RGB tuples), and multispectral images. Complex-valued arrays can also be regarded as multicomponent arrays, since each element is a 2-tuple of real values.

Here are some examples of multicomponent arrays:

     // A 3-dimensional array; each element is a length 3 vector of float
     Array<TinyVector<float,3>,3> A;
     
     // A complex 2-dimensional array
     Array<complex<double>,2> B;
     
     // A 2-dimensional image containing RGB tuples
     struct RGB24 {
       unsigned char r, g, b;
     };
     
     Array<RGB24,2> C;

5.1.1 Extracting components

Blitz++ provides some special support for such arrays. The most important is the ability to extract a single component. For example:

     Array<TinyVector<float,3>,2> A(128,128);
     Array<float,2> B = A.extractComponent(float(), 1, 3);
     B = 0;

The call to extractComponent returns an array of floats; this array is a view of the second component of each element of A. The arguments of extractComponent are: (1) the type of the component (in this example, float); (2) the component number to extract (numbered 0, 1, ... N-1); and (3) the number of components in the array.

This is a little bit messy, so Blitz++ provides a handy shortcut using operator[]:

     Array<TinyVector<float,3>,2> A(128,128);
     A[1] = 0;

The number inside the square brackets is the component number. However, for this operation to work, Blitz++ has to already know how many components there are, and what type they are. It knows this already for TinyVector and complex<T>. If you use your own type, though, you will have to tell Blitz++ this information using the macro BZ_DECLARE_MULTICOMPONENT_TYPE(). This macro has three arguments:

     BZ_DECLARE_MULTICOMPONENT_TYPE(T_element, T_componentType, numComponents)

T_element is the element type of the array. T_componentType is the type of the components of that element. numComponents is the number of components in each element.

An example will clarify this. Suppose we wanted to make a colour image, stored in 24-bit HSV (hue-saturation-value) format. We can make a class HSV24 which represents a single pixel:

     #include <blitz/array.h>
     
     using namespace blitz;
     
     class HSV24 {
     public:
         // These constants will makes the code below cleaner; we can
         // refer to the components by name, rather than number.
     
         static const int hue=0, saturation=1, value=2;
     
         HSV24() { }
         HSV24(int hue, int saturation, int value)
           : h_(hue), s_(saturation), v_(value)
         { }
     
         // Some other stuff here, obviously
     
     private:
         unsigned char h_, s_, v_;
     };

Right after the class declaration, we will invoke the macro BZ_DECLARE_MULTICOMPONENT_TYPE to tell Blitz++ about HSV24:

     // HSV24 has 3 components of type unsigned char
     BZ_DECLARE_MULTICOMPONENT_TYPE(HSV24, unsigned char, 3);

Now we can create HSV images and modify the individual components:

     int main()
     {
         Array<HSV24,2> A(128,128);   // A 128x128 HSV image
         ...
     
         // Extract a greyscale version of the image
         Array<unsigned char,2> A_greyscale = A[HSV24::value];
     
         // Bump up the saturation component to get a
         // pastel effect
         A[HSV24::saturation] *= 1.3;
     
         // Brighten up the middle of the image
         Range middle(32,96);
         A[HSV24::value](middle,middle) *= 1.2;
     }

5.1.2 Special support for complex arrays

Since complex arrays are used frequently, Blitz++ provides two special methods for getting the real and imaginary components:

     Array<complex<float>,2> A(32,32);
     
     real(A) = 1.0;
     imag(A) = 0.0;

The function real(A) returns an array view of the real component; imag(A) returns a view of the imaginary component.

Note: Blitz++ provides numerous math functions defined over complex-valued arrays, such as conj, polar, arg, abs, cos, pow, etc. See the section on math functions (Math functions 1) for details.

5.1.3 Zipping together expressions

Blitz++ provides a function zip() which lets you combine two or more expressions into a single component. For example, you can combine two real expressions into a complex expression, or three integer expressions into an HSV24 expression. The function has this syntax:

     resultexpr zip(expr1, expr2, T_element)
     resultexpr zip(expr1, expr2, expr3, T_element)         ** not available yet
     resultexpr zip(expr1, expr2, expr3, expr4, T_element)  ** not available yet

The types resultexpr, expr1 and expr2 are array expressions. The third argument is the type you want to create. For example:

     int N = 16;
     Array<complex<float>,1> A(N);
     Array<float,1> theta(N);
     
      ...
     
     A = zip(cos(theta), sin(theta), complex<float>());

The above line is equivalent to:

     for (int i=0; i < N; ++i)
        A[i] = complex<float>(cos(theta[i]), sin(theta[i]));