頭と尻尾はくれてやる!

iOSアプリなどの開発日記です


SceneKitでオブジェクト表面に背景画像を表示する

タイトルだけだとよくわからないよな、やっぱり。

トーラスの表面に背景を描画

↑そもそもはこのようにオブジェクトを輪郭線だけ描いてるような表現をしたいのです。

SceneKitでは背景の設定はこれでOK↓
{
    scene.background.contents = @“kabegami.jpg";
}
sceneはSCNSceneオブジェクト。

トーラス

↑ここにトーラス(SCNTorusで作成)を描くとこんな感じ。

↓単にオブジェクトを透過にすると、、、
{
//    node.geometry.firstMaterial.transparency = 0.5;
    node.opacity = 0.5;
}
トーラスを透過1

↑どちらの方法でも全体が透過してしまうし、隠れてほしい向こう側が透けてしまっている(赤い矢印部分)。

↓シェーダで透過が有効になるようにして、
{
    program.opaque = NO;
}
フラグメントシェーダ内で法線との内積から輪郭に近いとこは黒、そうでないところは透過させる(アルファ値ゼロ)にしてやると、、、

トーラスを透過2

↑さっきと同じで、自分も透過して見えて欲しくない向こう側が見えてしまう。

結局フラグメントシェーダに背景画像を渡してやって、表示する座標からテクスチャ上の座標を得て背景画像を描画するようにした。オブジェクトを透過させてるのではなく背景画像を貼り付けてる。
シェーダはこんな感じで↓
{

    if (n_dot_l <= LowLimitDot) {
        float2 backTexCoords = float2( in.aPosition.x / in.aPosition.w , in.aPosition.y / in.aPosition.w);
        //backTexCoords =float2(backTexCoords.x*0.5+0.5 , backTexCoords.y*0.5+0.5);//iOS
        backTexCoords =float2(backTexCoords.x*0.5+0.5 , -backTexCoords.y*0.5+0.5);//macOS
        
        color = backTexture.sample(sampler2d, backTexCoords);
    } else {
        color = float4(float3(0),1.0);//outline
    }

    return half4(color);
}
↑表示する点の座標を-1〜1 → 0〜1に変換してテクスチャ座標を得ている。
macOSの場合だとiOSと上下逆になるっぽい。
輪郭線は単に黒で表示してる。

トーラスの表面に背景を描画

↑やっと意図するのになった!(一番最初の画像と同じのだけど)😄



↑ちょっと動かしてみた場合。正しく背景を表示していることが確認できる。


壁紙素材はこちらからお借りしました↓
タイル調の壁紙クロス|ぱくたそフリー素材


追記
↓カエルに適用するとこんな感じ
スポンサーサイト






macOSで画像の輝度データを得る

機械学習のMNISTをmacOSのMetal Performance Shader使ってやろうとしているのだけど、png画像からデータを取り出すのに苦労した。

28x28サイズの画像

↑MNISTで使われる28x28でアルファチャンネルのないpng画像。
ここから輝度を28x28個取り出したい。

最初、iOSで使ってたコードを持ってきてUIImageをNSImageに書き換えるなどしたら警告もなくなったので動かしてみたもののちゃんと動かず、よくよく調べると画像からデータが全く取得できていなかった。
{
     [imageView.layer renderInContext:context];
}
↑iOSの場合だとこのようにしてたが、、、
cocoa - Get pixels and colours from NSImage - Stack Overflow
↑こちらによると、NSGraphicsContextでラップするとええよ、とあるので参考にして書き換えた。
それがこんな感じ↓
{
    NSImage *image = [NSImage imageNamed:@"0002.png"];

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGImageAlphaInfo bitmapInfo = kCGImageAlphaNone;
    
    CGContextRef context = CGBitmapContextCreate(nil, 28,28, 8, 28,
                                                 colorSpace,
                                                 bitmapInfo);

    NSRect imageRect = NSMakeRect(0, 0, 28,28);
    NSGraphicsContext *gctx = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO];
    [NSGraphicsContext setCurrentContext:gctx];
    [image drawInRect:imageRect];

    void *data = CGBitmapContextGetData (context);



    [srcImage.texture replaceRegion:srcImageRegion
                                  mipmapLevel:0
                                        slice:0
                                    withBytes:data
                                  bytesPerRow:28
                                bytesPerImage:0];
}
srcImageはMPSImageオブジェクト。最後のメソッドでデータをMPSImageに書き込んでる。


dataの中身を直接覗いて確認する↓
{
    unsigned char *lumi = (unsigned char *)data;
    for(NSUInteger y=0;y<28;y++) {
        NSString *line = @"";
        for (NSUInteger x=0;x<28;x++) {
            NSUInteger ite= 28*y+x;
            line = [line stringByAppendingFormat:@"%d ",lumi[ite]];
            //NSString *str = (lumi[ite] > 1) ? @"1" : @"0";
            //line = [line stringByAppendingFormat:@"%@",str];
        }
        NSLog(@"%@",line);
    }
}
輝度を表示

