Click here to Skip to main content
15,896,912 members
Articles / Multimedia / Image Processing

Oil Paint Effect: Implementation of Oil Painting Effect on an Image

Rate me:
Please Sign up or sign in to vote.
4.89/5 (41 votes)
20 Oct 2012CPOL8 min read 116.2K   5.3K   68  
Applying oil painting effect on an image.
// PaintEffect1.cpp: implementation of the PaintEffect class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PaintEffect.h"
#include "PaintEffectImpl.h"
#include "math.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

PaintEffect::PaintEffect()
{

}

PaintEffect::~PaintEffect()
{

}

/*
// Parameters:
pbyDataIn_i: Input RGB buffer of input image.
nRadius:     Radius of processing. This values is used to consider nearest pixels.
             If this value is high, processing cost will increase. 2 ~5 are good values.
fIntensityLevels: Applied to r,g,b values intensity.
                  Increasing this values will create blocky output image.
nWidth: Width of image.
nHeight: Height of image.
pbyDataOut_o : Output RGB buffer.
 */
void PaintEffect::Process( const BYTE* pbyDataIn_i,
                           const int nRadius_i,
                           const float fIntensityLevels_i,
                           const int nWidth_i,
                           const int nHeight_i,
                           BYTE* pbyDataOut_o )
{
    int nIntensityCount[256];
    int nSumR[256];
    int nSumG[256];
    int nSumB[256];

    // Border pixes( depends on nRadius) will become black.
    // On increasing radius boundary pixels should set as black.
    memset( pbyDataOut_o, 0, nWidth_i * nHeight_i * 3 );

    // If total bytes in a row of image is not divisible by four, 
    // blank bytes will be padded to the end of the row.
    // nBytesInARow bytes are the actual size of a row instead of nWidth * 3.
    // If width is 9, then actual bytes in a row will will be 28, and not 27.
    int nBytesInARow = ceil( nWidth_i * 3 / 4.0 ) * 4.0;

    // nRadius pixels are avoided from left, right top, and bottom edges.
    for( int nY = nRadius_i; nY < nHeight_i - nRadius_i; nY++)
    {
        for( int nX = nRadius_i; nX < nWidth_i - nRadius_i; nX++)
        {
            // Reset calculations of last pixel.
            memset( nIntensityCount, 0, sizeof(nIntensityCount) );
            memset( nSumR, 0, sizeof(nSumR) );
            memset( nSumG, 0, sizeof(nSumG) );
            memset( nSumB, 0, sizeof(nSumB) );

            // Find intensities of nearest nRadius pixels in four direction.
            for( int nY_O = -nRadius_i; nY_O <= nRadius_i; nY_O++ )
            {
                for( int nX_O = -nRadius_i; nX_O <= nRadius_i; nX_O++ )
                {
                    int nR = pbyDataIn_i[( nX+nX_O) * 3  + ( nY + nY_O ) * nBytesInARow ];
                    int nG = pbyDataIn_i[( nX+nX_O) * 3  + ( nY + nY_O ) * nBytesInARow + 1];
                    int nB = pbyDataIn_i[( nX+nX_O) * 3  + ( nY + nY_O ) * nBytesInARow + 2];

                    // Find intensity of RGB value and apply intensity level.
                    int nCurIntensity =  ( ( ( nR + nG + nB ) / 3.0 ) * fIntensityLevels_i ) / 255;
                    if( nCurIntensity > 255 )
                        nCurIntensity = 255;
                    int i = nCurIntensity;
                    nIntensityCount[i]++;

                    nSumR[i] = nSumR[i] + nR;
                    nSumG[i] = nSumG[i] + nG;
                    nSumB[i] = nSumB[i] + nB;
                }
            }

            int nOutR = 0;
            int nOutG = 0;
            int nOutB = 0;

            int nCurMax = 0;
            int nMaxIndex = 0;
            for( int nI = 0; nI < 256; nI++ )
            {
                if( nIntensityCount[nI] > nCurMax )
                {
                    nCurMax = nIntensityCount[nI];
                    nMaxIndex = nI;
                }
            }

            nOutR = nSumR[nMaxIndex] / nCurMax;
            nOutG = nSumG[nMaxIndex] / nCurMax;
            nOutB = nSumB[nMaxIndex] / nCurMax;

            pbyDataOut_o[( nX) * 3 + ( nY ) * nBytesInARow ] = nOutR;
            pbyDataOut_o[( nX) * 3 + ( nY ) * nBytesInARow + 1] = nOutG;
            pbyDataOut_o[( nX) * 3 + ( nY ) * nBytesInARow + 2] = nOutB;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions