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

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

【python/OpenCV】画像を手書きっぽく加工するやつを作ってみる

 最近SNSなどでとある手書き風のアプリがリリースされちょっと話題になっています。

 iPhoneを持っていないのでどのようなアプリかはわかっていないのですが、結果の動画や画像を見る限りではOpenCVで再現できそうでした。そこでタイトルにあるように似たようなものを作れないかと思い、自分で色々調べて作ってみたのでその備忘録です。

 ちなみに自作したものは以下のような感じになります。

・加工前
f:id:rikoubou:20181115184750j:plain

・加工後
f:id:rikoubou:20181115184805p:plain

 完全に同じにはなりませんが、割と手書きな感じにはなっているかと思います。

 今回の画像加工の手順としては大体「グレースケール化→輪郭線抽出→影部分の抽出→輪郭線と影部分の合成」という順番でやっています。

 ではそれぞれについて説明していきます。読むのが面倒な場合は最後のソースコードのところまで飛ばしてください。


1:グレースケール化
 輪郭線を抽出する前段階として画像をグレースケール化します。輪郭線を抽出する前段階として一般的なものです。
 グレースケール化するには以下の「cv2.cvtColor」関数でできます。

import cv2

image = cv2.imread('hogehoge.jpg') # 画像取得
grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # グレースケール


2:輪郭線抽出
 グレースケール化したものから輪郭線を抽出するのは「cv2.Canny」関数でできます。

outlineImage = 255 - cv2.Canny(grayImage, 110, 70)

 cv2.Cannyの第1引数がグレースケール化した画像です。第2引数と第3引数を変化させることで取得する線の調節ができます。
「255」という値から結果を引いているのは、cv2.Cannyの結果として線の部分が白、他が黒になっているためです。255から結果を引くことで色を反転させています。


3:影部分の抽出
 影部分の抽出は以下の手順でやっています。

grayImage = cv2.GaussianBlur(grayImage, (31, 31), 30) # ぼかす
ret, shadowImage = cv2.threshold(grayImage, 40, 220, cv2.THRESH_BINARY) # 閾値で2値化

 GaussianBlur関数でぼかし、そのあと2値化しています。これで影の部分が取得できます。


4:輪郭線と影部分の合成
 2つの画像ができたのであとは合成します。合成には「cv2.bitwise_and」関数を使います。

resultImg = cv2.bitwise_and(outlineImage, shadowImage)


5:ソースコード
 基本的には1〜4の手順で行い、適宜コントラストを減らしたりぼかしを加えたりなどして調節しています。
 今回作成したソースコードは以下の通りです。

 ・2018/11/19追記:画像サイズが奇数ピクセルだとエラーになっていたのでソースコードを修正しました。

・cv2Outline.py

import numpy as np
import cv2
import glob
from datetime import datetime
from time import sleep

RESIZE_SIZE = 4 # 画像を処理する時に使うサイズ(1/n)
CAMERA_SIZE = 2 # カメラ画像の縮小サイズ(1/n)

# カメラフラグでTrueにするとWebカメラの変換になる
CAMERA_FLG = False

IMG_FOLDER_PATH = "./img/*"     # 画像フォルダ
SAVE_FOLDER_PATH = "./result/"  # 出力保存フォルダ


# メイン関数
def main():
    print("--- start ---")

    # カメラの場合との場合分け
    if (CAMERA_FLG):
        # VideoCaptureのインスタンスを作成(引数でカメラを選択できる)
        cap = cv2.VideoCapture(0)
        changeCameraImage(cap)
        closeWindows(cap) # ウインドウを全て閉じる
    else:
        changeLoadImages(IMG_FOLDER_PATH, SAVE_FOLDER_PATH)

    print("--- end ---")


# カメラの映像を変換する関数
def changeCameraImage(cap):
    while True:
        ret, frame = cap.read() # 戻り値のframeがimg
        resultImg = changeImage(frame) # 画像変換

        # 結果をリサイズ
        fx = int(resultImg.shape[1]/CAMERA_SIZE)
        fy = int(resultImg.shape[0]/CAMERA_SIZE)
        resultImg = cv2.resize(resultImg, (fx, fy))

        # 文字を追加
        text = 'Exit is [Q] key'
        cv2.putText(resultImg, text, (0,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255,0), 3, cv2.LINE_AA)

        # 加工した画像を表示
        cv2.imshow('resultImg', resultImg)

        # キー入力を1ms待って、keyが「q」だったらbreak
        key = cv2.waitKey(1)&0xff
        if key == ord('q'):
            break


