利用 Avisynth 2.5.8 的 ColorKeyMask 功能实现视频抠像

下载安装Avisynth 2.5.8 + 下载安装 FFMpeg
编写 Avisynth 脚本 mating.avs
----------------------------------------------------------------------------------
video1 = AVISource ("背景.avi").ConvertToRGB32
video2 = AVISource ("前景.avi").ConvertToRGB32.colorkeymask($45D168,40).Blur(0,1)
Layer(video1,video2,"add",255,0,0)
----------------------------------------------------------------------------------
然后编写批处理 play.bat
----------------------------------------------------------------------------------
ffplay "mating.avs" -loop 0
----------------------------------------------------------------------------------
运行play.bat
----------------------------------------------------------------------------------
缺点:边界过度不够自然
优点:处理速度较快

下面是优化方案
1.下载 Avisynth 2.5.8 源代码(用VC + MASM32) Avisynth_258_src.zip
    http://sourceforge.net/projects/avisynth2/files/AviSynth%202.5/AviSynth%202.5.8/

    说明:需要VC6 + MASM32 汇编

	MASM32 汇编 下载地址
    http://www.masm32.com/masmdl.htm

2.要修改的函数 ColorKeyMask::GetFrame(int n, IScriptEnvironment *env)

    Avisynth_258_src.zip 解压到一个 .\avisynth_2.5.8\ 目录
	...\avisynth_2.5.8\src\filters\layer.cpp 文件中有这个函数
	原先的函数使用 IsClose 函数过滤 去掉设置相近的颜色
	要优化的部分在 ColorKeyMask::GetFrame 函数内

static __inline bool IsClose(int a, int b, unsigned threshold) 
{ 
	return (unsigned(a-b+threshold) <= threshold*2);
}

PVideoFrame __stdcall ColorKeyMask::GetFrame(int n, IScriptEnvironment *env)
{
	PVideoFrame frame = child->GetFrame(n, env);
	env->MakeWritable(&frame);
	
	BYTE* pf = frame->GetWritePtr();
	const int pitch = frame->GetPitch();
	const int rowsize = frame->GetRowSize();
	
	if (!(env->GetCPUFlags() & CPUF_MMX) || vi.width==1) 
	{
		const int R = (color >> 16) & 0xff;
		const int G = (color >> 8) & 0xff;
		const int B = color & 0xff;
		
		for (int y=0; y < vi.height; y++) 
		{
			for (int x=0; x < rowsize; x+=4) 
			{
				if (IsClose(pf[x],B,tolB) && IsClose(pf[x+1],G,tolG) && IsClose(pf[x+2],R,tolR))
					pf[x+3]=0;
				//在这里添加进行边缘模糊的算法 开始
				//思路
				//1.根据这点判断是否是边缘
				//2.如果是边缘,就把边缘的内侧alpha通道值逐渐变化处理 0->255
				// pf[x+(0-2)]是 RGB 值  pf[x+3] alpha值
				// 从 pf 到 pf + pitch 是 一帧图像中的一行
				// 这部分代码写出来之后可能不超过 100 行,就是算法需要好好研究
				
				//...
				
				//在这里添加进行边缘模糊的算法 结束
				
			}
			pf += pitch;
		}
	}
	else // MMX 这部分是为了加快处理速度 使用 MMX 指令集, 优化时暂不考虑这部分
	{
		const int height = vi.height;
		const int col8 = color;
		const int tol8 = 0xff000000 | (tolR << 16) | (tolG << 8) | tolB;
		const int xloopcount = -(rowsize & -8);
		pf -= xloopcount;
		__asm 
		{
			mov       esi, pf
			mov       edx, height
			pxor      mm0, mm0
			movd      mm1, col8
			movd      mm2, tol8
			punpckldq mm1, mm1
			punpckldq mm2, mm2
yloop:
			mov       ecx, xloopcount
xloop:		movq      mm3, [esi+ecx]
			movq      mm4, mm1
			movq      mm5, mm3
			psubusb   mm4, mm3
			psubusb   mm5, mm1
			por       mm4, mm5
			psubusb   mm4, mm2
			add       ecx, 8
			pcmpeqd   mm4, mm0
			pslld     mm4, 24
			pandn     mm4, mm3
			movq      [esi+ecx-8], mm4
			jnz       xloop
			
			mov       ecx, rowsize
			and       ecx, 7
			jz        not_odd

; process last pixel
			movd      mm3, [esi]
			movq      mm4, mm1
			movq      mm5, mm3
			psubusb   mm4, mm3
			psubusb   mm5, mm1
			por       mm4, mm5
			psubusb   mm4, mm2
			pcmpeqd   mm4, mm0
			pslld     mm4, 24
			pandn     mm4, mm3
			movd      [esi], mm4
not_odd:
			add       esi, pitch
			dec       edx
			jnz       yloop
			emms
		}
	}
	return frame;
}


posted @ 2013-12-31 19:37  1CM  阅读(1126)  评论(0编辑  收藏  举报