Creating an Application for Image Blurring and Rotation
The code example below represents a simple application that loads an image from the BMP file, rotates and blurs it after user presses left/right or up/down arrow keys.
The source code for this application can be downloaded from the Intel® Integrated Performance Primitives - Sample and Tutorial website.
/* C++ source code is found in ipp_blur_rotate.cpp */
#include "ipps.h"
#include "ipp_blur_rotate.h"
#include "bmpreader.h"
#include <math.h>
#include <stdio.h>
char titleBuffer[256];
video *v;
#if (defined unix || defined UNIX)
#include <X11/keysym.h>
#define VK_LEFT XK_Left
#define VK_UP XK_Up
#define VK_RIGHT XK_Right
#define VK_DOWN XK_Down
#define VK_ESCAPE XK_Escape
#elif defined __APPLE__
#define VK_LEFT 0xf702
#define VK_UP 0xf700
#define VK_RIGHT 0xf703
#define VK_DOWN 0xf701
#define VK_ESCAPE 0x1B
#endif
IppStatus warpAffine(Ipp8u* pSrc, IppiSize srcSize, int srcStep, Ipp8u* pDst, IppiSize dstSize, int dstStep, const double coeffs[2][3])
{
/* IPP functions status */
IppStatus status = ippStsNoErr;
/* number of image channels */
const Ipp32u numChannels = 3;
/* border value to extend the source image */
Ipp64f pBorderValue[numChannels];
/* sizes for WarpAffine data structure, initialization buffer, work buffer */
int specSize = 0, initSize = 0, bufSize = 0;
/* pointer to work buffer */
Ipp8u* pBuffer = NULL;
/* pointer to WarpAffine data structure */
IppiWarpSpec* pSpec = NULL;
/* set offset of the processing destination ROI */
IppiPoint dstOffset = {0, 0};
/* border type for affine transform */
IppiBorderType borderType = ippBorderConst;
/* direction of warp affine transform */
IppiWarpDirection direction = ippWarpForward;
/* set border value to extend the source image */
for (int i = 0; i < numChannels; ++i) pBorderValue[i] = 255.0;
/* computed buffer sizes for warp affine data structure and initialization buffer */
status = ippiWarpAffineGetSize(srcSize, dstSize, ipp8u, coeffs, ippLinear, direction, borderType,
&specSize, &initSize);
/* allocate memory */
pSpec = (IppiWarpSpec*)ippsMalloc_8u(specSize);
/* initialize data for affine transform */
if (status >= ippStsNoErr) status = ippiWarpAffineLinearInit(srcSize, dstSize, ipp8u, coeffs, direction, numChannels, borderType, pBorderValue, 0, pSpec);
/* get work buffer size */
if (status >= ippStsNoErr) status = ippiWarpGetBufferSize(pSpec, dstSize, &bufSize);
/* allocate memory for work buffer */
pBuffer = ippsMalloc_8u(bufSize);
/* affine transform processing */
if (status >= ippStsNoErr) status = ippiWarpAffineLinear_8u_C3R(pSrc, srcStep, pDst, dstStep, dstOffset, dstSize, pSpec, pBuffer);
/* free allocated memory */
ippsFree(pSpec);
ippsFree(pBuffer);
return status;
}
void ipp_blur_rotate::process(const drawing_memory &dm)
{
IppStatus status = ippStsNoErr;
/* number of image channels */
int numChannels = 3;
/* perform filtering */
if (bFilterUpdate)
{
/* temporary work buffer */
Ipp8u* pBuffer = NULL;
/* buffer size for filtering */
int bufSize = 0;
/* Get work buffer size */
status = ippiFilterBoxBorderGetBufferSize(srcSize,maskSize,ipp8u,3,&bufSize);
/* allocate buffer memory */
pBuffer = ippsMalloc_8u(bufSize);
/* Image filtering */
if (status >= ippStsNoErr) status = ippiFilterBoxBorder_8u_C3R(pSrc, srcStep, pBlur, blurStep, srcSize, maskSize, ippBorderRepl, NULL, pBuffer);
/* filtration flag is dropped */
bFilterUpdate = false;
/* rotation operation should be applied after filtration */
bRotateUpdate = true;
/* free buffer memory */
ippsFree(pBuffer);
}
/* perform rotation */
if (bRotateUpdate)
{
IppiSize roiSize = {dstSize.width / 2, dstSize.height };
Ipp8u* pDstRoi = pBlurRot;
IppiRect srcRoi = {0};
srcRoi.width = srcSize.width;
srcRoi.height = srcSize.height;
/* affine transform coefficients */
double coeffs[2][3] = {0};
/* affine transform bounds */
double bound[2][2] = {0};
/* compute affine transform coefficients by angle and x- and y-shifts */
if (status >= ippStsNoErr) status = ippiGetRotateTransform(angle, 0, 0, coeffs);
/* get bounds of transformed image */
if (status >= ippStsNoErr) status = ippiGetAffineBound(srcRoi, bound, coeffs);
/* fit source image to dst */
coeffs[0][2] = -bound[0][0] + (dstSize.width / 2.f - (bound[1][0] - bound[0][0])) / 2.f;
coeffs[1][2] = -bound[0][1] + (dstSize.height - (bound[1][1] - bound[0][1])) / 2.f;
/* perform affine processing for the blurred image */
if (status >= ippStsNoErr) status = warpAffine(pBlur, srcSize, blurStep, pDstRoi, roiSize, blurRotStep, coeffs);
/* set destination ROI for the not blurred image */
pDstRoi = pBlurRot + roiSize.width * numChannels;
/* perform affine processing for the original image */
if (status >= ippStsNoErr) status = warpAffine(pSrc, srcSize, srcStep, pDstRoi, roiSize, blurRotStep, coeffs);
/* rotation flag is dropped */
bRotateUpdate = false;
/* needs to redraw the image */
bRedraw = true;
}
if (bRedraw)
{
drawing_area area( 0, 0, dstSize.width, dstSize.height, dm) ;
/* pass information message to window's title */
#if defined _WIN32
sprintf_s(titleBuffer, sizeof(titleBuffer)/sizeof(titleBuffer[0]), "Intel(R) IPP: blur + rotate tutorial : rotation angle %.0f : box filter mask size {%d, %d}", angle - 360.0 * floor(angle / 360.0), maskSize.width, maskSize.height);
#elif (defined unix || defined UNIX)
sprintf(titleBuffer, "Intel(R) IPP: blur + rotate tutorial : rotation angle %.0f : box filter mask size {%d, %d}", angle - 360.0 * floor(angle / 360.0), maskSize.width, maskSize.height);
#elif defined __APPLE__
sprintf(titleBuffer, "Intel(R) IPP: blur + rotate tutorial : rotation angle %.0f : box filter mask size {%d, %d}", angle - 360.0 * floor(angle / 360.0), maskSize.width, maskSize.height);
#endif
v->title = titleBuffer;
v->show_title();
// fill the rendering area
for (int y = 0; y < dstSize.height; ++y)
{
Ipp8u* dstt = pBlurRot + y * blurRotStep;
area.set_pos( 0, y );
for (int x = 0, j = 0; x < dstSize.width; ++x, j += 3)
{
area.put_pixel( v->get_color(dstt[j+2], dstt[j+1], dstt[j]) );
}
}
bRedraw = false;
}
}
/* Key processing */
void ipp_blur_rotate::onKey( int key )
{
if (pSrc == NULL || pBlur ==NULL || pBlurRot == NULL) return;
/* up or down arrow key is pressed */
if (key == VK_UP || key == VK_DOWN)
{
/* max size of mask for image blurring */
const IppiSize maxMaskSize = {31,31};
/* increase or decrease mask size on 2 depending on the key */
maskSize.width = (key == VK_DOWN) ? maskSize.width - 2 : maskSize.width + 2;
maskSize.height = (key == VK_DOWN) ? maskSize.height - 2 : maskSize.height + 2;
/* check that both mask width and mask height are positive */
if (maskSize.width < 1) maskSize.width = 1;
if (maskSize.height < 1) maskSize.height = 1;
/* check that both mask width and mask height are at more the maximum mask size */
if (maskSize.width > maxMaskSize.width) maskSize.width = maxMaskSize.width;
if (maskSize.height > maxMaskSize.height) maskSize.height = maxMaskSize.height;
/* filtration operation should be applied */
bFilterUpdate = true;
}
/* left or right arrow key is pressed */
if(key == VK_RIGHT || key == VK_LEFT)
{
/* increase or decrease angle on 2 depending on the key */
angle = (key == VK_LEFT) ? angle + 2 : angle - 2;
/* rotation operation should be applied after filtration */
bRotateUpdate = true;
}
if (key == VK_ESCAPE) v->running = false;
}
bool ipp_blur_rotate::loadFileBMP( const char* bmpImageFile )
{
/* check the pointer */
if (bmpImageFile == NULL) return false;
/* number of image channels */
int numChannels = 0;
/* Read data from a file (only bmp format is supported) */
Status status = ReadFile(bmpImageFile, &pSrc, srcSize, srcStep, numChannels);
if (numChannels != 3)
{
status = STS_ERR_UNSUPPORTED;
}
if (status == STS_OK)
{
/* set blurred image step */
blurStep = srcStep;
/* set rotated image size to keep whole rotated image */
dstSize.width = static_cast<int>(sqrt((float)srcSize.width * srcSize.width + srcSize.height * srcSize.height) + 0.5f) * 2;
dstSize.height = static_cast<int>(sqrt((float)srcSize.width * srcSize.width + srcSize.height * srcSize.height) + 0.5f);
/* set image step for blurred and rotated image */
blurRotStep = dstSize.width * numChannels;
/* Memory allocation for the intermediate images */
pBlur = ippsMalloc_8u(srcStep * srcSize.height);
/* Memory allocation for the intermediate images */
pBlurRot = ippsMalloc_8u(dstSize.width * numChannels * dstSize.height);
maskSize.width = 3;
maskSize.height = 3;
bFilterUpdate = bRotateUpdate = bRedraw = true;
return true;
}
return false;
}
ipp_blur_rotate::ipp_blur_rotate()
: angle(0.0), pSrc(NULL), pBlur(NULL), pBlurRot(NULL),
bFilterUpdate(false), bRotateUpdate(false), bRedraw(false)
{
dstSize.width = srcSize.width = 0;
dstSize.height = srcSize.height = 0;
}
ipp_blur_rotate::~ipp_blur_rotate()
{
ippsFree(pSrc);
ippsFree(pBlur);
ippsFree(pBlurRot);
}