# 画像を読み込んで変換する関数
def changeLoadImages(imgFolderPath, saveFolderPath):
    images = glob.glob(imgFolderPath)

    for fname in images:
        frame = cv2.imread(fname) # 画像取得
        resultImg = changeImage(frame) # 画像変換

        # 画像保存
        saveImgByTime(saveFolderPath, resultImg)
        sleep(1)


# 画像を変換する関数
def changeImage(colorImg):
    gray = cv2.cvtColor(colorImg, cv2.COLOR_BGR2GRAY) # グレースケール
    gray = cv2.GaussianBlur(gray, (15, 15), 15) # ぼかす

    # 輪郭線処理
    img_diff = outine(gray) # 輪郭線抽出
    img_diff = cv2.GaussianBlur(img_diff, (11, 11), 8) # ぼかす
    ret, img_diff = cv2.threshold(img_diff, 170, 240, cv2.THRESH_BINARY) # 閾値で2値化

    # 影部分の処理
    gray = cv2.GaussianBlur(gray, (31, 31), 30) # ぼかす
    ret, gray = cv2.threshold(gray, 40, 220, cv2.THRESH_BINARY) # 閾値で2値化
    gray = lowContrast(gray) # コントラストを落とす
    
    # 輪郭線と影部分の画像を合成
    resultImg = cv2.bitwise_and(img_diff, gray)

    return resultImg


# 画像の輪郭線を抽出する関数
def outine(grayImg):
    # リサイズ
    fx = int(grayImg.shape[1]/RESIZE_SIZE)
    fy = int(grayImg.shape[0]/RESIZE_SIZE)

    grayChangeImg = cv2.resize(grayImg, (fx, fy))
    # 輪郭線抽出
    result = 255 - cv2.Canny(grayChangeImg, 110, 70)
    # リサイズして元に戻す
    result = cv2.resize(result, (grayImg.shape[1], grayImg.shape[0]))
    return result


# コントラストを落とす関数
def lowContrast(img):
    # ルックアップテーブルの生成
    min_table = 50
    max_table = 230
    diff_table = max_table - min_table
    look_up_table = np.arange(256, dtype = 'uint8' )
 
    for i in range(0, 255):
        look_up_table[i] = min_table + i * (diff_table) / 255
 
    # コントラストを低減
    result = cv2.LUT(img, look_up_table)
    return result


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


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


if __name__ == '__main__':
    main()

 少し説明すると「cv2Outline.py」として保存したファイルと同じ場所に「img」、「result」のフォルダをそれぞれ作成します。そして「img」フォルダに加工前の画像を入れて「python3 cv2Outline.py」を実行すると「result」フォルダに結果が保存されます。

 また以下の部分の「False」を「True」に書き換えて実行するとWebカメラの表示に切り替わります。

# カメラフラグでTrueにするとWebカメラの変換になる
CAMERA_FLG = False

 2018/11/19追記:また画像が小さいといい感じに輪郭線の抽出ができていないようだったため、画像サイズに合わせてある程度計算で適切に処理するようなバージョンも作りました。

・alt_cv2Outline.py

import numpy as np
import cv2
import glob
from datetime import datetime
from time import sleep

CAMERA_SIZE = 2 # カメラ画像の縮小サイズ(1/n)

BLUR_VALUE = 25000 # ブラーをかけるための定数
PIXEL_VALUE = 300000 # 拡大/縮小の基準となるピクセル

# カメラフラグでTrueにするとWebカメラの変換になる
CAMERA_FLG = False

IMG_FOLDER_PATH = "./img/*"     # 画像フォルダ
SAVE_FOLDER_PATH = "./result/"  # 出力保存フォルダ

# メイン関数
def main():
    print("--- start ---")

    # カメラの場合との場合分け
    if (CAMERA_FLG):
        # VideoCaptureのインスタンスを作成(引数でカメラを選択できる)
        cap = cv2.VideoCapture(0)
        changeCameraImage(cap)
        closeWindows(cap) # ウインドウを全て閉じる
    else:
        changeLoadImages(IMG_FOLDER_PATH, SAVE_FOLDER_PATH)

    print("--- end ---")


