PythonでImage Colorization APIを使ってモノクロ動画(gif)をカラー化する

自分でモノクロ映像をカラー化したい。最近そのような相談を、映像関係の方からよく頂くようになった。今のところすべてお断りしているが、APIを使えば簡単そうなのでやってみた。
こちらでカラー化してお渡しするならまだしも、プログラミング経験のない人を対象に、遠隔で指示しながら相手のPC上にDockerやらUbuntuやらTensorFlowやらの環境を構築するのは至難の業なので、今後できればこちらの方法を検討したほうが良いかもしれない。


#参考
今回、gifの分解、連結にはこちらのサイト様を参考にさせていただいた。
というかほとんどそのまま。。。
感謝です。
https://www.lifewithpython.com/2017/10/python-extract-gif-frames.html
https://chayarokurokuro.hatenablog.com/entry/2019/06/03/Python%E3%81%A7png%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89gif%E3%82%A2%E3%83%8B%E3%83%A1%E7%94%BB%E5%83%8F%E4%BD%9C%E6%88%90

#カラー化
![687474703a2f2f696d672e796f75747562652e636f6d2f76692f5661456c306661447733382f302e6a7067.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467051/acf0b9e8-2cd7-7624-e4e0-ebff625a18b5.jpeg)

[DeOldify](https://github.com/jantic/DeOldify?fbclid=IwAR0uZi0oVZQrGb-JJBfMmoyR9kWejCw5AliazfAsL-QEKEd30dzSY6qOU5s#what-is-nogan)というものを使った。こちらはDeepAIでAPIが無料公開されている。
チュートリアルにquickstart用のAPI-Keyが埋め込まれているが、こちらは数回利用すると使えなくなるため、アカウントを作成してAPI-Keyを取得しておくとよい。基本的に無料で使える。

[GitHub]
https://github.com/jantic/DeOldify?fbclid=IwAR0uZi0oVZQrGb-JJBfMmoyR9kWejCw5AliazfAsL-QEKEd30dzSY6qOU5s#what-is-nogan

[DeepAI]
https://deepai.org/machine-learning-model/colorizer?fbclid=IwAR2fFg4MWKa0XqpqUoZLOYFRH4AuKH1jmmS3KsDkjW_ObI6U_efz-q0aios

カラー化できる画像には以下のような制限がある。
HDとかの画質はちょっと無理なので注意。
それでもカラー化する系のやつなのかでは大きい方だと思う。

>the max file upload size is 1200px for any dimension. That being said, If you upload an image with a dimension larger than 1200px, we shrink the image so no dimension is large than that.

#ソースコード
ソースコードはこちら。
API-Keyは適宜取得して書き換えてほしい。
今回はgifで行ったが、OpenCVを使えばmp4とかでもいけるかもしれない。
ただし、無料で公開してくれているものなので、数千枚分のリクエストを一気に投げるとかしないように。。
マナーは守って利用したほうがいいと思う。
(なんか、1分間に何枚まで、みたいな利用規約が見つけられなかった。)

```python
# coding: utf-8
from pathlib import Path
from PIL import Image, ImageSequence
import cv2
import glob
import requests

# モノクロgifへのパス
IMAGE_MONO_PATH = 'mono.gif'
# 生成されるカラーgifへのパス
IMAGE_COLOR_PATH = 'color.gif'
# 分割したモノクロ画像生成フォルダ
DESTINATION_MONO = 'splitted_mono'
# 分割したカラー画像生成フォルダ
DESTINATION_COLOR = 'splitted_color'

gif = cv2.VideoCapture(IMAGE_MONO_PATH)
fps = gif.get(cv2.CAP_PROP_FPS)
DURATION = round(1000/fps)

def main():
    frames = get_frames(IMAGE_MONO_PATH)
    write_frames(frames, IMAGE_MONO_PATH, DESTINATION_MONO)
    get_color(DESTINATION_MONO, DESTINATION_COLOR)
    join_images(DESTINATION_COLOR, IMAGE_COLOR_PATH, DURATION)

def get_frames(path):
    im = Image.open(path)
    return (frame.copy() for frame in ImageSequence.Iterator(im))


def write_frames(frames, name_original, destination):
    path = Path(name_original)

    stem = path.stem
    # extension = path.suffix
    extension = '.png'

    dir_dest = Path(destination)
    if not dir_dest.is_dir():
        dir_dest.mkdir(0o700)
        print('Destionation directory is created: "{}".'.format(destination))

    for i, f in enumerate(frames):
        name = '{}/{}-{}{}'.format(destination, stem, i + 1, extension)
        f.save(name)
        print('A frame is saved as "{}".'.format(name))

def get_color(mono_destination, color_destination):
    dir_dest = Path(color_destination)
    if not dir_dest.is_dir():
        dir_dest.mkdir(0o700)
        print('Destionation directory is created: "{}".'.format(color_destination))

    files = sorted(glob.glob(mono_destination + '/*.png'))

    for i, file in enumerate(files):
        r = requests.post(
            "https://api.deepai.org/api/colorizer",
            files={
                'image': open(file, 'rb'),
            },
            headers={'api-key': 'quickstart-QUdJIGlzIGNvbWluZy4uLi4K'}
        )
        url = r.json()['output_url']
        file_name = color_destination + '/' + str(i) + ".png"

        response = requests.get(url)
        image = response.content

        with open(file_name, "wb") as f:
            f.write(image)

def join_images(color_destination, color_filename, duration):
    files = sorted(glob.glob(color_destination + '/*.png'))
    images = list(map(lambda file : Image.open(file) , files))
    images[0].save(color_filename , save_all = True , append_images = images[1:] , duration = duration , loop = 0)


if __name__ == '__main__':
    main()

```

#最後に
動かすとこんな感じです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">モノクロ動画に色つけるやつ意外とうまいこといった。<br>てんさーふろーとかいう難しいやつはAPIに任せますた。<a href="https://twitter.com/hashtag/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#エンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://t.co/311K4wd7Bc">pic.twitter.com/311K4wd7Bc</a></p>&mdash; たくみ@スカジャンのエンジニア (@hatt_takumi) <a href="https://twitter.com/hatt_takumi/status/1274365882743967745?ref_src=twsrc%5Etfw">June 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

実際に変換したgifをお見せしたかったが、そのままアップロードしても大丈夫そうなモノクロ素材が見つけられなかった。
画像だけど、DeOldifyにあったサンプルはこんな感じ。
![68747470733a2f2f692e696d6775722e636f6d2f565975617634492e6a7067.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467051/557d1f68-0b96-8c93-e3bb-94b6cdf6fb3b.jpeg)