利用 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;

}





你可能感兴趣的:(color)