頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


TensorFlowで画像の水増し時のパラーメタの検討方法

TensorFlowで学習時に画像を水増しする、というおなじみの手法。

画像の水増し方法をTensorFlowのコードから学ぶ - Qiita
TensorFlowを使った画像の水増しレシピまとめ
↑このあたりを見るとどのパラメータをいじるとどういう風に画像が変わるか、というのがざっとわかる。

自分がデータセットに使おうとするpng画像があるとして、それを水増し用処理した画像を表示するコードを紹介。
import tensorflow as tf
import numpy as np
from PIL import Image


def img_show(img) :
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()


srcImg = Image.open(“lena.png")
img_show(srcImg)

if srcImg.mode == 'RGBA' :
# srcが4chの場合3chにする — (1)
rgbImg = Image.new('RGB', srcImg.size, (255, 255, 255))
rgbImg.paste(srcImg, mask=srcImg.split()[3])

elif srcImg.mode == 'RGB' :
rgbImg = srcImg

npArray = np.asarray(rgbImg)/255.0


with tf.Session() as sess :

tfImage = tf.convert_to_tensor(npArray, np.float32)


# いろいろな水増し処理
#tfImage = tf.image.adjust_brightness(tfImage, 0.4)
#tfImage = tf.image.adjust_contrast(tfImage, 1.4)
tfImage = tf.image.adjust_hue(tfImage, 0.25)
#tfImage = tf.image.adjust_saturation(tfImage, 2.0)


newNpArray = 255.0*tfImage.eval()
newNpArray = np.clip(newNpArray, 0, 255.0)
img_show(newNpArray)



(1)読み込んだ画像がアルファチャンネルを持っている場合に3chになるような処理をしている。というのもTensorFlowの水増し処理は3chでないとダメなのがあるため。

画像出力結果

↑実行すると別ウインドウで画像が表示される。


おまけ
保存して確認する場合は↓こんな感じで。
	saveImg = Image.fromarray(np.uint8(newNpArray))
saveImg.save(filePath)




TensorFlow 1.7.0-rc1
Python 3.5.2
macOS 10.14.6
スポンサーサイト






grayscaleのMTLTextureをCoreML/Visionの予測に渡す

機械学習の結果であるmlmodelファイルがあり、それをiOSアプリで使う場合。

Core ML+Visionを用いた物体認識の最小実装 - Qiita
↑通常このような流れでできると思うのだが、画像が白黒のMTLTextureだったので躓いた。

モデルへの入力が画像の場合、
let handler = VNImageRequestHandler(ciImage: ciImage, options: [:])
//let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
try! handler.perform([mlRequest])
↑このような感じで予測を実行するのでCIImageかCGImageが欲しい。

今回はMTLTextureがあるのでまずはそれを変換する必要がある。
let ciImageA = CIImage(mtlTexture: mtlTexture, options: nil)
↑MTLTextureをCIImageに変換するメソッドがあるので一撃。
これでモデルへ渡せる。
カラーだとこれでいいんだと思う。

今回のケースはこのMTLTextureがgrayscaleの白黒画像だった。pixelFormatは .r8Unorm だと確認できる。
これを使いモデルで予測させると全然期待してない結果を出す。警告などもない。
これがモデル自体の性能なのか?モデル作り直すかなと思っていたのだが、よくよく調べると白黒画像に起因するものだった。

結果から言うと上記のCIImageで色空間(color space)を設定していなかったことが原因だった。
let option = [ CIImageOption.colorSpace: CGColorSpaceCreateDeviceGray() ]
let ciImageB = CIImage(mtlTexture: mtlTexture, options: option)
↑このようにcolor spaceを設定しておけば意図通りの予測結果が出てきた。

画像で表示した結果

↑一番上が元の白黒画像。
imageAは上記ciImageAを
let uiImageA = UIImage(ciImage: ciImageA!)
このようにUIImageオブジェクトにして表示したもの。そもそもがRGBの色空間に赤の1チャンネルだけのデータがあるから赤っぽくなるんだろう。
imageBは上記のオプションで色空間を指定した場合。ちゃんと色空間を設定した白黒画像は赤っぽく表示されることはないんだな、、、覚えておかねば!

なお、imageA,BともciImage作成時に上下反転させているが略。


tfcoremlを使ってTensorFlowの学習結果をiOS/macOSアプリで使う

機械学習の結果をiOS/macOSアプリで使おうとするといくつか方法はある。

CreateMLで学習させると結果をmlmodelファイルで得ることができ、これをiOS/macOSアプリではCoreML+Visionで簡単に使うことができる。
この方法が一番簡単だと思うが自分の場合ではCreateMLだと学習が進まなかったこともあり断念。

TensorFlow、もしくはKeras(バックエンドはTensorFlow)での学習結果を使う場合にはiOS/macOSアプリでweightやbiasのデータを読み込んでMetalPerformanceShadersを使ったことはあった。今回もそうしようと思ったのだが、、、MPSCNNConvolutionのイニシャライザ
init(device:convolutionDescriptor:kernelWeights:biasTerms:flags:)
が deprecated in iOS 11.0 と出てしまう。そらあかん。
ということで今回は、、、

TensorFlowで作ったモデルをCore MLで利用する - Qiita
↑こちらの記事を参考にTensorFlowで学習、pbファイルを出力し、それをtfcoremlを使ってmlmodelに変換してiOS/macOSアプリで使ってみることにした。その時に躓いたところをメモしておく。


1)tfcoremlのインストール
tfcoreml · PyPI
↑本家tfcoremlのサイト。現時点で0.3.0が最新か。betaもあるみたいだけどおっかないので
pip install -U tfcoreml
で0.3.0をインストール。ちなみにPythonは3.5.2、TensorFlowは1.7.0-rc1。


