ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【映画鑑賞】プロメアの感想(ネタバレあり)

www.youtube.com

 キルラキルで有名なTRIGGERの劇場アニメ最新作である「プロメア」を初日に鑑賞してきました。

 ものすごく面白く、映像的にもすごかったので感想や見所などを書いていきます。

 基本的に「ネタバレを気にしない」方向でいくので注意してください。

 また記事中に出てくる画像は全て参考資料の動画からキャプチャしたものです。

 では始めます。


1:全体的な感想
 とにかく熱い!
 アクションシーンがすごい!
 なんかむちゃくちゃだけど理屈抜きに面白い!

 いつものTRIGGER作品の純度をさらに高めてアクションシーンばかり詰め込んでぶちまけました、みたいな作品でした。
 ただひたすらに気持ちがいいアニメーションとビビッドでかっこいい色合いの画面の連続で見ている方が熱量にやられてしまうほどでした。

 TRIGGER作品好きならもちろんのこと、気持ちの良いアニメーションが見たいという人には絶対おすすめの作品です。

 作品自体の個人的な感想をTRIGGER作品に対して語るのは野暮だと思うので「めちゃくちゃいいぞ!」というぐらいで留めておきます。


2:プロメアの演出について
 ※ここからはネタバレありで進めます。

 頭を空っぽにした状態で最高に楽しめる作品であることは間違いないのですが、ちょっと引いた目線で見ると、実はかなりテーマにより沿った細かい演出もなされている作品でもあると感じました。

 それは△、□、そして後半に出てくる◯という3つの単純かつ基本的な図形による演出です。

 映画の一番最初でバーニッシュが生まれた経緯が語られますが、そこで印象的に△のマークが出てきます。
 これはバーニッシュのシンボルが「△」であることを示しています。
 同様にバーニングレスキュー、フリーズフォースなどのいわゆる火消し側、体制側のシンボルは「□」、物語の後半に出てくるそれ以外であるデウス・プロメスは「◯」がシンボルになっています。

 簡単にまとめると以下のようになります。

シンボル図形 勢力
バーニッシュ側(マッドバーニッシュ)
火消し側、体制側(バーニングレスキュー、フリーズフォース)
それ以外(デウス・プロメス)

 バーニッシュ側のシンボルが△なのは冒頭のところでわかりやすいと思います。

 体制側のシンボルが□というのはわかりやすくは語られてはいませんが、クレイの拠点であるプロメポリスの塔は四角形のみで構成されていますし、クレイがガロに箱舟計画を教える時に乗っているエレベータは四角形のキューブのような形をしています。
 このようにデザインを通じて各勢力の表現をきちんと変えています。
 それはエフェクトにも適用されています。

 マッドバーニッシュとバーニングレスキューの戦闘シーンでは、以下のようにバーニングレスキューが扱う武器(氷)の形はちゃんと四角形になっています。
f:id:rikoubou:20190524212204p:plain
 対してマッドバーニッシュ側の炎のエフェクトはいわゆる「ローポリ風」の3DCGが使われており、飛び散る炎が三角形になっています。
f:id:rikoubou:20190524213209p:plain

 そして物語の後半で出てくる新しい勢力であるデウス・プロメス側の「◯」というシンボル。
 湖の底に落ちてからは◯がいくつも出てきますし、アイナが水玉コラみたいになっているようなカットまであるのでわかりやすいと思います。
 デウス・プロメスが開発したバーニッシュ側のリオと体制側のガロ(△と□)が乗り込むデウス・X・マキナも今まで出てきたメカとは全く違い、見た目が丸っこくデザインされています。
 △と□が調和した形としての「◯」としても描かれていると思います。

 このように各勢力のシンボルがそのままエフェクトやデザインとして取り込まれて表現されています。

 今回3DCGのエフェクトについては「あえてローポリ風を意識している」とパンフレットでも語られています。
 3DCGは三角形や四角形を最小単位とした「ポリゴン」の集合体であるので、この「ポリゴンを全面に押し出した画面づくり」をすることにより△のバーニッシュ側と□の体制側をより深く表現することができていると個人的には思っています。

 このローポリである△と□の組み合わせで表現される3DCG=「デウス・X・マキナ(◯)」であり、調和の象徴であるとも読み取れます。
 パンフレットのネタバレ注意の部分でコヤマシゲトさんのコメントにもそのようにデザインしたとコメントがあります。

 このように各シンボルと物語のテーマをデザインやエフェクト面でもしっかりと演出されている、とても丁寧な作品であるとも言えると思います。


 以上、演出面を中心に色々書いてきましたが、まだ1回しか観てないので色々見落としているところなどもあるかと思います。

 個人的にかなり面白く、映像面も本当にすごかったのでもう一回どこかで見直したいです。