# カメラの映像を変換する関数
def changeCameraImage(cap):
    while True:
        ret, frame = cap.read() # 戻り値のframeがimg
        resultImg = changeImage(frame) # 画像変換

        # 結果をリサイズ
        fx = int(resultImg.shape[1]/CAMERA_SIZE)
        fy = int(resultImg.shape[0]/CAMERA_SIZE)
        resultImg = cv2.resize(resultImg, (fx, fy))

        # 文字を追加
        text = 'Exit is [Q] key'
        cv2.putText(resultImg, text, (0,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255,0), 3, cv2.LINE_AA)

        # 加工した画像を表示
        cv2.imshow('resultImg', resultImg)

        # キー入力を1ms待って、keyが「q」だったらbreak
        key = cv2.waitKey(1)&0xff
        if key == ord('q'):
            break


# 画像を読み込んで変換する関数
def changeLoadImages(imgFolderPath, saveFolderPath):
    images = glob.glob(imgFolderPath)

    for fname in images:
        frame = cv2.imread(fname) # 画像取得
        resultImg = changeImage(frame) # 画像変換

        # 画像保存
        saveImgByTime(saveFolderPath, resultImg)
        sleep(1)


# 画像を変換する関数
def changeImage(colorImg):
    gray = cv2.cvtColor(colorImg, cv2.COLOR_BGR2GRAY) # グレースケール

    # ピクセル数からぼかす値を計算
    allPixel = colorImg.shape[1] * colorImg.shape[0]
    bokashi = calcBlurValue(allPixel)
    gray = cv2.GaussianBlur(gray, (bokashi, bokashi), bokashi) # ぼかす

    # 輪郭線処理
    img_diff = outine(gray, allPixel) # 輪郭線抽出

    # 輪郭線用のぼかし計算
    bokashiOutline = bokashi
    if bokashi > 4:
        bokashiOutline = bokashi - 4

    img_diff = cv2.GaussianBlur(img_diff, (bokashiOutline, bokashiOutline), bokashiOutline) # ぼかす
    ret, img_diff = cv2.threshold(img_diff, 170, 240, cv2.THRESH_BINARY) # 閾値で2値化

    # 影部分の処理
    gray = cv2.GaussianBlur(gray, (bokashi, bokashi), bokashi) # ぼかす
    ret, gray = cv2.threshold(gray, 40, 220, cv2.THRESH_BINARY) # 閾値で2値化
    gray = lowContrast(gray) # コントラストを落とす
    
    # 輪郭線と影部分の画像を合成
    resultImg = cv2.bitwise_and(img_diff, gray)

    return resultImg


# ブラーをかける値を計算する関数
def calcBlurValue(allPixel):
    result = int(np.sqrt(allPixel/BLUR_VALUE))
    if (result%2 == 0):
        result = result + 1
    return result


# 画像の輪郭線を抽出する関数
def outine(grayImg, allPixel):
    # リサイズ
    z =  np.sqrt(PIXEL_VALUE / (grayImg.shape[1] * grayImg.shape[0]))
    if (z > 1):
        z = 1

    fx = int(grayImg.shape[1] * z)
    fy = int(grayImg.shape[0] * z)

    grayChangeImg = cv2.resize(grayImg, (fx, fy))
    # 輪郭線抽出
    result = 255 - cv2.Canny(grayChangeImg, 100, 50)
    # リサイズして元に戻す
    result = cv2.resize(result, (grayImg.shape[1], grayImg.shape[0]))
    return result


# コントラストを落とす関数
def lowContrast(img):
    # ルックアップテーブルの生成
    min_table = 50
    max_table = 230
    diff_table = max_table - min_table
    look_up_table = np.arange(256, dtype = 'uint8' )
 
    for i in range(0, 255):
        look_up_table[i] = min_table + i * (diff_table) / 255
 
    # コントラストを低減
    result = cv2.LUT(img, look_up_table)
    return result


# 画像を時刻で保存する関数
def saveImgByTime(dirPath, img):
    # 時刻を取得
    date = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = dirPath + date + ".png"
    cv2.imwrite(path, img) # ファイル保存
    print("saved: " + date + ".png")


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


