せっかくのグリーンスクリーンなので、らしい遊びをしてみた (3)

まだ消化不良でしょ?

だって音声無視してるしね。

同じものだとつまらんので今度は以下2つの合成:


ロンドンに不思議な球体がぁ、てなもんになるかな?

スクリプトの構造は大幅に変わる:

 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     iastrbg = next(s for s in icontbg.streams if s.type == b'audio')
27     ocont = av.open(args.outfile, "w")
28     ovstr = ocont.add_stream(codec_name="h264", rate=ivstrbg.rate)
29     oastr = ocont.add_stream(codec_name="aac", rate=iastrbg.rate)
30     ovstr.width = ivstrbg.width
31     ovstr.height = ivstrbg.height
32 
33     packetsbg = icontbg.demux()
34     packetsgb = icontgb.demux(ivstrgb)
35     while True:
36         try:
37             packetbg = next(packetsbg)
38             if packetbg.stream.type == 'video':
39                 iframebgs = packetbg.decode()
40                 iframegbs = next(packetsgb).decode()
41                 for iframes in zip(iframebgs, iframegbs):
42                     logging.info(iframes)
43                     imgbg = iframes[0].to_image()
44                     imggb = iframes[1].to_image().resize(imgbg.size)
45                     keyclr = imggb.getpixel(pick)
46         
47                     r = np.array(imggb.getdata(0))
48                     g = np.array(imggb.getdata(1))
49                     b = np.array(imggb.getdata(2))
50                     a = np.zeros(r.shape)
51                     a[np.logical_and(
52                             np.isclose(r, keyclr[0], atol=args.atol),
53                             np.isclose(g, keyclr[1], atol=args.atol),
54                             np.isclose(b, keyclr[2], atol=args.atol))] = 255
55                     alpha = Image.new("L", imggb.size)
56                     alpha.putdata(a.flatten())
57                     mask = imggb.copy()
58                     mask.putalpha(alpha)
59         
60                     dimg = Image.composite(imgbg, imggb, mask)
61         
62                     ofr = av.VideoFrame.from_image(dimg)
63                     for p in ovstr.encode(ofr):
64                         ocont.mux(p)
65             else:
66                 for iframe in packetbg.decode():
67                     logging.info(iframe)
68                     iframe.pts = None
69                     for p in oastr.encode(iframe):
70                         ocont.mux(p)
71         except StopIteration:
72             break
73 
74     ocont.close()

音声と映像のレートは当然違うので (1)(2) でシンプルに zip してたようにはいかない、というわけだけれど、本当は映像のフレームレートが違ってたらダメなんだけどね、そこは同じだとして。(フレームレート違いを扱うのは多分かなり難儀。)

結果:

なんつーかあんましオモロイ例にならなくてすまん。Creative Commons なものだけでやろうとすれば限られてくるもんでなぁ。ほんとは「渋谷に不思議な球体がぁ」なんてのだったらオモロいと思ったんだけどね。