見出し画像

【MachineLearning、iOS】デザイナー向けのコンペに全力でプログラムをぶつけてみた

以下のコンペがあるということをFacebookかInstagramか忘れましたが、2月くらいに見つけて面白そうだから応募してみました。

応募要項「シブヤ」「時代」「人間」「妖怪」「お祭り」のいずれかのテーマ、または、それらの組み合わせを「ピクセルアート」で表現。期間中、TwitterまたはInstagramで、「Shibuya Pixel Art」公式アカウントをフォローし、自身が制作したイラスト、アニメ、映像、彫刻、刺繍、写真などを「#shibuyapixelart2019」のハッシュタグと「作品タイトル」を付けて投稿。※https://pixel-art.jp/03/contest/ から引用

応募背景
・絵が全く描けなくてもプログラムでなんとかしてやってけそう
応募方法がめっちゃ楽(TwitterかInstagramで投稿で応募可能なため)
・ハッシュタグ見たらピクセルの絵の作品が多いのでプログラムでやればインパクトあるんじゃないかという安直な思考

応募した作品
画面上に人がいたらその人の部分を検知してFragmentShaderという処理を施してPixel化する作品を作りました。

使用した技術について
大きく分けて以下の2点です。

・Machine Learning(機械学習)
iOSのFrameworkにあるCoreMLという機械学習をする機能を利用して人を検知します。人を検知するためにこれは人であるということがわかる人の学習モデルを作成しました。その学習モデルを利用し、画面内に人がどこにいるかというチェックに利用しました。

・Shader
厳密にはShaderの中のFragment Shader(Pixel Shader)という技術を利用して検知している人の画面上のピクセルを操作してPixelate表現(モザイクみたいなやつ)を実現しています。(ややこしいですね)

アプリに関して
作成期間
・ 2019/3/1〜2019/3/31(帰宅してから実装していたので、実質10日ほど)

開発環境
・MacBook Pro (15-inch, 2017) Radeon Pro 560
macOS 10.14.2
・Xcode : 10.1 (10B61)
・Swift : 4.2.1

Framework
UIKit、AVFoundation、SpriteKit、Vision、CoreML

仕様
1.カメラから動画を撮影できること。
2.撮影した動画から物体を検知すること。(機械学習で判定する)
3.検知した物体にFragmentShaderをかける

実装に関して
1.カメラから動画を撮影できること。
→これに関してはAVFoundationを利用して動画を撮影する機能を作成します。これはググれば出てくるので割愛します。

2.撮影した動画から物体を検知すること。(機械学習で判定する)

機械学習をするためのフローは以下の通りです。
データセットを用意する(INRIA Person Datasetというものを利用しました)

データセットから学習モデルを作成する

作成した学習モデルをiOSのCoreMLから利用できるように実装する

撮影した動画(厳密には1frameの画像)をCoreMLのAPIを使用して渡し、どこに物体があるか検知する

APIの結果を利用して矩形表示する。

データセットから学習モデルを作成する
Pythonの開発環境を作成し、そこでAppleのTuriCreateというライブラリを利用してデータセットから学習モデルを作成します。
(使い方はTuriCreateのReadmeを参照)

学習モデルを作成するための環境
Anaconda(Jupiter Notebook)
・Python 3.6.5
Turi Create(Appleのライブラリ)

今回この構成で学習モデルを作成する際にハマったこと

多分当時作成していた環境(macOS 10.14.2、MacBook Pro (15-inch, 2017) Radeon Pro 560)で実施すると以下のようなエラーが出て学習せず止まります。

/BuildRoot/Library/Caches/com.apple.xbs/Sources/MetalPerformanceShaders/MetalPerformanceShaders-121.1.1/MPSCore/Utility/MPSLibrary.mm:218: failed assertion `MPSKernel MTLComputePipelineStateCache unable to load function cnnConv_Update_32x64.
Compiler encountered an internal error: (null)

RadeonのGPUが搭載されてるせいかそれを利用しようとしてどうやらエラーになるようでした。なので以下の通りにgpuを使用しない設定して作成したところうまくいきました。

tc.config.set_num_gpus(0)

学習するのに12時間かかりました.........

(まだ試してませんが最新のmacOSに上げたらもしかしたら動くかもしれないです。)

作成すると以下のような学習モデルができます。

上記で作成した学習モデルを活用し、撮影した動画(厳密には1frameの画像)をCoreMLのAPIを使用して渡し、どこに物体があるか検知するとこんな感じになります。最初はサンプルとして車を検知するアプリを作成しました。(車のデータセットはここから)

ここまでできるとあとは人の学習モデルを同様に作成するだけで人を認識するアプリが作成できます。(細かい実装は割愛します。あとで別で記事にするかも。)

3.検知した物体にFragmentShaderをかける
今回Shaderに関してはSpriteKitを利用しました。
理由
・SpriteKitの実装に慣れていたから。(昔簡単なゲーム作成していた)
・個人的にはMetalより工数はかからない。(コンペ締め切りまで時間なかった)
・SpriteKitのShaderを作成するのに慣れていた。
・ShaderをCropするのにSpriteKitが簡単だった。(CropNodeというものがある)

コンペ向けにまずはPixelateのFragmentShaderを作成

作成するとこんな感じのものができます。
ただ、このShaderを人にあてると犯人っぽくなるのでちょっと色をつけてアートっぽくしたいなと思いました。

FragmentShaderにFragmentShaderをかける
そこで、上記のままだと犯人っぽくなるので以下のように実装するとShaderの結果に対してさらにShaderをかけられるようになります。
今回は画像を3色で分けるShaderとPixelateするShaderをかけ合わせました。

// 一度Shaderをかける
let shader = SKShader(fileNamed: "3color.fsh")  // 三色にするShader
bgNode.shader = shader
bgNode.texture = texture

// ShaderをかけたNodeからtextureを取得し自身のtextureに上書き
let 3colorTexture = view?.texture(from: bgNode)
bgNode.texture = 3colorTexture

// 上書きされたNodeに対してさらにShaderをかける
let pixShader = SKShader(fileNamed: "pixelation.fsh") // PixelateするShader
bgNode.shader = pixShaderr

するとこんな感じになります。
これでMachine Learningで人を検知したところにPixel表現をするアプリの完成です。

まとめ
細かい実装に関してはだいぶ省いてますが、Machine Learningも使い方によってはちょっと面白い使い方ができるかと思います。
また今回はMachine Learningの物体検知にだけ絞っているので画像の分類やテキストの分類など他にも様々な機能があるのでMachine Learningを知ることで実装の幅をもしかしたらさらに広がるかもしれません。
興味を持った方は使ってみてはいかがでしょうか。

#programming #note #プログラミング #shibuyapixelart2019 #pixelart #machinelearning #fragmentshader #objectdetection #yolo #realtimerendering #turicreate #python #ios #coreml #vision #spritekit #art #mediaart #newmediaart #shibuya #ai  

いいなと思ったら応援しよう!