頭と尻尾はくれてやる!

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


macOSでSCNView→png画像を作成、保存する

SCNViewの表示内容からpng画像を作って保存したかったんだ。なおNSSavePanelは使わない。
散々回り道したけど、こんな感じ。

{
    //(1)
    NSImage *image = [sceneView snapshot];
	
    //(2)
    NSData *imageData = [image TIFFRepresentation];
    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
    NSDictionary *imageProps = [NSDictionary dictionary];
    imageData = [imageRep representationUsingType:NSPNGFileType properties:imageProps];

    //(3)
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *url =[fm homeDirectoryForCurrentUser];
    NSString *path = [url path];
    NSString *pathStr = [path stringByAppendingPathComponent: @"images/screenshot.png"];

    //(4)
    NSError *error = nil;
    if (![imageData writeToFile:pathToDesktop options:NSAtomicWrite error:&error]) {
        NSLog(@"%@",error);
    }
}
(1)まずNSImageオブジェクトを作る。snapshotで一撃。
(2)NSImageオブジェクトからNSDataオブジェクトを作る。調べるといろんなやり方があるみたい。propertiesに渡すのもなくてもいけそう(でもnilだと警告が出る)。
(3)保存先、ファイル名を指定。imagesってフォルダーを作ってそこに入れてる。
(4)保存。ダメならエラー表示。

sandbox設定
↑XcodeのTarget設定のところのApp SandboxをONにしてる場合、保存先が限られてデスクトップなどには保存できない。
{
    NSString *pathToDesktop = [NSString stringWithFormat:@"/Users/%@/Desktop/screenshot.png", NSUserName()];
}
↑保存先にデスクトップを指定すると

Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “screenshot.png” in the folder “Desktop”.

なんてエラーになる。ただしサンドボックスをOFFにしておけばデスクトップにも保存できた。なおNSSavePanelを使えばサンドボックスON/OFF関係なくどこでも保存できるみたい。

macOSのサンドボックスについてもっと勉強せねば。


サイズの合わない窓用エアコンを取り付けた

ウチの小さい部屋には外に室外機を置くスペースはもちろんそれ用の配管を通す穴もない。つまり元々エアコンを設置できるようには設計されていないんだけど、どうしても設置したくてコロナの窓用エアコンを検討してた。ヒーターを別途置くスペースもないしヒートポンプの方が電気代も安いよなってことで冷暖兼用が欲しい。

ウインドエアコンの取り付け方|ウインドエアコンシリーズ|空調・家電機器|製品情報|コロナ

↑設置に必要な幅として495mm以上とある(冷房専用なら470)。しかし、ウチの窓のサイズを確認すると445mmくらいしかない!
あかんやん、、、と最初はあきらめていたのだけどよくよく調べると実機(CWH-A1817)の横幅は360mmになってる。設置用の枠のサイズはどこを見ても書いてないんだが、実機よりちょっと大きいくらいに見える。まさか窓ストッパーを倒さないと電源が入らない、とかなってないよな?だったら取付枠さえ窓にセットできればなんとかなるんじゃないの?ということでえいや!と注文してみた。だめなら最悪DIYでエアコン設置台兼本棚みたいなのを作るつもりでいた。



窓用エアコン

↑届いたエアコンと設置するところの窓。
取付枠の横幅を測ってみると390mm程度だ。いけるかも?!

取付枠設置後

↑かろうじて取付枠が設置できた!窓ストッパーは最初からあきらめてる。
なお、元々窓のレール(?)部分に衝突防止用部品みたいなのがあってそれがためにうまく取付枠を設置できなかったので、それを強引に取り外してようやく取付枠の設置ができた。

ドレン

↑あせったのがドレン用の部品とかがあったことだ。え?不要だったんじゃないの?と思いサイトを再確認したらそれは冷房専用機であって冷暖兼用機にはドレン工事が必要とあるのだ。あちゃー、やってしもうた、、、と焦ったんだが別に画像の状態でもいいんじゃね?ってことで配管などは設置せず。

設置完了

↑無事に設置完了。試運転したらちゃんと動いたよ。でもこれ使用時には当然窓を開けておく必要があるわけだが、うっかり忘れてしまいそうな気がする。そういう気がするって場合はたいていやってしまうもんだ。取説によると室外側の吸い込み温度が高温になると停止するみたいだけど。

作業時間は2時間ちょいかな。設置に必要な条件を満たしていない方法なので自己責任で。
これでこの部屋でも快適にすごせる。ありがとう、コロナさん!
謎なのは吹出口のルーバーをどう向けようがエアフィルターが引っかかって取り出せないんだけど?


macOSアプリでSave Asができない

