首先看效果图:
油画我的理解是色彩比较重,而且会有一片一片区域的同样色彩,没有什么细节,灰阶降低,只表现为一些特定的色彩。
算法上的原理如下:
1. 统计每个像素领域半径中出现的R,G,B的直方图,以及灰度的直方图,该直方图的bin的大小是设定好的,由此可以统计出落在某个bin上的数量
2. 统计直方图中出现次数最多的R、G、B的均值,就是最要这个像素的结果。
从某个人的博客中借用了一个比较形式化的图,便于更好理解:
http://www.cnblogs.com/hoodlum1980/archive/2011/01/15/1936078.html
该算法存在两个参数:
1. 半径:统计像素的矩形框,越大则图像细节越少
2. 平滑度:直方图bin的宽度,越大越平滑
算法代码:没有经过任何优化
void OilPaintingRGB(unsigned char* pInput,unsigned char* pOutput,int width,int height,int nStride,int radius,int smooth)
{
int intensity, maxIntensity;
unsigned char* src = pInput;
unsigned char* dst = pOutput;
unsigned char* p;
int i,j,x,y,t;
int offset = nStride-width*3;
double scale = smooth/255.0;
int _smooth = smooth + 1;
int* red = (int*)malloc(sizeof(int)*_smooth);
int* green = (int*)malloc(sizeof(int)*_smooth);
int* blue = (int*)malloc(sizeof(int)*_smooth);
int* intensities = (int*)malloc(sizeof(int)*_smooth);
if(pInput == NULL || pOutput == NULL)
return;
if(width <= 0 || height <= 0)
return;
if(radius<1)
radius = 1;
// for each line
for ( y = 0; y < height; y++ )
{
// for each pixel
for ( x = 0; x < width; x++, src += 3, dst += 3 )
{
memset(red,0,sizeof(int)*_smooth);
memset(green,0,sizeof(int)*_smooth);
memset(blue,0,sizeof(int)*_smooth);
memset(intensities,0,sizeof(int)*_smooth);
// for each kernel row
for ( i = -radius; i <= radius; i++ )
{
t = y + i;
// skip row
if ( t < 0 )
continue;
// break
if ( t >= height )
break;
// for each kernel column
for ( j = -radius; j <= radius; j++ )
{
t = x + j;
// skip column
if ( t < 0 )
continue;
if ( t < width )
{
p = &src[i * nStride + j * 3];
intensity = (int)( 0.2125 * (*p) + 0.7154 * (*(p+1))) + 0.0721 * (*(p+2));
intensity = intensity * scale;
intensities[intensity] ++;
// red
red[intensity] += *p;
// green
green[intensity] += *(p+1);
// blue
blue[intensity] += *(p+2);
}
}
}
// get most frequent intesity
maxIntensity = 0;
j = 0;
for ( i = 0; i < _smooth; i++ )
{
if ( intensities[i] > j )
{
maxIntensity = i;
j = intensities[i];
}
}
// set destination pixel
*dst = (unsigned char)( red[maxIntensity] / intensities[maxIntensity] );
*(dst+1) = (unsigned char)( green[maxIntensity] / intensities[maxIntensity] );
*(dst+2) = (unsigned char)( blue[maxIntensity] / intensities[maxIntensity] );
}
src += offset;
dst += offset;
}
free(red);
free(green);
free(blue);
free(intensities);
}