if __name__ == '__main__':
    main()

 画像の大きさに合わせてそれぞれのソースコードを使い分ければいいかなと思っています。(どうしても画像のサイズや単純なものが写っているかどうかに影響してくるので…)


 以上が今回作ってみたものです。OpenCVpythonがあれば手軽に色々な加工ができて面白いです。

 また今回作ったソースコードも一応公開しておきます。


・参考資料

【python/OpenCV】OpenCVでWebカメラの画像を取得する

 OpenCVを入れたのでちょっとWebカメラで遊んでみるというタイトル通りの内容です。

 基本的には参考にした内容ほぼ丸パクリです。


1:OpenCVWebカメラの画像を取得する
 以下の記述でできます。

import cv2 # OpenCV のインポート

# VideoCaptureのインスタンスを作成(引数の番号でカメラを選択できる)
cap = cv2.VideoCapture(0)

# VideoCaptureから1フレーム読み込む
ret, frame = cap.read() # 戻り値のframeが画像

「cap = cv2.VideoCapture(0)」で接続しているWebカメラインスタンスを作成しています。ノートPCなどに内臓されているカメラの場合は、引数に「0」を指定してあげれば良いです。
「ret, frame = cap.read()」でカメラの画像を1フレーム読み込みます。この戻り値のframeが読み込んだ画像になります。


2:サンプルコード
 1の内容でWebカメラの画像が取得できました。これを応用してカメラの画像に現在時刻を表示させるサンプルを作りました。

 そのサンプルが以下になります。

from datetime import datetime # 時刻関係のライブラリ
import cv2 # OpenCV のインポート

# VideoCaptureのインスタンスを作成(引数でカメラを選択できる)
cap = cv2.VideoCapture(0)

while True:
    # VideoCaptureから1フレーム読み込む
    ret, frame = cap.read() # 戻り値のframeがimg

    # 1/4にリサイズ
    frame = cv2.resize(frame, (int(frame.shape[1]/4), int(frame.shape[0]/4)))
    # 加工なし画像を表示する
    # cv2.imshow('Raw Frame', frame)

    # 現在時刻の文字列を画像に追加
    date = datetime.now().strftime("%H:%M.%S")
    edframe = frame
    cv2.putText(edframe, date, (0,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255,0), 3, cv2.LINE_AA)

    # 加工した画像を表示
    cv2.imshow('Edited Frame', edframe)

    # キー入力を1ms待って、keyが「q」だったらbreak
    key = cv2.waitKey(1)&0xff
    if key == ord('q'):
        break

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

 このサンプルを実行すると、Webカメラの元画像を1/4した大きさのものに現在時刻が左上に表示されます。
 終了させる時は「q」キーを押すと終了します。


 以上がWebカメラの画像を取得する方法です。割と簡単に実装できたのでOpenCVを使ってもっと色々なことをやっていきたいです。


・参考資料

【Blender/OpenCV】BlenderでOpenCVを使えるようにする

 今回はタイトルにあるようにBlenderOpenCVを使えるようにする方法の備忘録です。
 別にBlenderOpenCVを使う必要はないかもしれませんが、調べてやってみたらできたので残しておきます。

 以前の記事でやったOpenCVのインストールまで終わっているという前提で進めていきます。
rikoubou.hatenablog.com

 では始めます。


1:OpenCVのインストール先を確認する
 ターミナルを起動し「python」と入力してpythonを立ち上げます。
 pythonを立ち上げたら以下のコマンドを入力してOpenCVのインストールパスを確認します。

import cv2
cv2

 実行すると以下のようになるので、表示される「.../cv2/」までのパス(赤線部分)をコピーしておきます。
f:id:rikoubou:20181106134550p:plain


2:Blenderを起動させてOpenCVを読み込ませる
 1でOpenCVのパスを確認できたらBlenderを起動させ、Scripting画面に切り替えます。
f:id:rikoubou:20181106134848p:plain
f:id:rikoubou:20181106134924p:plain

 下半分の黒い画面がpythonの入力ができるコンソール画面になっているので、ここにpythonのコードを入力してOpenCVを使えるようにします。

 Blenderでは外部のライブラリの読み込みは自動で行ってくれないので、手動で設定してやる必要があります。
 pythonでの外部ライブラリの読み込みは以下のように記述します。

