首先看效果图:
油画我的理解是色彩比较重,而且会有一片一片区域的同样色彩,没有什么细节,灰阶降低,只表现为一些特定的色彩。
算法上的原理如下:
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); }