・参考資料

【MacOS/Raspberry Pi】SCPコマンドを使ったファイルのアップロードとダウンロード

rikoubou.hatenablog.com
 以前の記事でSSHを使ってリモートログインする方法を説明しました。

 SSHでログインしていると「ファイルのやりとりもしたい」となってくるので、今回はSCPコマンドを使ったファイルのアップロードとダウンロードの方法についてです。

 では始めます。


1:SCPコマンドでのファイルのアップロード
 ファイルのアップロードはMacOS側でターミナルを立ち上げ、以下のコマンドを実行すればできます。

$ scp [対象ファイルパス] [ユーザ名]@[IPアドレス]:[アップロード先ディレクトリパス]

 例えばMacOS側で「/Users/hoge.txt」ファイルをRaspberry Piのpiユーザ(IPアドレスが192.168.0.0)の「/home/pi/」配下にアップロードする場合は以下のコマンドになります。

$ scp /Users/hoge.txt pi@192.168.0.0:/home/pi/

 このコマンドを実行するとログインしようとしたユーザのパスワードを尋ねられるので、piユーザならデフォルトの「raspberry」と入力すればOKです。


2:SCPコマンドでのファイルのダウンロード
 ファイルのダウンロードはMacOS側でターミナルを立ち上げ、以下のコマンドを実行すればできます。

$ scp [ユーザ名]@[IPアドレス]:[対象ファイルパス] [ダウンロード先ディレクトリパス]

 例えばRaspberry Piのpiユーザ(IPアドレスが192.168.0.0)の「/home/pi/hoge.txt」ファイルをMacOS側の「/Users/」配下にダウンロードする場合は以下のコマンドになります。

$ scp pi@192.168.0.0:/home/pi/hoge.txt /Users/

 このコマンドも実行するとログインしようとしたユーザのパスワードを尋ねられるので、piユーザならデフォルトの「raspberry」と入力すればOKです。


 以上がSCPコマンドを使ったファイルのアップロードとダウンロードの方法です。

 こういうのも覚えてるとファイルのやりとりや更新が楽にできるのでどんどん使っていきたいです。


・2019/05/24追記:SCPコマンドでのディレクトリのアップロード/ダウンロード
 ファイルではなくディレクトリを丸ごと指定してアップロードやダウンロードをしたい場合は、以下のように「-r」オプションをつけます。

ディレクトリのアップロード

$ scp -r [対象ディレクトリパス] [ユーザ名]@[IPアドレス]:[アップロード先ディレクトリパス]
$ scp -r /Users/hoge/ pi@192.168.0.0:/home/pi/

ディレクトリのダウンロード

$ scp -r [ユーザ名]@[IPアドレス]:[対象ディレクトリパス] [ダウンロード先ディレクトリパス]
$ scp -r pi@192.168.0.0:/home/pi/ /Users/


・参考資料

【MacOS/Raspberry Pi】sshを使ってリモートログイン

 いちいちRaspberry Piにマウスやモニターやキーボードをくっつけて動かすのも面倒な場合、リモートログインして色々やりたくなる場合があります。
 調べれば出てきますが自分用に簡単にまとめたいと思ったので、今回はタイトルにある通り「sshを使ってリモートログイン」する方法です。

 では始めます。


1:Raspberry Pi側のSSHを有効にする
 Raspberry Piを立ち上げて「Raspberry Piの設定」を選択します。
f:id:rikoubou:20190520170724p:plain

インターフェイス」タブを選択して「SSH」の項目を「有効」に切り替えて「OK」ボタンをクリックします。
f:id:rikoubou:20190520170834p:plain

 SSHの設定が完了したら、設定を有効にするためにRaspberry Piを再起動させます。
f:id:rikoubou:20190520171111p:plain
f:id:rikoubou:20190520171136p:plain

 これでRaspberry Pi側でのSSHの設定は完了です。


2:Raspberry Pi側のIPアドレスを確認する
 IPアドレスを確認するには以下のどちらかのコマンドで確認できます。

$ ifconfig
$ ip a

 これで「192.168.0.0」のようなIPアドレスが確認できるので、それをメモしておきます(画像の赤枠部分)。
f:id:rikoubou:20190520171742p:plain


3:sshコマンドでリモートログインする
 IPアドレスがわかったら、MacOS側でターミナルを立ち上げて以下のコマンドでリモートログインします。

