PARP Research Group Universidad de Murcia


Interoperability with the IPP library

To enable the QVision to interoperate with the IPP, the following line must be present (and un-commented) in the config.pri file, prior to compilation and installation of the QVision library:

CONFIG += qvipp

Any program using the QVision framework IPP wrapper must include the following heade in its source code:

#include <qvipp.h>

From then on, both the QVision library and the developed applications will automatically include and link the adequate files from the IPP library.

Directly using QVision image objects with native IPP functions

The simplest way of using a QVision image on a IPP function, is by using the QVImage::operator() operator, and the QVImage::getStep(), QVImage::getRows() and QVImage::getCols() methods from the class QVImage. For example, the IPP function Set has the following header signature:

IppStatus ippiSet_8u_C1R(Ipp8u value, Ipp8u* pDst, int dstStep, IppiSize roiSize);

The following code will apply that function to a single channel, gray-scale image:

#include <qvip.h>

// [...]

QVImage<> image;

ippiSet_8u_C1R( 128,                                            // Value to set image pixels.
                &image(0,0),                                    // Pointer to the pixel (0,0).
                image.getStep(),                                // Step of the image.
                (IppiSize){ image.getCols(), image.getRows() }  // Size of the image to be processed
                                                                // by the IPP function.
                );

But the former method is perhaps too low-level to work with under the QVision framework. The following section exposes a more adequate method for using QVision images with IPP functions.

The IPP wrapper functions

The QVision offers a set of wrapper functions to use the Intel's Performance Primitives library in an object oriented fashion. For each one of the most commonly used functions in the IPP library, the QVision provides an homonimous wrapper function that takes the same input images and data, and calls the original IPP function to process them.

The difference between the original IPP function and the wrapper function, is that the latter takes QVImage and/or QVMatrix objects, instead of a pointer to the image or matrix content, and the image step, whenever an image is required as input parameter.

You can see the full list and documentation of the IPP wrapper functions in the group IPP wrapper functions. The following subsections detail their usage.

IPP wrapper function naming conventions

We take for instance the functions used to add two image in the IPP library. There is a whole family of them, named with the prefix ippiAdd_, followed by a suffix indicating relevant information about the storage type of the pixels contained the image, the image number of channels, and so on.

For example, the function ippiAdd_8u_C1RSfs is used to add two 8-bit unsigned data type images, composed by one single channel, storing the result in a destination image of the same type. That function has the following header:

IppStatus ippiAdd_8u_C1RSfs(
        const Ipp<Ipp8u>* pSrc1, int src1Step,
        const Ipp<Ipp8u>* pSrc2, int src2Step,
        Ipp<Ipp8u>* pDst, int dstStep,
        IppiSize roiSize,
        int scaleFactor);

The QVision offers a wrapper function named Add, which uses the following header:

void Add(       const QVImage<uChar, 1> & qvimage_pSrc1,
                const QVImage<uChar, 1> & qvimage_pSrc2,
                QVImage<uChar, 1> & qvimage_pDst,
                const int scaleFactor = 1,
                const QPoint &destROIOffset = QPoint(0,0));

The input image object type parameter qvimage_pSrc1 in the Add function substitutes the input parameters pSrc1 and src1Step from the IPP function ippiAdd_8u_C1RSfs (corresponding to the image data pointer and image step).

The body of the Add function calls the IPP function, mapping the pointer to the data buffer of the image qvimage_pSrc1 and its step value respectively to the input parameters pSrc1 and src1Step of the IPP function.

The gain with this approach is double. First, the interface of the Add function is clearer than the header of its IPP counterpart. The simpler name of the former (which omits the pixel depth and channel number suffix) grants an easier and more robust object-oriented usage. By overloading that name, we can select which of the Add functions should be called, depending on the type of the input images.

Second, images require only one input parameter in the wrapper function, instead of the two required in the original IPP function.

A typical call to the IPP original function may look like this:

IppiSize size = { cols, rows };
IppStatus status = ippiAdd_8u_C1RSfs(img1Ptr, img1Step, img2Ptr, img2Step, imgDestPtr, imgDestStep, size, 1);

Calls to the Add function can be like this:

Add(img1, img2, imgDest);       // No roiSize required.
Add(img1, img2, imgDest, 2);    // Factor different than 1.
Add(img1, img2, imgDest, 1, QPoint(10,10) );    // Destination ROI offset different than the default.
                                                // (its meaning and usage is discussed below).

QVision naming for IPP pixel depth notation

The QVision offers an alternative notation for bit-depth types, to make them more human-readable. The following table illustrates the type equivalence between IPP image and QVImage depth types:

QVision type uChar uShort uInt sChar sShort sInt sFloat sDouble
IPP type Ipp8u Ipp16u Ipp32u Ipp8s Ipp16s Ipp32s Ipp32f Ipp64f

