TwitterのGIFアイコン作ってみるよ!

TwitterでGIFアイコン使えるのは知っていたのだが、なかなか機会が無かったので思い立ったが吉日的にやってみた。

まず、動画をフレーム単位で読み込んだ。これはWindowsでAlt+PrintScreenでちまちましました。
ストパン一期EDより。


この二枚で2フレーム間です。
通常アニメは24fps/secですが、二枚連続同じ画像が続くので実質12/sec
今回抜き出した枚数は25枚

適当にサーニャが写ってるところだけ抜き出す。エイラなんていなかった。
ついでに背景も消した。

import Image

location = "/home/username/sanyaGIF"

n = 25
for i in range(n):
    box3 = (280+i*7, 100, 280+250+i*7, 100+250)
    im = Image.open("%s/input/%02d.png" %(location,i+1))
    im2 = im.crop(box3)
    width, height = im2.size
    
    for j in range(width):
        for k in range(height):
            point = (j, k)
            rgb = im2.getpixel(point)
            if rgb[0] + rgb[1] < rgb[2]*1.55:
                rgb = (255, 255, 255)
                im2.putpixel(point, rgb)
    im2.save("%s/output/%02d.png" %(location, i+1))

出力されたものをフリーのGIF作成ソフトに突っ込む


実はこれ、最初はこんな感じだった。

背景に影響されて輪郭が変色したため、残すのは不自然だった。

そこで上のように背景判断をキツ目にしたが、今度は輪郭が消えてこっちも不自然になってしまった。

そこで輪郭を作ろうと、一回り大きなサーニャのシルエットを作って、そこに元の画像を重ねるアプローチで行った。

import Image

location = "/home/username/sanyaGIF"

def resize(im, num):
    wideth ,height = im.size
    for i in range(wideth):
        for j in range(height):
            point = (i, j)
            rgb = im.getpixel(point)
            if rgb[0]!=255 or rgb[1]!=255 or rgb[2]!=255:
                rgb = (0, 0, 0)
                im.putpixel(point, rgb)
    scale = 1.1
    size = (int(wideth*scale), int(height*scale))
    im2 = im.resize(size)
    im2.save("%s/output2/%02d.png" %(location, num+1))
    
def paste(num):
    im  = Image.open("%s/output/%02d.png"  % (location, num+1))
    im2 = Image.open("%s/output2/%02d.png" % (location, num+1))
    
    wideth, height = im.size
    wideth2, height2 = im2.size
    box = (int((wideth2-wideth)/2), int((height2 - height)/2), int((wideth2-wideth)/2)+wideth, int((height2 - height)/2)+height)
    
    for i in range(wideth):
        for j in range(height):
            point = (int((wideth2-wideth)/2)+i, int((height2-height)/2)+j)
            #point = (i+50, j+50)
            if (255, 255, 255) != im.getpixel((i, j)):
                im2.putpixel(point, im.getpixel((i, j)))
    im3 = im2.crop(box)
    im3.save("%s/output3/%02d.png" % (location, num +1))
    #im2.save("%s/output3/%02d.png" % (location, num +1))
   
n = 25
for i in range(n):
    im = Image.open("%s/output/%02d.png" % (location, i+1))
    resize(im, i)
    
for i in range(n):
    paste(i)
    print i
    
print "end"

出来た結果がこちら

そもそものアプローチを間違えたことに気づく。これはこれでいいが、望んでいたものとは違う

今度はエッジ抽出して輪郭を見つけ出そうとするはじめからそうしろよ的アプローチで行った

import Image

location = "/home/username/sanyaGIF"

def edge(num):
    im = Image.open("%s/output/%02d.png" %(location, num+1))
    im2 = Image.new('RGB', im.size, (255, 255, 255))
    w, h = im.size
    
    for i in range(w):
        for j in range(h):
            if 1 < i < w-2:
                rgb = im.getpixel((i, j))
                if rgb[0]==255 and rgb[1]==255 and rgb[2]==255:
                    if im.getpixel((i-1, j)) != im.getpixel((i, j))or im.getpixel((i, j))!= im.getpixel((i+1, j)):
                        im2.putpixel((i, j), (0, 0, 0))
    for i in range(w):
        for j in range(h):
            if 1 < j < h-2:
                rgb = im.getpixel((i, j))
                if rgb[0]==255 and rgb[1]==255 and rgb[2]==255:
                    if im.getpixel((i, j-1)) != im.getpixel((i, j))or im.getpixel((i, j)) != im.getpixel((i, j+1)):
                        im2.putpixel((i, j), (0, 0, 0))
         
    im2.save("%s/output4/%02d.png" % (location, num+1))
 
def blur(num):
    im = Image.open("%s/output/%02d.png" %(location, num+1))
    im2 = Image.open("%s/output4/%02d.png" %(location, num+1))  
    w, h = im.size
    
    for i in range(w):
        for j in range(h):
            point = (i, j)
            if im2.getpixel(point) == (0, 0, 0):
                im.putpixel(point,im2.getpixel(point))
                
    for i in range(1, w-1):
        for j in range(1, h-1):
            point = (i, j)
            if im2.getpixel(point) == (0, 0, 0):
                rgb_sum = [0, 0, 0]
                for l in range(-1, 2):
                    for m in range(-1, 2):
                        point2= (i+l, j+m)
                        rgb_sum[0] += im.getpixel(point2)[0]
                        rgb_sum[1] += im.getpixel(point2)[1]
                        rgb_sum[2] += im.getpixel(point2)[2]
                im.putpixel(point, (rgb_sum[0]/9, rgb_sum[1]/9, rgb_sum[2]/9))
    
    im3 = im.resize((250, 250))
                
    im3.save("%s/output5/%02d.png" % (location, num+1))

def mask(num):
    im = Image.open("%s/output5/%02d.png" % (location, num+1))
    w, h = im.size
    
    for i in range(w):
        for j in range(h):
            if im.getpixel((i, j)) == (255, 255, 255):
                im.putpixel((i, j), (64, 174, 255))
                
    im.save("%s/output5/%02d.png" % (location, num+1))
              
n=25

for i in range(n):
    edge(i)
    print i

for i in range(n):
    blur(i)
    print i
for i in range(n):
    mask(i)
    print i
print "Finish"

抽出されたエッジがこちら

あとは繋ぎ目が自然になるように適当に出力されたファイルを並べ替えたりコマ数を落としたりした。これで完成!