そりゃぁ「アレ」をするだけさ、てことで。
一つ前のまんまでやめちゃうと、やや消化不良よね、と。
tolerance を見りゃいいだけの話で:
1 #
2 import sys
3 import argparse
4 import logging
5 import json
6
7 import numpy as np
8 import av
9 from PIL import Image
10
11 if __name__ == '__main__':
12 logging.basicConfig(stream=sys.stderr, level=logging.INFO)
13 parser = argparse.ArgumentParser()
14 parser.add_argument("background")
15 parser.add_argument("greenback")
16 parser.add_argument("outfile")
17 parser.add_argument("--pick", type=str, default="[0, 0]")
18 parser.add_argument("--atol", type=int, default=30)
19 args = parser.parse_args()
20 pick = tuple(json.loads(args.pick))
21
22 icontbg = av.open(args.background)
23 icontgb = av.open(args.greenback)
24 ivstrbg = next(s for s in icontbg.streams if s.type == b'video')
25 ivstrgb = next(s for s in icontgb.streams if s.type == b'video')
26 ocont = av.open(args.outfile, "w")
27 ovstr = ocont.add_stream(codec_name="h264", rate=ivstrbg.rate)
28 ovstr.width = ivstrbg.width
29 ovstr.height = ivstrbg.height
30 for packets in zip(icontbg.demux(ivstrbg), icontgb.demux(ivstrgb)):
31 for iframes in zip(packets[0].decode(), packets[1].decode()):
32 logging.info(iframes)
33 imgbg = iframes[0].to_image()
34 imggb = iframes[1].to_image().resize(imgbg.size)
35 keyclr = imggb.getpixel(pick)
36
37 r = np.array(imggb.getdata(0))
38 g = np.array(imggb.getdata(1))
39 b = np.array(imggb.getdata(2))
40 a = np.zeros(r.shape)
41 a[np.logical_and(
42 np.isclose(r, keyclr[0], atol=args.atol),
43 np.isclose(g, keyclr[1], atol=args.atol),
44 np.isclose(b, keyclr[2], atol=args.atol))] = 255
45 alpha = Image.new("L", imggb.size)
46 alpha.putdata(a.flatten())
47 mask = imggb.copy()
48 mask.putalpha(alpha)
49
50 dimg = Image.composite(imgbg, imggb, mask)
51
52 ofr = av.VideoFrame.from_image(dimg)
53 for p in ovstr.encode(ofr):
54 ocont.mux(p)
55 ocont.close()
isclose 使っただけね、本質的には。あとは抜く色のピックアップをする位置指定をオプション指定出来るようにもしてるけど。
てわけで(atol=50):
まぁこんなもんでしょ。