やーめったと。
2017-12-15 追記: 以下参照:
ダウンロードという行為そのものが youtube の利用規約に反することを知りませんでした。(なお、ダウンロードするだけで著作権法違反となる、という話ではない。)以下一応読めるようにはしておくけれど、出来れば読まないで。
成功はしなかったけど、「諦め」前に失敗作を記録しておこうと思って。
(4)で「これは意図と違うであろ?」を、考えられることは一応やってみた:
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, ImageOps, ImageColor
10
11 def _conv_green(keyclr, src, threshold=16, sensitivity=1.5, replacewith="#333"):
12 if keyclr[1] > keyclr[2]: # green back
13 c1i, c2i, c3i = 1, 0, 2
14 else: # blue back
15 c1i, c2i, c3i = 2, 1, 2
16 rw = ImageColor.getrgb(replacewith)
17 rwsum = float(sum(rw))
18 rw1r = 3 * rw[c1i] / rwsum
19 rw2r = 3 * rw[c2i] / rwsum
20 rw3r = 3 * rw[c3i] / rwsum
21
22 arr = np.array(src)
23 c1 = arr[:, :, c1i]
24 c2 = arr[:, :, c2i]
25 c3 = arr[:, :, c3i]
26 cond = np.logical_and(c1 > threshold, np.logical_or(c1 > c2 * sensitivity, c1 > c3 * sensitivity))
27 arr[:, :, c1i] = c1 * rw1r + (~cond) * c1
28 arr[:, :, c2i] = cond * c1 * rw2r + (~cond) * c2
29 arr[:, :, c3i] = cond * c1 * rw3r + (~cond) * c3
30 return Image.fromarray(arr)
31
32 if __name__ == '__main__':
33 logging.basicConfig(stream=sys.stderr, level=logging.INFO)
34 parser = argparse.ArgumentParser()
35 parser.add_argument("background")
36 parser.add_argument("greenback")
37 parser.add_argument("outfile")
38 parser.add_argument("--pick", type=str, default="[0, 0]")
39 parser.add_argument("--atol", type=int, default=30)
40 parser.add_argument("--bg-start", help="in secs", type=float, default=0)
41 parser.add_argument("--gb-start", help="in secs", type=float, default=0)
42 parser.add_argument("--gb-end", help="in secs", type=float, default=0)
43 parser.add_argument("--audio-from-gb", action="store_true")
44 parser.add_argument("--gb-base-alpha", type=int, default=0)
45 args = parser.parse_args()
46 pick = tuple(json.loads(args.pick))
47 #
48
49 icontbg = av.open(args.background)
50 icontgb = av.open(args.greenback)
51 ivstrbg = next(s for s in icontbg.streams if s.type == b'video')
52 ivstrgb = next(s for s in icontgb.streams if s.type == b'video')
53 iastrbg = next(s for s in icontbg.streams if s.type == b'audio')
54 iastrgb = next(s for s in icontbg.streams if s.type == b'audio')
55 ocont = av.open(args.outfile, "w")
56 ovstr = ocont.add_stream(codec_name="h264", rate=ivstrbg.rate)
57 oastr = ocont.add_stream(codec_name="aac", rate=iastrbg.rate)
58 ovstr.width = ivstrbg.width
59 ovstr.height = ivstrbg.height
60 #
61 if args.bg_start:
62 bg_start_pts_v = int(args.bg_start / float(ivstrbg.time_base) + ivstrbg.start_time)
63 bg_start_pts_a = int(args.bg_start / float(iastrbg.time_base) + iastrbg.start_time)
64 ivstrbg.seek(bg_start_pts_v)
65 iastrbg.seek(bg_start_pts_a)
66 if args.gb_start:
67 gb_start_pts_v = int(args.gb_start / float(ivstrgb.time_base) + ivstrgb.start_time)
68 gb_start_pts_a = int(args.gb_start / float(iastrgb.time_base) + iastrgb.start_time)
69 ivstrgb.seek(gb_start_pts_v)
70 iastrgb.seek(gb_start_pts_a)
71 if args.gb_end:
72 gb_end_pts_v = int(args.gb_end / float(ivstrgb.time_base) + ivstrgb.start_time)
73 else:
74 gb_end_pts_v = 0
75 #
76
77 if not args.audio_from_gb:
78 avbothpackets = icontbg.demux()
79 vidonlypackets = icontgb.demux(ivstrgb)
80 else:
81 avbothpackets = icontgb.demux()
82 vidonlypackets = icontbg.demux(ivstrbg)
83 done = False
84 while not done:
85 try:
86 avbothpacket = next(avbothpackets)
87 if avbothpacket.stream.type == 'video':
88 if not args.audio_from_gb:
89 iframebgs = avbothpacket.decode()
90 iframegbs = next(vidonlypackets).decode()
91 else:
92 iframebgs = next(vidonlypackets).decode()
93 iframegbs = avbothpacket.decode()
94 for iframes in zip(iframebgs, iframegbs):
95 logging.info(iframes)
96 imgbg = iframes[0].to_image()
97 imggb = iframes[1].to_image().resize(imgbg.size)
98 keyclr = imggb.getpixel(pick)
99 r = np.array(imggb.getdata(0))
100 g = np.array(imggb.getdata(1))
101 b = np.array(imggb.getdata(2))
102 a = np.ones(r.shape) * args.gb_base_alpha
103 #
104 a[np.logical_and(
105 np.isclose(r, keyclr[0], atol=args.atol),
106 np.isclose(g, keyclr[1], atol=args.atol),
107 np.isclose(b, keyclr[2], atol=args.atol))] = 255
108 alpha = Image.new("L", imggb.size)
109 alpha.putdata(a.flatten())
110 mask = imggb.copy()
111 mask.putalpha(alpha)
112
113 dimg = Image.composite(imgbg, _conv_green(keyclr, imggb), mask)
114 #dimg = Image.composite(
115 # imgbg,
116 # ImageOps.colorize(
117 # imggb.convert("L"),
118 # black="black", white="orange"),
119 # mask)
120
121 ofr = av.VideoFrame.from_image(dimg)
122 for p in ovstr.encode(ofr):
123 ocont.mux(p)
124 if gb_end_pts_v and iframes[1].pts >= gb_end_pts_v:
125 done = True
126 else:
127 for iframe in avbothpacket.decode():
128 logging.info(iframe)
129 iframe.pts = None
130 for p in oastr.encode(iframe):
131 ocont.mux(p)
132 except StopIteration:
133 break
134
135 ocont.close()
惜しいんだよな:
実際「それっぽければいい」んであれば、コメントアウトした「グレイスケールに変換してから colorize はまぁ悪くはなくて、活きてる方はパラメータによってはこの colorize と全然大差ないものが出来上がっちゃう。「緑を緑じゃなくしたい」だけなわきゃぁなくて、「赤は赤だろうよ」としたいから複雑なことを「やりかけた」わけだけど、ご覧の通り、緑の亡霊が…。
疲れたのでこれでやめる。(4)で宣言した通りで、こんなんワタシの本題じゃぁないんであって。