import sys
sys.path.append("[ライブラリのパス]")

 なのでOpenCVを使うには上記のコードをBlenderのコンソール画面に入力していきます。

 一行ずつ入力して行きエラーが発生しなければ以下のように「import cv2」をすることでBlenderOpenCVを扱えるようになります。
f:id:rikoubou:20181106140151p:plain


3:「import cv2」の実行でエラーが出る時の対処法
 sys.path.appendをした後の「import cv2」でエラーが出ることがあります。

  • パスが間違っている場合

 以下のようなエラーが出る場合があります。

import cv2

Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
ModuleNotFoundError: No module named 'cv2'

 この場合はライブラリまでのパスが間違っている可能性が高いので、もう一度ライブラリのパスを確認してください。

  • numpyのバージョンが合っていない場合

 以下のようなエラーが出る場合があります。

import cv2

RuntimeError: module compiled against api version 0xc but this version of numpy is 0xa
(色々と続く...)

 この場合はOpenCVのnumpyとBlenderのnumpyのバージョンが合ってない時に起こるエラーです。
 対処するには以下のコマンドで「ターミナルから起動するpythonでのnumpyのバージョン」と「Blenderでのnumpyのバージョン」を確認してください。

import numpy
numpy.__version__

 ターミナルから起動するpythonBlenderでバージョンをそれぞれ確認します。
f:id:rikoubou:20181106141622p:plainf:id:rikoubou:20181106141543p:plain

 ここの例ではバージョンが1.15系として合っていますが、違っている場合は以下の方法で両方のnumpyを最新にします。

・ターミナルから起動するnumpyのアップグレード
 pipでインストールしているので、以下のコマンドを入力してnumpyをアップグレードさせます。

$ pip install numpy --upgrade

Blenderのnumpyアップグレード
 以下のリンクにある「Official」のマークが付いている最近のBlenderをダウンロードしてインストールします。

 両方とも最新にするとnumpyのバージョンが合うようになるはずなので、もう一度同じようにライブラリをappendさせてから「import cv2」をするとエラーが解消されます。


 以上がBlenderOpenCVを使えるようにする方法です。
 まだOpenCV自体何もわかっていないので、組み合わせて何か面白いものを作れるようになりたいです。


・参考資料

【python/OpenCV】インストールしたpythonとOpenCVのパスを確認する

 以前の記事でpythonOpenCVのインストールをしました。

 ちょっと気になってそれぞれどこにインストールされてるのか知りたかったのですが、ぱっと見よくわかりませんでした。
 調べたところ「pythonを開いてコマンドを叩けば良い」ということがわかったので、そのメモです。


・ライブラリのインストール場所を確認する方法
 基本的には以下の方法で確認できます。

import [ライブラリ]
print([ライブラリ].path)

 pythonのインストール先を確認するのは以下のコマンドでできます。

import sys
print(sys.path)

 出力結果は以下のようになります。
f:id:rikoubou:20181105173950p:plain

 OpenCVのインストール先を確認するのは以下のコマンドでできます。

import cv2
print(cv2)

 出力結果は以下のようになります。
f:id:rikoubou:20181105174114p:plain


 以上がパスの確認方法です。

 パスが必要になる時が稀によくあるので、その時のためのメモです…。


・参考資料

【python/OpenCV】MacOSにpythonとOpenCVの環境を構築する

 pythonOpenCV使ってみるかー、と思い立って環境構築しようとしたのですが、自分が使っているMacpythonの環境がよくわからなくなってしまっていたので、一度まっさらにしてから入れ直すということをやりました。

 色々と戸惑ってしまった部分も多かったので備忘録として残そうと思った次第です。


1:HomeBrewをインストールする
 HomeBrewをインストールしていない場合はHomeBrewをインストールします。

 ターミナルを立ち上げて以下のコマンドを実行すればインストールされます。

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"


2:pyenvをインストールする
 pyenvは使用するpythonのバージョンを切り替えたり管理したりするためのものです。

 HomeBrewをインストールできたら、以下のコマンドを実行してpyenvをインストールします。

$ brew install pyenv

 この時に以下のような権限エラーが出る場合があります。(自分の場合は出ました)

