FC2ブログ

頭と尻尾はくれてやる!

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


NSImageから白黒画像のデータが欲しい(1)

macOSでSCNViewのスクショをコードで得る
↑これの続き。
繰り返し書くけど、機械学習(CNN)で使うので白黒画像が欲しい。
なので上の記事のようにsnapshotでNSImageオブジェクトを得て、それを白黒化したNSImageを得ればいいな、と思って調べたところ、下のような記事があったので試してみた。

カラー画像のモノクロ化で苦戦中 | Unlimited

-(NSImage *)grayishImage:(NSImage *)image
{
    NSData *tiffData = [image TIFFRepresentation];
    NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:tiffData];
    
    CIImage *inputImage = [[CIImage alloc] initWithBitmapImageRep:bitmap];
    CIColor *ciColor = [[CIColor alloc] initWithColor:[NSColor whiteColor]];
    NSNumber *nsIntensity = @1.0f;
    
    CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome" keysAndValues:@"inputImage", inputImage, @"inputColor", ciColor, @"inputIntensity", nsIntensity, nil];
    CIImage *outputImage = [filter valueForKey:@"outputImage"];
    NSBitmapImageRep *outBitmap = [[NSBitmapImageRep alloc] initWithCIImage:outputImage];
    
    NSImage *outImage = [[NSImage alloc] initWithData:[outBitmap TIFFRepresentation]];
    
    return outImage;
}
↑コードはこんな感じ。

スクリーンショットを白黒画像にしたところ

↑確かに白黒にはなった(前記事と同じくSceneKitのSCNViewオブジェクトのスクショをsnapshotで撮影し、半分のサイズで重ねて表示してるところ)。

ところが、だ。

この方法で得たNSImageオブジェクトのcolor spaceを調べる(※)と
kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1
などと出てくる。おい、RGBの値を持ってるのか?

MNISTの白黒画像

↑ちなみにMNISTで使う白黒画像を同じように確認すると
kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; Generic Gray Gamma 2.2 Profile
と表示される。

あー、やっぱりさっきのは白黒に見えてるけどデータとしてはRGBの値を持ってるのか、、、
機械学習で使う場合、これではまずい。
ということで続く。


(※)NSImageオブジェクトのcolor spaceを調べる。
{
    CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)[image TIFFRepresentation], NULL);
    CGImageRef cgImage =  CGImageSourceCreateImageAtIndex(source, 0, NULL);
    NSLog(@"colorSpace=%@",CGImageGetColorSpace(cgImage));
}



version memo
macOS High Sierra 10.13.6





奥河内くろまろの郷で自転車借りてサイクリングしてきた

奥河内サイクリングのガイドマップの写真

↑事の始まりはこういうガイドマップの冊子をどこぞでもらったこと。
冊子には大阪南部の河内長野市にある道の駅「くろまろの郷」で自転車をレンタルできるとあり、家からそれほど遠くもなく、それじゃあ家族で行ってサイクリングしてみるか、ということになった。

奥河内くろまろの郷
↑こちらが公式サイト。

当日は道の駅でクロスバイクをレンタル(予約してた)し、出発。

奥河内サイクリングのガイドマップのおすすめコースの画像

↑コースは冊子にあるおすすめコースを参考にし、「汗かき度」の一番低い二つのコースを合わせ、
くろまろの郷→天野酒→観心寺→歩絵夢(昼食)→千早口→美加の台(廃線跡)→戻る
という感じで行ってみた。

走行コース記録のスクリーンショット

↑当日の走行した記録(runtastic road bikeというアプリ)。21.1kmでした。
赤い点がくろまろの郷。当然ここからスタートしたけど記録開始するのを忘れてて緑の点から記録してる。

検討してる方のために思ったことを書いとく。