2)TensorFlowでのモデル作成
#    x = tf.placeholder(tf.float32, [None, HEIGHT*WIDTH], name = 'x')
x = tf.placeholder(tf.float32, [None, HEIGHT, WIDTH, 1], name = 'x')
↑入力がHEIGHT*WIDTHになっていた(MNISTの例題などではこうなってるのでその流れでこうなってた)ので区切って画像形式にしたここではカラーではなくグレースケールなので1にしてる。
pbファイルとして出力するところは略。


3)tfcoremlで変換
classLabels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

tf_converter.convert(tf_model_path = PbFilePath,
mlmodel_path = MlmodelFilePath,
output_feature_names = ['y_conv:0'],
input_name_shape_dict = {'x:0':[1, Height, Width, 1]},
image_input_names = ['x:0'], # — (1)
class_labels = classLabels, # —(2)
image_scale = 1.0/255.0 # —(3)
)
↑肝心の変換部分はこんな感じ。
(1)image_input_namesは上記参考記事の通り。画像形式にしておくとiOS/macOSアプリで使う時にもラク。
(2)softmaxを使う画像分類なのだがclass_labelsを設定しないと結果を見てもよくわかんない、となるのでラベルの設定が必要だった。
(3)自分のモデルには必要だった。0から1の値で学習させていたんだわ。

変換処理をすると
[espresso] [Espresso::handle_ex_] exception=Unsupported engine type
[espresso] [Espresso::handle_ex_] exception=Espresso exception: "Device not found": Can't find metal device

といった警告が表示される。

macOSアプリでもmlmodelロード時(?)にも同じものが表示されたが、意図通りに予測できていた。
Core ML+Visionを用いた物体認識の最小実装 - Qiita
↑iOS/macOSアプリでmlmodelを使うのはこのあたりを参考に。

予測の実行結果
↑macOSアプリでの予測結果。あってるよ〜!
助かった!ありがとう、tfcoreml!


iPhone故障で確認コード受信できずApple IDでサインインできない!

妻のiPhone 7 Plusの調子が悪くなった。ディスプレイ右側に太い縦線が2本入りタッチによる操作もうまくできないことが多い。
ソフト的な原因かもということで再起動、および強制的な再起動をするも効果なし。
次に工場出荷状態に戻して(つまりリセット)iCloudにあるバックアップから復元させようとした。
リセットはできたのだが、最新のiOSをダウンロードしてから、とのことで夜間にダウンロード。
翌朝、無事ダウンロード終了して復元作業をしようとしたが、

故障したiPhone 7 Plus

↑縦線以外にも何やらおかしくなっており、もはやディスプレイが入力をほとんど受け付けず、さわってもないのにキー入力しているような状態になってしまってた。もうAppleに修理に出すしかないと決断した。

修理に出している間、携帯がないのも不便ということで使っていなかったiPhone 5sを代わりに使おうとしたのだが、、、
5sを妻のiCloudにあるバックアップから復元させる手順の途中で、Apple IDが2ファクター認証になってるので確認コード入力を求められる。
本来なら確認コードは妻のiPhone 7 Plusに送信されている。
しかしすでに壊れてリセットまでしているので当然受信することはできない。

Apple ID を使って 2 ステップ確認でサインインできない場合 - Apple サポート

↑サポートページの説明には
Apple ID で 2 ステップ確認をお使いの場合、サインインの際に下記のうち 2 つ以上が必要となります。
・Apple ID のパスワード
・信頼できるデバイス
・復旧キー

↑このような記述が。
パスワードはあるんだが、妻にとって「信頼できるデバイス」は壊れた7 Plus以外にはない。復旧キーなんて聞いたこともないとのこと。
つまり、3つのうちパスワード1つしか持っていない、、、詰んだ、、、?
知らんかったわ、、、これ、7 Plusを修理したとしても、前のアカウントにはアクセスできないってことじゃ?
うかつにリセットせずに修理してればなんとかなったのかもしれなかった。あああ、やってもうた、、、旅行の写真があぁ、、、


と思ってたんだが、確認コードをメッセージではなく電話番号でも受信できそうだったので、試しに、7 Plusのsimを息子のiPhone 6に差してみたところ、6で確認コードを受信することができた!
ということで無事5sは復元に成功し妻の代替機となり、7 PlusはAppleに修理に出した。見積額は税込42,984円、、、痛いっ!


なお、壊れたiPhone 7 Plusも6も5sも全てsimフリー機、simのサイズは同じ。


ARKitの画像トラッキングにおける画像平面の初期姿勢

ARKitの画像トラッキング(ARImageTrackingConfigurationを使うやつね)で対象の画像を見つけた場合に得られるARAnchorオブジェクト。それをanchorとするとanchor.transformでその位置・姿勢を得ることができる。

これをつかってごにょごにょ(※1)する時なんかにあれ?と思ったのはこのtransformがmatrix_identity_float4x4の状態にはこの平面はx-z平面にある、ということ。
x-y平面にあるものと思ってコード書いててなんかうまくいかねえ?となり気付いたんだが。
ちなみにMDLMeshのnewPlane(withDimensions:segments:geometryType:allocator:)で作成する平面はx-y平面に作成される。うー、なんかややこしいのう。


※1 ↓こういうのをやってたのです。





Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.