Both naming conventions are interchangeable, but in the source code of the toolkit we preferred the first one.

Regions of Interest (ROI)

Most of the IPP functions can restrict their operations to a small area of the input images. Aritmetical operators, filtering functions, color conversion functions, etc... can be applied only to a rectangular area inside the input image, which can include the whole image if neccesary.

QVImage objects have a property named ROI which contains a QRect object modeling the rectangular area inside the image, which is used as the Region of Interest by the IPP functions that operate with it. This rectangle can be read and modified with several methods from the QVGenericImage class: QVGenericImage::getROI, QVGenericImage::setROI, QVGenericImage::erodeROI, QVGenericImage::dilateROI, QVGenericImage::resetROI and so on.

Usage of the ROI in image processing

This is a ROI usage example code: The following code illustrates the usage of the ROI with the Copy function:

#include <qvipp.h>      // QVIPP functions are included in this header file.
[...]

QVImage<uChar> sourceImage("tajMahal.png");
sourceImage.setROI(10,10,90,90);        // This sets the ROI of the input image.

QVImage<uChar> destinationImage(200, 200);
Copy(sourceImage, destinationImage);

[...]

The figure below shows the result of that code on an input image. The left image is the source image, containing the tajMahal image. The right image shows the result of the Copy operation. The black area can contain unspecified content, not necessarily black, if it was not previously initialized so.

tajmahalcopyroi.png

The ROI is commonly used to specify the portion of the image which contains valid information. Thus, after the copy operation of the previous example, the ROI of the destinationImage will be set to contain only the part of the image which really shows a part of the Taj Mahal -that is, that contains "valid" data-.

Note:
If the destination image is not large enough to contain the ROI, it will be re-sized. The new content of the image, outside the original image size, will be unspecified.

Each image processing function should update the ROI of the output image or images, so that they contain the correct area computed by the operations, and which can be used in posterior processing. The following code is useful to illustrate this:

[...]

QVImage<uChar> sourceImage("lena.png");
sourceImage.setROI(100, 110, 90, 40);   // This sets the ROI of the input image.

QVImage<uChar> temporaryImage(256, 256);
FilterGauss(sourceImage, temporaryImage, 5);

QVImage<uChar> destinationImage(256, 256);
FilterGauss(temporaryImage, destinationImage, 5);

[...]

It applies two Gaussian filter on the lena image. The first call to FilterGauss will store in the ROI of the temporaryImage the area of the image which contains valid data from its operations, so the next call to FilterGauss will only work with that part of the image -the one that now is supposed to be valid-.

lenagauss_5_5roi.png

Of course, and if needed, the programmer can anyway set another ROI at any time by explicitly calling the method QVImage::setROI().

Destination ROI pointer

In some cases the developer may want to indicate a location for the ROI in the destination image. The user can indicate in the parameter destROIOffset (present in most of the IPP wrapper functions) the point in the destination image where the function must locate the top left corner of the ROI.

This parameter is included in the header of several functions from the package IPP wrapper functions, the Copy function amongst them. The following code illustrates the usage of the destROIOffset parameter:

[...]

QVImage<uChar> sourceImage("tajMahal.png");
sourceimage.setROI(10,10,90,90);        // This sets the ROI of the input image.

QVImage<uChar> destinationImage(200, 200);
Copy(sourceimage, destinationImage, QPoint(60,30));

[...]

The QPoint(60,30) parameter in the call to the Copy function indicates that it should copy the content of the ROI in the source image to the destination location, starting at the point (60,30):

tajmahalcopyroianchor.png
Note:
When dealing with several input images, the IPP wrapper functions functions usually perform a ROI size checking to ensure that the ROI of all the input images is adequate. For example, the Add function checks that both of the input images have the same ROI size. A correct example usage of the Add function would be this:
[...]
// lena is an image of size 256x256. tajMahal is an image of size 200x200.
QVImage<uChar> tajMahal("tajMahal.png"), lena("lena.png");

lena.setROI(45,65,155,85);                      // Set initial ROI for image sourceImage1.
tajMahal.setROI(30,20,155,85);                  // Set initial ROI for image sourceImage2.
                                                // ROI's have a dimension of 155x85 pixels
QVImage<uChar> destinationImage(230,230);       // 'destinationImage' has size 230x230

Add(lena, tajMahal, destinationImage, QPoint(10,20));
[...]
The following picture illustrates the result of that code:
tajmahallenacopyroianchor.png
If the developer provides the Add function two images with an incorrect ROI size, and if the program executes in DEBUG mode, a Q_ASSERT will be raised and the program will stop, indicating the error.



QVision framework. PARP research group. Copyright © 2007, 2008, 2009, 2010, 2011.