The optimum choice for the bit precision of the video signals of a video processing algorithm may differ for each particular implementation of that algorithm. The re-usability of an application model therefore improves when it allows a range of bit precisions. In support of this, VYA requires that the bit precision of the video input and the video output signals of each model is parametrized. An adverse impact on the simulation speed is prevented by adopting a very simple mechanism for this purpose: type VYApixel is assumed to range from to , while the effective range of the video input and/or output pixels is defined by parameters. To reflect that the bit precision of an implementation is fixed, the bit precision parameters are passed as arguments in the constructor of a process (network), which allows them to be programmable yet forces them to be constant during each instantiation. For example:
class myVYAprocess : public VYAprocess { public: // constructor myVYAprocess( Id n, VYAbitPrecision inPrec, VYAbitPrecision outPrec, ... }; |
Class VYAbitPrecision is defined in vya.h,cc as follows:
class VYAbitPrecision { public: // constructors VYAbitPrecision(); VYAbitPrecision(VYAbitPrecision&); VYAbitPrecision(unsigned int, bool); // member variables unsigned int bits; bool signbit; }; |
Table 2 explains how the bit precision parameters determine the pixel range. These parameters must be supplied for input as well as output video interfaces. When a module has multiple video input and/or output interfaces, the programmer can choose to provide separate parameters for each interface or to combine them into a single parameter - e.g., UbitPrecIn and VbitPrecIn vs. UVbitPrecIn. To prevent incorrect behavior caused by illegal parameter values (e.g. signbit = true for a Y interface), modules must check parameter correctness by calling function VYAcheckPrecision which is a member function of VYAprocess provided in vya.h,cc.
The internal precision of an algorithm must be sufficient to handle the maximum input pixel range indicated in Table 2. Generally, it will suffice to use a 32-bit data type like int for intermediate results. Final results must be normalized to the required output precision; for this purpose, vya.h provides inline functions for rounding, shifting, clipping etc.
Because mapping an algorithm to an efficient implementation is facilitated by understanding its internals, the internal precision of a VYA module is preferably indicated by means of comments. In the example shown below, a filter with gain 29 is applied to a luminance line. By definition, the overall gain of a module equals , which implies that the filter output must be normalized by dividing it by using round and shift operations. Luminance data being unsigned, the result must finally be clipped between 0 and 2outPrec.bits-1 to ensure the correct output range. Comments indicate the bit precision of the input data and of the result of every processing step. The format used is s.n.m, where, s indicates the sign bit (0: positive; 1: negative; s: positive or negative), n indicates unused bits, and m indicates magnitude bits. Besides 16 bits for type VYApixel, this example assumes 32 bits for type int.
void myVYAprocess::processLine() { int min, max, sf, data; unsigned int pix; min = 0; max = (1 << outPrec.bits) - 1; sf = inPrec.bits - outPrec.bits; // scale factor for (pix=0; pix<imgWidth; pix++) { // read pixel data = (int) Yin[pix]; // {0.31-inBits.inBits} // insert processing here // round, normalize and clip data = RNORM(data, sf); // {0.31-outBits.outBits} data = CLIP(data, min, max); // {0.31-outBits.outBits} // write pixel Yout[pix] = (VYApixel) data; // {0.15-outBits.outBits} } } |