下载安装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;
}