卡通画(矢量风格画)特效生成算法

       当初做这个算法时,参考的是相机360中的卡通特效。实际查找资料时,我看很多资料也把这种效果称为矢量风格画,严格意义讲,我也说不上来到底该叫什么。找了些资料,也没有找到准确的定义。况且我做的效果,和矢量风格画以及卡通画还有些差距,说白了,并不是那么像。不过,虽然不像,但从效果上,我觉得各有千秋吧,实际对比发现,有些图片处理后,效果要优于相机360中的效果。
       计算过程主要在y通道进行。如果在rgb空间分三个通道处理,计算过程将会非常耗时,所以需要由rgb空间转换至yuv空间,单独对y通道进行处理,最后在变换回rgb空间进行显示、输出。下面把算法大体描述一下。rgb转yuv,得到y通道,单独对y通道做边缘检测,然后计算结构张量,得到整幅图像的矢量场,即计算每个像素点的水平分量及垂直分量。有了矢量场,就可以调用线积分卷积算法进行滤波,得到具有手绘风格的笔触效果。在由yuv空间转回rgb空间过程中,还可以根据不同需求,生成不同风格的结果图,比如黑白图,彩色图等。
       下面贴出算法整体调用逻辑代码,基本可以了解本文提出的卡通画特效算法思路。
void* ImageVectorStylizationThread(void *arg)
{
	VectorStylizationInfo *vecstylization_info = (VectorStylizationInfo *)arg;
	BMPINFO *pSrcBitmap = vecstylization_info->pSrcBitmap;
	int style_index = vecstylization_info->style_index;
	int color_index = vecstylization_info->color_index;
	int thread_id = vecstylization_info->thread_id;

	int width = pSrcBitmap->lWidth;
	int height=  pSrcBitmap->lHeight;
	int size = width*height;
	int mem_size = size * sizeof(float);
	float *rdata = (float *)malloc(mem_size);
	float *gdata = (float *)malloc(mem_size);
	float *bdata = (float *)malloc(mem_size);
	float *ydata = (float *)malloc(mem_size);
	float *udata = (float *)malloc(mem_size);
	float *vdata = (float *)malloc(mem_size);

	// 数据转换
	ConvertToFloat(pSrcBitmap, rdata, gdata, bdata);

	// rgb转yuv
	for (int i = 0; i < size; i++)
	{
		Rgb2Yuv(rdata[i], gdata[i], bdata[i], &ydata[i], &udata[i], &vdata[i]);
	}

	// 抽取边缘
	float *edgedata = (float *)malloc(mem_size);
	ExtractEdge(ydata, edgedata, width, height, 15.7f, 0.017f, 105.5f);

	// 计算矢量场
	float *vec_x = (float *)malloc(size * sizeof(float));
	float *vec_y = (float *)malloc(size * sizeof(float));
	CalcVectorField(ydata, width, height, vec_x, vec_y, 1.5f);
	
	// 线积分卷积
	LICFilter(edgedata, ydata, vec_x, vec_y, width, height);

	free(vec_x);
	free(vec_y);
	vec_x = NULL;
	vec_y = NULL;
	free(edgedata);
	edgedata = NULL;

	// 输出结果
	switch (style_index)
	{
	case 0:
		// 黑白
		memcpy(rdata, ydata, mem_size);
		memcpy(gdata, ydata, mem_size);
		memcpy(bdata, ydata, mem_size);
		ConvertToUchar(rdata, gdata, bdata, pSrcBitmap);
		ImageBlend(pSrcBitmap, 0, 0);
		break;
	case 1:
		// 单彩
		memcpy(rdata, ydata, mem_size);
		memcpy(gdata, ydata, mem_size);
		memcpy(bdata, ydata, mem_size);
		ConvertToUchar(rdata, gdata, bdata, pSrcBitmap);
		ImageBlend(pSrcBitmap, 0, 0);
		ImageBlend(pSrcBitmap, 1, color_index);
		break;
	case 2:
		// 多彩
		for (int i = 0; i < size; i++)
		{
			Yuv2Rgb(ydata[i], udata[i], vdata[i], &rdata[i], &gdata[i], &bdata[i]);
		}
		ConvertToUchar(rdata, gdata, bdata, pSrcBitmap);
		ImageAdjust(pSrcBitmap);
		break;
	default:
		break;
	}
	
	free(ydata);
	free(udata);
	free(vdata);
	ydata = NULL;
	udata = NULL;
	vdata = NULL;

	free(rdata);
	free(gdata);
	free(bdata);
	rdata = NULL;
	gdata = NULL;
	bdata = NULL;

	return NULL;
}
       同样,本算法也是有局限性的,对于背景与前景简单一些的图效果比较好,如果图像背景或者前景比较杂乱,生成的结果可能不太理想。下面是一些效果图:
             
                                                                  
                
                
                
                
                
                
                
                
                
       欢迎下载示例demo:http://download.csdn.net/detail/u013085897/9747177,另外本算法已经集成进我的安卓应用《铅笔画》, 大家有兴趣可以到360、安卓、安智等商店下载使用。


评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值