最近、macOSアプリ(リリース目的ではなく自分専用だけど)を作ろうかなと勉強してる。

ざっと調べるとドキュメント・ベース・アプリケーションなるものがあって、それでエディターっぽいのを作るのがHello Worldみたいなもんらしい。知らんけど。

プロジェクトでDoc Base Appにチェック

↑プロジェクトの新規作成時に Create Document-Based Application にチェックすれば必要なクラスのサブクラスとか用意してくれる。

storyboardのviewに Text View を貼り付けてやる。
Documentクラス(NSDocumentのサブクラス、Xcodeが作ってくれてる)にすでにある以下のメソッドに必要な処理を書けば、ファイルの読み込み、保存ができる。

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError;
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError;


ところが、どういうわけか Save as ができない。

storyboardではSave As

↑storyboard上だとSave Asになってるのに、

実行時はDuplicate

↑実行時にはDuplicateになってる。



なんぞや?と調べた結果、アプリのTarget設定のCapabilitiesってところにApp SandboxってのがあってここのFile accessがデフォでRead Onlyになってる。

Read Onlyを変更する

ここをRead/Writeに変えたら期待通りDuplicateじゃなくSave Asになり、処理もできるようになった。そういうことだったのね、、、



macOS Sierra 10.12.6(ええ、まだSierraですねん)
Xcode 9.0.1


Depth APIで部屋の奥の方を消してみた

iOS 11で公開された深度に絡むAPI、いわゆるDepth APIで遊んでみた。

Capturing Depth in iPhone Photography - WWDC 2017 - Videos - Apple Developer
↑これね。

サンプルコードのAVCamPhotoFilterのシェーダー部分をいじって、遠い部分を黒く塗りつぶすようにして部屋を撮影したのがこちら。

↑デバイスはiPhone 7 Plus。
なかなかしんどいですねえ、、、相当負荷が高い処理なんだろうな。

Supported Depth Resolutions for Streaming

↑上記のWWDCの動画内でこのようにリアルタイム(ストリーミング)だと320x180@24 fpsのデータが得られるとか(画像クリックで拡大)。案外小さいデータなんだな、とか思ってたんだが、、、それだけ処理が大変ってことか。

Depth APIとARKit使えば近くの人物などはそのまま表示し、周りの背景を描画したものに差し替えるような動画ができるんじゃね?とか思ってたけどこの様子じゃそれどころじゃなさそう。


機械学習におけるデータの範囲(2)

機械学習におけるデータの範囲
↑の続き。データの範囲はどうしても0から1じゃないとダメなのか問題。オチもよくわからないってことなんだがやったこと書いとく。

簡単化するためMNISTで同じようなことをやって確認してみた。ちなみに畳み込みのある方のMNIST。
これも自分でtfrecord形式のデータを作成してて、読み込む時は画像データ(輝度)の値を
tf.uint8
で得ている。8ビットの符号なし整数だから0から255。
image = tf.cast(image, tf.float32)
image /= 255.0
という感じでfloatにキャストしといてから255で割って、0から1.0になるようにしてる。当然これはちゃんと学習が進む。

輝度の確認

↑元画像はこんなので明るい部分はをチェックすると0.99近い。
なのでさっきのを
image /= 128.0 # 255.0
って書き換えたら0から2.0くらいになる。
試しにこれでやってみると、、、ちゃんと学習が進んだ!
image /= 85.0
これだと0から3.0くらいなんだが、、、学習が進むことも落ちることもあった。
データファイルの順番、バッチ作成時にランダムになるようにしてるから毎回同じってわけでは決してないので、たまたまいけることもあればたまたまダメなこともあるってことで、そこはええねん。

落ちる時のエラーメッセージにはこんなのが。
Nan in summary histogram for: conv2/weights_0

これってTensorBoardで必要なデータを出力する時の話?と思ってその辺りを消して実行すると、落ちずに処理は進むんだけど、cross entropyがずっとNanのままだった。
損失関数が発散するような場合には学習率を変えればうまくいったことがあったが、今回は全然効果なし。

ちなみに
(1)image /= 255.0(0から1.0)の場合
(2)image /= 85.0(0から3.0)で処理ができた場合
それぞれでTensorBoardのDistibutionを比較するとweight,biasの分布はさほど変わらずだけど、初期の勾配が大きくなっている。

TensorBoardによる係数の分布1

↑こちらは(1)の方。

TensorBoardによる係数の分布2

↑こちらは(2)の方。

けどこの程度で問題になるんかな?
数学的には別に0から1じゃなくてもいけるんだけど、コンピュータの処理上でどこかでオーバーフローでもやってるんだろうか?




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

FC2Ad