滤镜之油画Oil Painting

首先看效果图:


 

油画我的理解是色彩比较重,而且会有一片一片区域的同样色彩,没有什么细节,灰阶降低,只表现为一些特定的色彩。

算法上的原理如下:

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);
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值