$ ssh [ユーザ名]@[IPアドレス]

 例えば2で確認したIPアドレスが「192.168.0.0」であり、Raspberry Piのデフォルトユーザである「pi」でログインする場合は以下のようになります。

$ ssh pi@192.168.0.0

 するとユーザのパスワードを求められるのでログインユーザのパスワードを入力すればログインできます。
 デフォルトユーザpiであれば、初期パスワードである「raspberry」を入力すればログインできます。


・おまけ:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!が出た場合
 3の手順でログインした際、以下のようなエラーメッセージが表示される場合があります。
f:id:rikoubou:20190520165956p:plain
 過去に同じIPアドレスで別の端末にログインしていた場合などにこのエラーが発生することがあります。

 その場合は以下のコマンドで過去の情報を削除します。

$ ssh-keygen -R [IPアドレス]

 対象のIPアドレスが「192.168.0.0」の場合は以下のようになります。

$ ssh-keygen -R 192.168.0.0

 このコマンドを実行した後、もう一度3のコマンドを実行するとエラーなくログインできます。


 以上がsshを使ってリモートログインする方法です。

 使ってない時期があると割と忘れてしまうので、こういうのもメモしていきたいですね…。


・参考資料

【Raspberry Pi】Raspberry Pi Zero WにOpenCVの環境を構築する

rikoubou.hatenablog.com
 以前の記事でTinkerBoardにOpenCV環境を構築してみました。
 最後のところで「Debian系なのでRaspberry Piでもいけるはず」と書いていたので、今回Raspberry Pi Zero WにOpenCV環境の構築をやってみました。

 結論から言うとほぼ同じ手順でOpenCVの環境は構築できました。ただやらなくて良いところや、ものすごく時間がかかるところなどがあるので別記事としてまとめた次第です。

 では始めます。


0:Raspberry Pi Zero Wの準備
 以下の記事でRaspberry Piの最低限のセットアップの方法を書いているのでこちらに沿ってRaspberry Pi Zero Wの最低限のセットアップを行います。


1:パッケージの最新化
 LXTerminalを起動させ、以下のコマンドを実行してパッケージを最新化します。

$ sudo apt-get update && sudo apt-get -y upgrade


2:python3用のpipをインストール
 以下のコマンドでpython3用のpipをインストールします。(場合によってはすでにインストールされていることもあります)

$ sudo apt-get install python3-pip


3:OpenCVのインストール
 2のpipを使ってOpenCVをインストールします。

$ pip3 install opencv-python

 Raspberry Pi Zero Wの場合、このコマンドが完了するまで2時間ほどかかります。


4:python3を立ち上げてimport cv2ができるか確認
 「python3」コマンドを実行してpythonを立ち上げ、import cv2と打ち込んでエラーがなければOpenCVが使えるようになっています。

$ python3
>> import cv2
>>


5:import cv2でエラーが発生したときの対処方法
 import cv2を打ち込んだ際に以下のようなエラーが発生することがあります。

ImportError: libjasper.so.1: cannot open shared object file: No such file or directory

 これは「libjasper.so.1」というライブラリが不足しているというメッセージなので、不足しているライブラリを入れていけば良いです。
 該当のライブラリを入れてからもう一度pythonを立ち上げ、import cv2を実行して不足しているライブラリを入れるというのを繰り返していきます。

 自分がやった場合において、不足していたライブラリを解消するために入力したコマンドは以下の通りです。

・libcblas.so.3

$ sudo apt-get install libatlas-base-dev

・libjasper.so.1

$ sudo apt-get install libjasper-dev

・libQtTest.so.4

$ sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig libqt4-test


 以上がRaspberry Pi Zero WにOpenCV環境を構築してみた手順になります。

 OSのバージョンなどによっては手順が変わる可能性があるので注意してください。


・参考資料

【Raspberry Pi】Raspberry Piで画面キャプチャをする

 今回はRaspberry Piで画面キャプチャを撮影する方法です。
 scrotというものをインストールして使っていきます。

 では始めます。


1:scrotをインストールする
 LXTerminalを起動させて以下のコマンドを実行することでインストールできます。

$ sudo apt-get update
$ sudo apt-get install scrot


2:scrotの使い方
 使い方としてはLXTerminalでコマンドを実行して画面キャプチャを行います。保存先は/home/pi配下になります。
 今回は使いそうなコマンドを列挙しておきます。
(※コマンドの詳しいオプションなどは参考資料に挙げてあるページ様を参照するようにしてください)

・コマンド実行後、10秒のカウントダウンの後に画面全体をキャプチャする