$ brew install pyenv

Updating Homebrew...
Error: The following directories are not writable by your user:
/usr/local/share/man/man5
/usr/local/share/man/man7

You should change the ownership of these directories to your user.
  sudo chown -R $(whoami) /usr/local/share/man/man5 /usr/local/share/man/man7

 このようなエラーが出た場合はエラーの記述にある通り以下のコマンドを実行して権限を変更します。

$ sudo chown -R [ユーザ名] /usr/local/share/man/man5 /usr/local/share/man/man7

 ユーザ名のところに権限を与えたい名前を入れて実行すると権限を変更でき、その後に再度「brew install pyenv」コマンドを実行するとエラーなく実行することができます。


3:インストールできる一覧を確認する
 以下のコマンドを実行するとインストールできる一覧が表示されます。

$ pyenv install --list

 何も書かれていない「3.7.0」などがpythonのバージョンです。他にも「anaconda3-5.2.0」などanacondaも選択できます。


4:バージョンを指定してpythonをインストールする
 一覧の中にあるものからインストールしたいものを選択してインストールします。(基本的には一番最新のバージョンで良いかと思います)

 以下のコマンドでインストールできます。

$ pyenv install [バージョン番号]

 python3.7.0をインストールしたい場合は以下のように記述します。

$ pyenv install 3.7.0


5:pythonのバージョンを切り替える
 pythonをインストールできたら、以下のコマンドを実行してインストールされている一覧を確認します。

$ pyenv versions

 これを実行すると以下のようにインストールされている一覧と現在選択中のバージョンが表示されます。
f:id:rikoubou:20181029163649p:plain

「*」のマークがついているのが、現在選択されているバージョンです。

 pythonのバージョンを切り替えるには以下のコマンドを実行します。

$ pyenv global [バージョン番号]

 python 3.7.0に切り替えたい場合は以下のようにします。

$ pyenv global 3.7.0

 このコマンドを実行した後にもう一度「pyenv versions」を実行すると、以下のように使用するpythonが切り替わります。
f:id:rikoubou:20181029164059p:plain

 バージョンが切り替わったかの確認として以下のコマンドを実行します。

$ python -V

 すると以下のようにpythonのバージョンを確認できます。
f:id:rikoubou:20181029164146p:plain


6:環境変数の設定
 以下のコマンドで「.bash_profile」をviエディタを開きます。

$ vi ~/.bash_profile

「i」キーを押して「insertモード」に切り替えてから、以下の一行をコピペして追記します。

export PATH="$HOME/.pyenv/shims:$PATH"

 追記が終了したら「ESC」キーを押して「コマンドモード」に切り替えてから、以下のコマンドを入力して上書き保存します。

:wq

 ファイルの上書き保存が終了したら、以下のコマンドを実行してファイルを再読み込みします。

$ source ~/.bash_profile


7:pipを使ってOpenCVをインストールする
 次にOpenCVをインストールします。pyenvを使ってpythonをインストールするとpipというのも入っているので、pipを使ってOpenCVを入れます。

 OpenCVを入れるには以下のコマンドを実行するだけです。

$ pip install opencv-python

 また商用には非推奨(特許関連のものも含まれているらしい)ですが、以下のコマンドを実行すると通常のOpenCVよりもより機能が含まれているものをインストールできます。

$ pip install opencv-contrib-python

 上記の2つのコマンドは競合してしまうようなので、どちらか一方をインストールした後に変更したい場合は以下のように一度アンインストールコマンドを実行してから入れ直す必要があります。

$ pip uninstall opencv-python
$ pip uninstall opencv-contrib-python


8:pythonOpenCVが使えるかの確認
 OpenCVのインストールができたら、pythonからOpenCVを使えるかの確認をします。

 ターミナルで「python」と入力してpythonを立ち上げて「import cv2」と入力します。これでエラーが出なければ、OpenCVを使えるようになっています。
f:id:rikoubou:20181029165808p:plain

 確認できたら「Ctrl+D」キーでpythonを終了させます。
 

 以上がMacOSpythonのインストールとpythonOpenCVを使えるようにするまでの手順です。

 ネットで探すと色々方法があって戸惑いましたが、一応上記のやり方でできました。
 これで画像処理とかをやっていきたいですね。