↑dataの中身をそのまま表示(右端は少しカットしてる)。

輝度を整列して表示

↑1と0で見やすくした場合。
下はNNで予測した結果(2であろうという確率が一番高くなってる)。


KerasでCNNを使ったMNIST

KerasでCNNを使おうと思うのでまずはお決まりのMNISTやってみた。

KerasをMacにインストール
↑前に全結合層でやってみたのでCNNを使うように修正するだけ。
なお、深い意味はないけどSequentialモデルではなくModelクラス(functional API)を使ってる。
(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.reshape(60000, 28,28,1)
x_test = x_test.reshape(10000, 28,28,1)
#略

#モデルの作成
x = Input(shape=(28,28,1,))
layer1 = Conv2D(32, (5,5), padding='same', activation='relu')(x)
layer2 = MaxPooling2D(pool_size=(2, 2), padding='same')(layer1)
layer3 = Conv2D(64, (5,5), padding='same', activation='relu')(layer2)
layer4 = MaxPooling2D(pool_size=(2, 2), padding='same')(layer3)
layer5 = Flatten()(layer4)
layer6 = Dense(1024, activation='relu')(layer5)
layer7 = Dropout(0.2)(layer6)
y_pred = Dense(10, activation='softmax')(layer7)

model = Model( inputs=x , outputs=y_pred)
model.compile(loss='categorical_crossentropy',
              optimizer=Adam(),
              metrics=['accuracy'])
最初の方でデータの次元を合わせるってことで28x28x1にreshapeしてる。
層の構成はTensorFlowの例題と合わせたつもり。

Deep MNISTのネットワーク構成のサマリー

↑サマリー。Kerasが出してくれるこのサマリーはホントいい勉強になるわ。

学習結果

↑数エポック学習後。テストデータに対して99.03%とのこと。


ここまで書いてたんだけど、、、
係数をMetal Performance Shaderで使うために保存しようとしたら上のコードだと保存できない(?)ようで、結局下のようなSequentialモデルに書き直しました。😝
model = Sequential()
layer1 = Conv2D(32, (5,5), padding='same', activation='relu' , input_shape=(28,28,1,) )
layer2 = MaxPooling2D(pool_size=(2, 2), padding='same')
layer3 = Conv2D(64, (5,5), padding='same', activation='relu')
layer4 = MaxPooling2D(pool_size=(2, 2), padding='same')
layer5 = Flatten()
layer6 = Dense(1024, activation='relu')
layer7 = Dropout(0.2)
y_pred = Dense(10, activation='softmax')

model.add(layer1)
model.add(layer2)
model.add(layer3)
model.add(layer4)
model.add(layer5)
model.add(layer6)
model.add(layer7)
model.add(y_pred)
model.compile(loss='categorical_crossentropy',
              optimizer=Adam(),
              metrics=['accuracy'])



貝塚市の渓流園地にBBQへ行ってきた

先日大阪南部にある貝塚市の山奥にある渓流園地というところへBBQに行ってきた。
思い付いたことを書いていくと、、、

・手作りっぽい長椅子があるので持参した椅子は使わなかった
・各エリアにはブルーシートが張られてたので持参したサンシェード(小さいテント)も使わなかった
・炊事場はなし
・ゴミや炭を捨てるところはない(ゴミ袋、炭入れ缶はいつも持ってた)
・トイレはある(水洗、和式)
・携帯が圏外
・川で遊べるのでサンダル、着替え、網など持って行くとよい
・小さい魚、カニ、巻貝を捕まえた
・蜂が多かった(同行者によるとスズメバチらしい)
・駐車場は2カ所あった
・駐車場からの道は舗装されてないので遠いと台車でも大変かも
・駐車料金500円、入園料大人400円、子供200円

渓流園地

↑BBQサイト横を撮影


何年もだめだったradiko.jpが復活してた

最近気が付いたんだけど、iPhoneの4G回線でradiko.jpが再び聞けるようになってた。

以前は普通にiPhoneのradikoアプリは外でも使えていた。
ところが、(記憶に間違いがなければ)あのタイムフリー機能を追加した大幅リニューアル以降、外では使えなくなった。一度取得した数十秒の内容を繰り返すばかり(ただしWi-Fiだと問題なし)。

もっともアプリの問題かiOSの問題か使っている回線(いわゆる格安SIMだし)の問題かよくわからなかった。

いつの間にか外ではradikoを使わなくなり何年か経っていたんだけど、先日何気なく起動してみたら、、、ちゃんと聞けるやん!
何やったんやろ?




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