$ scrot -c -d 10

・コマンド実行後、マウスでクリックした画面をキャプチャする

$ scrot -s


 以上がRaspberry Piで画面キャプチャをする方法です。

 時間差などでキャプチャできたりと色々便利だと思います。


・参考資料

【MacOS/VSCode】MacOSにVisual Studio Codeをインストールして日本語化する

 昨今様々なエディタが存在していますが、自分が最近よく使っているのはVSCodeVisual Studio Code)です。友人からオススメされて入れたのですが、軽い上に拡張機能も豊富にあって「もう全部これでいいんじゃないかな」と思っているくらいです。

 使っているにも関わらず一度も記事にしたことがなかったので、今回は取り上げた次第です。
 基本的には参考資料に挙げたページ様の内容そのままなので、詳しい説明はそちらを参照してください。また今回はMacOSでの方法なので、その他のOSとは手順が違う場合があるので注意してください。

 では始めます。


1:VSCodeをインストールする

 公式ページへ飛ぶと最新バージョンのインストーラがあるのでクリックしてダウンロードします。
f:id:rikoubou:20190517134851p:plain

 zipファイルがダウンロードされるので解凍します。すると以下のように「Visual Studio Code.app」ファイルができます。
f:id:rikoubou:20190517134950p:plain

 そのままこのappファイルを起動させても良いですが、一般的にはMacのアプリケーションフォルダ内に集約されているのでそちらに移動させます。

 あとはVisual Studio Code.appを起動させれば終わりです。


2:VSCodeの日本語化
 VSCodeはメニューなどの表示はデフォルトで英語設定になっているので、これを日本語化します。

 VSCodeの左側にある四角いアイコンのようなものをクリックし、検索欄のところに「japanese」と入力します。すると、一番上にMicrosoft公式が提供している日本語化の拡張機能が表示されるので、そちらを選択してインストールします。(※この画像ではすでにインストール済になっています)
f:id:rikoubou:20190517135505p:plain

 インストール後に再起動するとメニューなどが日本語化されます。


メモ:入れている拡張機能
 自分が今VSCodeに入れている拡張機能をメモ的に残しておきます。

Python
 最近割とPythonを書く機会が多いのでPythonを入れています。
f:id:rikoubou:20190517140058p:plain

Arduino
 Arduino IDEが入っていること前提ですが、 VSCodeArduinoを扱える拡張機能を入れています。色々と設定する必要があったりはしますが、Arduino IDEはほぼ補完機能がないのでこちらの方が書きやすいかと思います。
f:id:rikoubou:20190517140218p:plain

・Live Share
 ネットを通じてVSCodeの画面を共有したりするための拡張機能です。ネットを通じたペアプロみたいなことができます。いずれこの機能についても記事にしたいです。
f:id:rikoubou:20190517140511p:plain
 

 以上がざっとしたVSCodeのインストールから日本語化とちょっとした拡張機能の紹介です。

 個人的にVSCodeはかなり気に入ってるので、まだ試したことのない人は入れてみると良いかと思います。


・参考資料

【python/OpenCV/dlib】顔を認識して笑い男画像をリアルタイムで貼り付ける

 過去の記事でdlibを使って顔認識をしたり、アルファ画像を合成したりしました。

 これらのやり方がわかれば「笑い男画像を貼り付けることができるのでは?」と思い今回作ってみました。

 では始めます。


1:顔に被せる画像を準備する
 顔に被せたいアイコン画像を準備します。今回は以下のページ様から画像をダウンロードします。


2:ソースコード
 以下のソースコードをコピペして「face_icon.py」として保存します。

・face_icon.py

# -*- coding: utf-8 -*-
import cv2
import dlib
from datetime import datetime

IMAGE_PATH = "./nc73730.png" # 画像パス
CAPTURE_SCALE = 0.5 # カメラの画像サイズ