・参考資料

【Blender/イベント】BlendxJP3に参加してきました

techplay.jp

 2018/10/27(土)に渋谷にて行われた「BlendxJP3」に参加してきました。

 会場での写真は全く撮影してなかったので掲載することはできませんが、登壇者参加者含めて170名ほどの人が集まった熱気のあるイベントで非常に楽しかったです。

 発表内容も「Blenderpythonアドオンを作ろう!」というところから始まり、VRアドベンチャーの「東京クロノス」に関するものやBlender2.8のレンダリング、2DアニメーションによるBlender使用事例の紹介などなど盛りだくさんでした。

 終了後の懇親会でも他業種の様々な方とお話できて非常に有意義でした。お話させていただいた方々ありがとうございました。

 次があればまた参加したいと思います。

  Blenderはいいぞ!!!

 ちなみに当日のTwitterの内容がまとめられているようなので、そちらもどうぞ。
togetter.com

【Blender】Blender2.8のグリースペンシルを使ってみる

 お久しぶりです。ちょっと更新の期間が空いてしまいました。
 今回はタイトルにある通り、最近Twitterなどでも話題のBlender2.8でのグリースペンシル機能を使って見た時の備忘録です。

 ただし、「Blender2.8はまだ正式にリリースされていないもの」なので、突然落ちたりバグがあったりなど予期せぬことが起きても自己責任ということになるので理解をお願いします。

 またBlender2.79での知識が前提という想定で進めます。

 では始めていきます。


1:Blender2.8でのグリースペンシルの特徴
 Blender2.8でのグリースペンシルの特徴を挙げていきます。

・グリースペンシル自体がオブジェクト
 2.79との最大の違いはグリースペンシルがオブジェクトになったことです。これによりグリースペンシルにモディファイアを追加したり、ノードを使って色々な処理を追加したりできるようになりました。

・色はマテリアルで管理
 グリースペンシル自体がオブジェクトになったためか、グリースペンシルの色はマテリアルで管理するようになりました。つまり色を追加する場合は新たなマテリアルを作成することになります。

・塗りつぶし機能の追加
 他のペイントソフトでは標準的な機能ですが、2.79時代にはなかった塗りつぶし機能がついに追加されました。ただし塗りつぶしをする色のマテリアルはちょっと工夫をしないといけないので注意が必要です。

 自分が確認した中ではこれらが一番大きな特徴です。


2:Blender2.8をダウンロードする
 Blender2.8はまだ正式にリリースされていないものなので、Blenderの公式ページからはダウンロードリンクはありません。

 Blender2.8は以下のページからダウンロードできます。「Blender2.8」のマークがついているものの中から、OSに合ったリンクをクリックしてダウンロードします。

 自分の場合はMacなので以下のリンクからダウンロードします。
f:id:rikoubou:20181024153222p:plain

 ダウンロードしたファイルを解凍すると、Blender2.8の実行ファイルが入っています。
f:id:rikoubou:20181024154038p:plain


3:Blender2.8でのグリースペンシル画面の起動方法
 2でダウンロードしたBlender2.8を実行すると以下のような起動画面になります。
f:id:rikoubou:20181024154736p:plain

 Blender2.79とはもはや別物になってるので戸惑うかと思いますが、起動した時に表示されている「2D Animation」を左クリックします。
f:id:rikoubou:20181024154909p:plain

 すると以下のような2D Animation用の画面になり、すぐにグリースペンシル機能を使えるようになっています。
f:id:rikoubou:20181024155057p:plain

 まずは画面内の説明からしていきます。

 以下の①がグリースペンシルのレイヤーです。起動画面の「2D Animation」で立ち上げた場合、LinesとFillsの2つのレイヤーがあります。
 ②が色です。マテリアルになっており、デフォルトでのいくつかの線の色と塗りつぶし用の「Grey」があります。
 ③がドープシート部分です。2.79の時と同じようにキーフレームにグリースペンシルを登録してアニメーションさせることができます。
f:id:rikoubou:20181024164658p:plain

 他のペイントソフトのように左クリックをした状態でマウスを動かすと、以下のように線を書くことができます。
f:id:rikoubou:20181024155451p:plain

 左側でペン先や塗りつぶし、消しゴムなどを選択でき、右下のところで色を選択できます。
