Processing an Image from Edge to Edge

Intel® IPP image filtering functions assume that for each pixel being processed, adjacent pixels also exist. If required adjacent pixel values are missing, a memory violation or access violation error will occur. There are two ways to resolve these errors.

1. Process the edges with adjusted anchor point and ROI. Process the edges with an adjusted mask, anchor point, and ROI.

Depending on image size and filter size, adjusting the anchor point and ROI may eliminate the need for adding data to the image border.

Code Example: In this sample. we ignore the border pixels, our ROI only include the area one pixel from the border.

IppiSize roiSize = {1022, 1022};
IppiSize imgSize = {1024, 1024};
size_t size = imgSize.width*imgSize.height* sizeof(Ipp8u);
int srcStep = imgSize.width * sizeof(Ipp8u);
Ipp8u* data = (Ipp8u*)malloc(size);
Ipp8u *pStartPoint; pStartPoint = data;
ippiImageJaehne_8u_C1R(pStartPoint , srcStep, imgSize);
int dstStep = roiSize.width * sizeof(Ipp8u);
size_t dstSize = roiSize.width*roiSize.height* sizeof(Ipp8u); 
Ipp8u* dst = (Ipp8u*)malloc(dstSize);
ippiFilterGauss_8u_C1R(data+srcStep/sizeof(Ipp8u)+1, srcStep, dst, dstStep, roiSize, ippMskSize3x3);

If the filtering operation occurs on a section of the source image (ROI), then the necessity of adding border pixels depends upon the ROI size and position. If the image edges are part of the ROI, border pixels must be added (see below).

2. Duplicate the edge pixels around the image.

In this case, you need to:

  1. Determine which additional border pixels are required
  2. Creat/define these pixels

Special functions have been developed for extending image edges:

Function Description
ippiCopyReplicateBorder Copies pixel values between two buffers and adds the replicated border pixels.
ippiCopyWrapBorder Copies pixel values between two buffers and adds the border pixels.

Code Example: In this sample, we use ippiCopyReplicateBorder_8u_C1IR() function to extend the image border. This ensures that all of the pixels in the ROI have neighbor pixels to process.

IppiSize roiSize = {1024, 1024};
IppiSize imgSize = {1026, 1026};
size_t size = imgSize.width*imgSize.height* sizeof(Ipp8u);
int srcStep = imgSize.width * sizeof(Ipp8u);
Ipp8u* data = (Ipp8u*)malloc(size);
Ipp8u *pStartPoint;
pStartPoint = data + (1 * srcStep/sizeof(Ipp8u)) + 1;
ippiImageJaehne_8u_C1R(pStartPoint , srcStep, roiSize);
ippiCopyReplicateBorder_8u_C1IR(pStartPoint , srcStep, roiSize, imgSize , 1, 1);
int dstStep = dstRoi.width * sizeof(Ipp8u);
size_t dstSize = roiSize.width*roiSize.height;
Ipp8u* dst = (Ipp8u*)malloc(dstSize);
ippiFilterGauss_8u_C1R(data, srcStep, dst, dstStep, roiSize, ippMskSize3x3);

3. Related topic
Some of IPP image processing function also require external working buffer (ippiResizeSqrPixel) or special state structure as an input parameter in order to easily memory management. 
For example, the Intel® IPP ippiDilateBorderReplicate requires one IppiMorphState structure as parameter. You can use the following sequence to call the ippiDilateBorderReplicate function:

  1. Call function ippiMorphologyGetSize to get the size requirement for morphology state structure.
  2. Ensure that the required memory space for morphology state structure is properly allocated.
  3. Call the ippiMorphologyInit function to initiate morphology state structure.
  4. Use the ippiDilateBorderReplicate function in your application.
  5. Free the memory allocated for morphology state structure

Here is an example of ippiDilateBorderReplicate function use:

IppStatus status;
Ipp8u x[7*5],y[11*9];
IppiSize roi = {7,5}, masksize={3,3};
Ipp8u Mask[3*3]={ 1,1,1,1,1,1,1,1,1}
IppiPoint anchor={1,1};
int memorysize;
IppiMorphState* state;
ippiMorphologyGetSize_8u_C1R(roi.width, Mask, masksize, &memorysize);
state = (IppiMorphState*) ippsMalloc_8u(memorysize);
ippiMorphologyInit_8u_C1R(roi.width, Mask, masksize, anchor, state);
re=ippiDilateBorderReplicate_8u_C1R(x, 7, y, 11, roi, ippBorderRepl, state);
Note the parmaeter in the function : stepBytes. It is the distance in bytes of image row. It depends on your array memory layout and data type.  In most of case, it is equal to the image Width*sizeof(datatype)*Channel.  But sometimes, it is not, especially for bmp image and ippMalloc, which required 4 bytes aligned and 32 bytes aligneed correspondingly. there are padded zero at the end of row. so please take care when use stepBystes or shift the pointer by stepBystes.
For more complete information about compiler optimizations, see our Optimization Notice.