(1)電動じゃないクロスバイクは1日1,000円。
(2)レンタルにヘルメットは含まれているけどグローブはない。息子が途中から手のひらが痛いと言い出したので私のグローブを使ってしのいでたくらいなので、用意しておくといいかも。
(3)「汗かき度」が一番低いから平坦な道ばかりと思ってると泣きをみる。アップダウンの連続だ。
(4)冊子のルートラボというサービスが役に立った。QRコードを使うとルートと自分の位置がブラウザでわかるというものだけど、これがなければ廃線跡へは行けなかったと思う。ただし、「観心寺・延命寺コース」はリンク切れになってて使えない(もったいない!)。
(5)トンネルもあるので後ろがちかちかするようなライトを用意しておけばよかった。
(6)くろまろの郷にシャワー室はない。シャワーでスッキリして帰りたかった。


普段一人で黙々と走ってるのとは違って、こういうのんびりサイクリングは超絶楽しかったよ。


macOSでSCNViewのスクショをコードで得る

macOSでSceneKitで描いた画面(SCNView)のスクリーンショットが欲しい。
機械学習(CNN)で使うので一定時間ごとに白黒画像をコードで得たい。

まずはカラーでもいいからスクショを得るところから。
- (UIView *)resizableSnapshotViewFromRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates withCapInsets:(UIEdgeInsets)capInsets;
↑iOSだとこんなメソッドを使っていた。そうそう、snapshotってのがいつからかできたんだ。

macOSではどうやるのか?と調べると、、、
{
    NSImage *image = sceneView.snapshot;
}
↑このようなシンプルな方法がある。
ここでsceneViewはSCNViewオブジェクト。
snapshotはSCNViewのプロパティなのでNSViewなどでは使えない。

SCNViewをsnapshotでスクショを得た結果の画像

↑snapshotで得たNSImageオブジェクトを半分のサイズにして表示した。
このsnapshotでもいいのだが、全画面も必要ないし画面の一部をNSRectとかで指定して得られないのか?とさらに調べたところ、、、
{
    NSImage *image = [[NSImage alloc] initWithData:[sceneView dataWithPDFInsideRect:rect]];
}
↑こういう方法があった。rectはNSRectでこれでビューの任意の場所、サイズでいけるやん!と思ったのだがこれはSCNViewには使えないっぽい。
‘PDF’以外にも似たようなメソッドがあるけど同じくダメだった。
NSViewのスクショを得た画像
↑NSView(※)に対しては動いたんだが。惜しい!
SCNViewはNSViewのサブクラスだけど、ダメなんだな。

結局、SCNViewからスクリーンショットを得るのはsnapshotでやることにした。


(※)
画像はNSViewにNSImageViewとNSTextFieldを置いたもので、任意の位置で切り出したスクリーンショットを得ている。


version memo
macOS High Sierra 10.13.6





Automatorとショートカットを使い文字数を数える

Macで文書作成時に文字数を計測したいと思い、調べたところAutomatorを使うとできそうなので設定した。
作業時の流れは、作成した文書のテキストを選択し、ショートカットで文字数が表示される、という感じ。
なのでAutomatorでサービスを作成し、ショートカットを設定する、という二つのことを行う。

Macで選択中のテキストの文字数をカウントするスクリプト【DL有り】 | くにぽん’ず☆きちめきパラダイス

↑こちらにあるコードを使用させていただいた。感謝、感謝!
ただAutomator初心者の私にはこの記事を読んでもすんなり設定できず異様に苦労した。なので、なるべくAutomatorに慣れていない人にもわかるように書いてみた。


(1) Automator起動

Automatorアプリのアイコン

↑このロボットみたいなアイコンのアプリ。Macにデフォで入ってるはず。

(2) 書類の種類を選択

書類選択画面

↑種類は「サービス」を選択する。
本目的ではワークフローでもアプリケーションでもない。拡張子は.workflowになるが気にしない。

(3) コードをコピペ

ワークフローを作成するには、ここにアクションまたはファイルをドラッグしてくださいというメッセージ

↑デフォだと「ワークフローを作成するには、ここにアクションまたはファイルをドラッグしてください。」なんて出てるがここでもがいてもダメ。
「ライブラリ」の中にある「ユーティリティ」を選択(クリック)し、その右側にある「AppleScriptを実行」をダブルクリックする(クリックじゃない)。

コード入力画面

↑撮影用に小さくしてるけどこんなコードを入力するような画面が出てくるはず。
デフォであるコードは削除して、上記リンク先にあるコードをコピペする。
ここで実行してもちゃんと動かないけど気にしない。