f:id:rikoubou:20181024160350p:plain

 これで適当な線を書いたり消したりはできるかと思います。塗りつぶしはちょっと注意が必要なので次で説明します。


4:Blender2.8でのグリースペンシルの色と塗りつぶし
 先に述べたように2.8でのグリースペンシルの色はマテリアルとして管理されています。

・色の追加
 色の追加は色が表示されているところの「+」ボタンを左クリックします。
f:id:rikoubou:20181024165456p:plain

 新しい空のマテリアルスロットが作成されるので、下の「New」ボタンを左クリックします。
f:id:rikoubou:20181024170005p:plain

 マテリアルが追加されました。
f:id:rikoubou:20181024170055p:plain

 追加したマテリアルを選択した状態で下にスクロールすると、StrokeとFillの項目があります。Strokeは線の色、Fillは塗りつぶしの色の設定です。
f:id:rikoubou:20181024171037p:plain

 例えば以下のようにStrokeのColorを左クリックして色をピンクに、FillのColorを左クリックして黄色に設定してみます。この時Fillのアルファ値を1にして表示させておきます。
f:id:rikoubou:20181029170745p:plainf:id:rikoubou:20181024174238p:plain

 設定したマテリアルを選択した状態で線を書くと、以下のようにStrokeで設定した色の線が引かれ、囲まれた内側がFillで設定した色で塗りつぶしされます。
f:id:rikoubou:20181024171838g:plain

 この状態でFillのアルファ値を0に変更すると、以下のように塗りつぶしの色が見えなくなります。
f:id:rikoubou:20181024172202g:plain


・塗りつぶし
 塗りつぶしたい色のマテリアルを選択した状態で左側にある「バケツ」アイコンを左クリックします。(現在選択中のマテリアルのFillのアルファ値は0になっています)
f:id:rikoubou:20181024173332p:plain

 この状態で塗りつぶしたい範囲を左クリックすると、以下のようにStrokeの線の部分のみが表示されるばかりになります。(左クリックを連打しています)
f:id:rikoubou:20181024173616g:plain

 次にFillのアルファ値を1にした状態で塗りつぶしを行うと、以下のようにStrokeのピンク色の線が外縁となり、その内側がFillの色で塗られます。
f:id:rikoubou:20181024173724g:plain


 つまり、線のみの色を作成したい時は「Strokeの色を設定し、Fillのアルファ値を0にする」ようにし、塗りつぶしの色を作成したい時は「StrokeとFillの色を同じに設定し、Fillのアルファ値を1にする」ということになります。


5:Blender2.8でのグリースペンシルアニメーション
 まずはオニオンスキンの設定です。

 レイヤーが表示されている部分をスクロールさせていくと「Onion Skinning」という項目があるので、これにチェックを入れるとオニオンスキンが使えるようになります。
f:id:rikoubou:20181024165021p:plain

 これでオニオンスキンが使えるようになったので、あとは2.79の時と同じようにキーフレームにグリースペンシルを登録していけばよいです。

 適当に自分が作ってみたのが以下になります。
f:id:rikoubou:20181024175705g:plain


6:Blender2.8でのグリースペンシルアニメーションのレンダリング
 レンダリングして動画として出力する場合は、「カメラ」アイコンを左クリックして表示された中をスクロールして以下の②〜④の設定を行います。
f:id:rikoubou:20181024183845p:plain

 ②で出力ファイル名を設定します。
 ③「File Format」のプルダウンを「FFmpeg video」に変更します。
 ④「Encording」の「Container」のプルダウンを「MPEG-4」に変更します。

 レンダリングの設定が終わったら、画面メニューの「Render」→「Render Animation」を左クリックするとレンダリングが始まります。
f:id:rikoubou:20181024184401p:plain

 レンダリング結果は以下のようになります。

 グリースペンシルのレンダリングした結果の色が暗くなる理由はよくわかりませんが、とりあえずこれで動画として書き出すことができました。


 以上がBlender2.8のグリースペンシルを使ってみた感じです。
 前のバージョンとかなり違っているので戸惑いますが、便利な機能も追加されているので本リリースされたらすぐに使えるようになっておきたいですね。


・参考資料
www.youtube.com