def main():
    # 顔認証の準備
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

    cap = cv2.VideoCapture(0) # カメラの準備

    while True:
        _, frame = cap.read() # カメラ画像を取得
        
        # 画像サイズを変更
        frame = img_resize(frame, CAPTURE_SCALE)
        h, w, _  = frame.shape

        img = frame # img = frame * 0とすると黒画面になる
        dets = detector(frame[:, :, ::-1])

        if len(dets) > 0:
            parts = predictor(frame, dets[0]).parts() # 顔の点を取得
            distance, pos = calc_distance_and_pos(img, parts) # 顔の横幅と顔の中心を取得
            icon, icon_w, icon_h = load_icon(IMAGE_PATH, distance) # アイコン読み込み

            if (pos != None) and (distance > 0.0):
                x = pos.x - int(icon_w/2)
                y = pos.y - int(icon_h/2)
                if (0 <= y) and (y <= (h-int(icon_h))) and (0 <= x) and (x <= (w-int(icon_w))):
                    # 画面の範囲内だったら画像を合成
                    img = merge_images(img, icon, x, y)

        cv2.imshow("camera", img) # 画像を表示

        k = cv2.waitKey(1)&0xff # キー入力を待つ
        if k == ord('q'):
            # 「q」キーが押されたら終了する
            break
        elif k == ord('p'):
            # 「p」キーで画像を保存
            save_image(img)
            cv2.imshow("saved", img) # キャプチャした画像を表示

    # キャプチャをリリースして、ウィンドウをすべて閉じる
    cap.release()
    cv2.destroyAllWindows()

# アイコンを読み込む関数
def load_icon(path, distance):
    icon = cv2.imread(path, -1)
    icon_height, _  = icon.shape[:2]
    icon = img_resize(icon, float(distance * 1.5/icon_height))
    icon_h, icon_w  = icon.shape[:2]

    return icon, icon_w, icon_h

# 画像をリサイズする関数
def img_resize(img, scale):
    h, w  = img.shape[:2]
    img = cv2.resize(img, (int(w*scale), int(h*scale)))
    return img

# 距離と顔の中心座標を計算
def calc_distance_and_pos(img, parts):
    # 確認(33が顔の中心位置)
    cnt = 0
    pos = None
    p1 = None
    distance = 0.0

    for i in parts:
        if (cnt == 0):
            # 顔の幅を測る時の始点
            p1 = i
        if (cnt == 16):
            # 顔の幅を計算
            distance = ((p1.x-i.x)**2 + (p1.y-i.y)**2)**0.5
        if (cnt == 33):
            pos = i # 顔の中心位置
        # 画像に点とテキストをプロット
        cv2.putText(img, str(cnt), (i.x, i.y), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 0, 255), thickness=1, lineType=cv2.LINE_8)
        cv2.circle(img, (i.x, i.y), 1, (255, 0, 0), -1)
        cnt = cnt + 1

    return distance, pos

# 画像を保存する関数
def save_image(img):
    date = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = "./" + date + ".png"
    cv2.imwrite(path, img) # ファイル保存

# 画像を合成する関数
def merge_images(bg, fg_alpha, s_x, s_y):
    alpha = fg_alpha[:,:,3]  # アルファチャンネルだけ抜き出す(要は2値のマスク画像)
    alpha = cv2.cvtColor(alpha, cv2.COLOR_GRAY2BGR) # grayをBGRに
    alpha = alpha / 255.0    # 0.0〜1.0の値に変換

    fg = fg_alpha[:,:,:3]

    f_h, f_w, _ = fg.shape # アルファ画像の高さと幅を取得
    b_h, b_w, _ = bg.shape # 背景画像の高さを幅を取得

    # 画像の大きさと開始座標を表示
    print("f_w:{} f_h:{} b_w:{} b_h:{} s({}, {})".format(f_w, f_h, b_w, b_h, s_x, s_y))

    bg[s_y:f_h+s_y, s_x:f_w+s_x] = (bg[s_y:f_h+s_y, s_x:f_w+s_x] * (1.0 - alpha)).astype('uint8') # アルファ以外の部分を黒で合成
    bg[s_y:f_h+s_y, s_x:f_w+s_x] = (bg[s_y:f_h+s_y, s_x:f_w+s_x] + (fg * alpha)).astype('uint8')  # 合成

    return bg

if __name__ == '__main__':
    main()

 以下のように保存したら以下のように「face_icon.py」と同じ階層に、被せたい画像「icon.png」とdlibの学習済みデータである「shape_predictor_68_face_landmarks.dat」を配置します。
f:id:rikoubou:20190515173226p:plain

 この状態で実行すると以下のような感じで顔に画像を被せた状態で表示されます。
f:id:rikoubou:20190515173140p:plain

 顔を前後に動かすと、その顔の大きさに応じて被せる画像の大きさも変化します。顔が認識されない時や被せる画像が画面サイズからはみ出してしまう時は被せる画像は表示されません。
 また「p」キーを押すと画面キャプチャもできます。


 以上が今回作ってみたものになります。

 攻殻機動隊が好きだったので、割と手軽に笑い男を再現できて面白かったです。顔に被せる画像を色々変更して遊んでみるのもいいですね。


・参考資料