(4) 保存する

サービスの名前入力画面

↑⌘+s等で保存しようとすると「サービスの名前」を入力する画面が出るので好きなのを入力し、保存をクリックでOK。ここでは「文字数を数える」としてる。
保存先は聞かれない。macOSが良きに計らってくれる。

(5) ショートカットを設定する

ショートカット設定画面

↑システム環境設定 / キーボード / ショートカット / サービス
を見ると先ほど設定したサービスの名前があるので、そこで好みのショートカットを設定する。
ただ、簡単なのは他で使われていたりするので、自分の納得できるショートカットを設定しよう。
自分の場合は片手でいけるよう ⌘+control+shift+c とした。
実行結果画面
↑実行時の結果。別ウインドウで表示される。

(6) コードを変更する場合

二本指タップ時の画面

↑ショートカット設定のところでサービスの名前のところで右クリック(?私はトラックパッドなので二本指タップなんですが)すればこのように選択肢が出るので Automatorで開く を選択すれば再度編集ができるし、 Finderに表示 を選択すれば保存先がわかる。



バージョン情報
macOS High Sierra 10.13.6


NSTableViewにNSPopupButtonを置く

macOSでNSPopUpButtonとたわむれる
↑この続き。
上記の記事でNSPopupButtonを使ったがこれは言わば練習で、元々はこれをテーブルで使いたかった。

ところが、単純にstoryboradでNSTableViewのセルのところにNSPopupButtonを置いてもうまくいかない。
テーブルなので複数行のNSPopupButtonオブジェクトができた時にそれぞれのボタンが何を示しているかを得るのが難しい(※1)。
NSpopupButtonの参照を得ようとoutlet繋いでも複数はあかんってエラー出るし。


調べたところ、こういう記事が↓
cocoa - Pop up Button in view based NSTableView - Stack Overflow

このページにあるリンク先のpopTestプロジェクトをダウンロードして動かしてみると、、、

popTestスクショ

そうそう、こういう風にしたいのだよ!

ところが、このプロジェクトをよく見るとxibファイルに記述しててstoryboardを使っていない。

部品構成(xibファイルの場合)

↑xibファイルを選択するとこうなってるんだが、、、
ちょっ、、え?storyboardでやるのはどうすんの?なんか勝手が違うやん、、、?

結局、、、参考ページのプロジェクトと部品の構成を同じにてBindingsの設定をあーでもない、こーでもないと試行錯誤しまくったのだが、、、やっぱりダメ。

ようやく気付いたのが、Array Controller(NSArrayController)をstoryboard上で部品としてLibrary(※2)から追加できること(※3)。

LibraryでArray Controllerを選択

↑arrayとかで見つかるのでこれをドラッグ&ドロップ。

さらに追加したArray Controllerで
1. Connections inspector(※4)でoutletを接続
2. Bindings inspector(※5)のContent Arrayを設定

これで無事参考ページと同等のことができた。

これだとNSTableViewDataSource、NSTableViewDelegateのどちらもコードで設定してない。面白いなあ。

しかもこの方法でも、Connections inspectorでNSPopupButtonのactionを設定(コード内のメソッドへ接続)すれば、ボタンをクリック後にそのメソッドがコールされる。

なお、参考ページではdelegateに接続してるけど、

部品構成(storyboardの場合)

↑ファイル構成はこんな感じなのでViewControllerクラスに接続してる。




※1 苦し紛れの回避策
NSPopupButtonオブジェクトのsuperviewはセルを示すのであらかじめ
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
で各行のセルのポインタを得ておけばなんとかわかるのだが、、、そんなの強引すぎるよな。素直にバインドを勉強しようと思いました。


※2 Libraryとは
Storyboardで部品を選ぶ方法


※3 参考リンク
NSTableViewをCocoa Bindingsで使ってみた - takopomm’s diary


※4 Connections inspectorとは
Connections inspector
↑右から3つ目、丸の中に右矢印のあるやつ。


※5 Bindings inspectorとは
Bindings inspector
↑右から2つ目、ラーメン鉢の模様みたいなやつ。




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

FC2Ad