FC2ブログ

頭と尻尾はくれてやる!

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


macOSで保存したデータファイルからPythonで画像を作成する

NSImageから白黒画像のデータが欲しい(2)
↑この辺りの続き。
PythonのKerasとmacOSのSceneKitやMetal Performance Shaderを使い強化学習(CNNなので画像入力)をやりたい。

macOSアプリ側のSceneKitで描画するSCNViewのスクリーンショットを一定時間ごとに白黒画像データで取得。
全体の画像データとしてRGBの3チャンネル分のメモリを確保しておき、データを取得するごとに1チャンネル分ずらし最新のを最後のチャンネルに入れる。

macOSアプリで実行時のスクショ

↑するとこのような画像ができる(これはmacOSアプリ実行時のスクショ)。
3ステップ(時間)分の画像が1つの画像に入ってることになる。
元画像のいつもの宇宙船(?)は回転しているのでRGBそれぞれの画像は上図のようにずれて見える。
{
    unsigned char *wholeData;//全体のデータ


    NSData *data = [NSData dataWithBytes:wholeData length:(NofImageData*NofChannel*sizeof(unsigned char))];
    [data writeToFile:filePath atomically:YES];
}
↑macOSアプリ側の保存部分のコード。NSDataにしてからファイルに保存してる。
ここでNofImageDataは1チャンネル分のピクセル数、NofChannelはチャンネル数(今回は3)。

Finderで確認したファイルの容量

↑8ビット=1バイト、今回はサイズが200x200なので3x200x200 = 120,000バイトをバイナリで保存してる。計算通りだ。


次にPython側。
先ほど保存したデータファイルを読み込んで画像化してみる。
画像関連でPILライブラリを使う。
{
    from PIL import Image

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


    data = open(FilePath, "rb").read()

    size=(width, height)
    image = Image.new('RGB',size) #白黒は’L’

    for y in range(size[1]) :
        for x in range(size[0]) :
            ite = (y * size[0] + x) * 3
            r = data[ite]
            g = data[ite+1]
            b = data[ite+2]
        
            image.putpixel((x,y) , (r,g,b))

    img_show(image)
}
↑PILでカラー画像のオブジェクト(image)を作成して、そこにputpixelで入れるだけ。

Pythonで出力した画像のスクショ

↑元画像と同じになった!

意図通りにはできたんだが、、、気付いた。なんでこれちゃんと動いたんだ?
ということで続く。


Amazonのほしい物リスト(公開用)を作ってみた

ytのほしい物​リスト

↑作成した私のほしい物リスト(欲しいものリストじゃないのね)。
もちろん自分用じゃなくて公開するためのもの。もともとの非公開のリストには、欲しくはないが気になるといったものを入れてる。

Amazonほしいものリストを住所・本名を公開せずに贈ってもらう方法 | ゆずうさぎ
↑こちらを参考にやってみた。

若干画面が変わっていて戸惑ったところが、「リストの設定」というリンクがないこと。

ほしい物リスト作成画面

↑画面右の方、「作成する」の右にあるはずなのにない?
あれー?と思ったら、

「リストの共有」にオンマウスした状態のほしい物リスト作成画面

↑「リストの共有」の右の・・・のところにマウスを持っていくと表示されたのでここで「リストの設定」を選択できる。
他にも若干違うところがあるけど、まあなんとかなった。



NSArrayControllerの中身を全部削除するカテゴリ

なぜかNSArrayControllerオブジェクトが持つオブジェクトを全て削除するメソッドがない。
なんでだろう?
そういう処理はよろしくないのか?

↓ともかくこんな感じでカテゴリで作って使ってる。
// ヘッダー側
@interface NSArrayController (RemoveAllObjects)
-(void)removeAllObjects;
@end

//実装側
@implementation NSArrayController (RemoveAllObjects)
-(void)removeAllObjects
{
    NSUInteger nofObjects = [self.arrangedObjects count];
    for (NSUInteger ite=0;ite<nofObjects;ite++) {
        [self removeObjectAtArrangedObjectIndex:nofObjects - ite -1];
    }
}
@end
今の所問題ない。😄


macOS High Sierra 10.13.6


データ列からNSImageオブジェクトを作成する

NSImageから白黒画像のデータが欲しい(2)
↑ここでデータ列から白黒のNSImageを作成してるのでそのコードをメモ。

元データは白黒なので1ピクセルあたり8ビット (=1バイト)で縦x横のサイズ分ってことで
unsigned char *data = calloc(width*height , sizeof(unsigned char));
↑こういう感じでメモリを確保してそこに適当に輝度データが入ってる、とする。

そのデータとサイズからNSImageオブジェクトを返すメソッドがこちら↓
+(NSImage *)makeGrayNSImageFromData:(void *)data size:(NSSize)size
{
    size_t width = size.width;
    size_t height = size.height;
    size_t bitsPerComponent = 8;
    size_t bitsPerPixel = 8;
    size_t bytesPerRow = width;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    bool shouldInterpolate = 1;
    CGColorRenderingIntent intent = 0;
    
    NSUInteger nData = width * height;
    CFDataRef cfdata = CFDataCreate(NULL, data, nData);
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(cfdata);
    
    CGImageRef cgimage = CGImageCreate(
                            width, height,
                            bitsPerComponent, bitsPerPixel, bytesPerRow,
                            colorSpace, bitmapInfo, dataProvider,
                            NULL, shouldInterpolate, intent);
    
    NSImage *image = [[NSImage alloc] initWithCGImage:cgimage size:size];
    
    CGImageRelease(cgimage);
    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colorSpace);
    CFRelease(cfdata);
    
    return image;
}
メモリ解放を忘れるとどんどん使用してるメモリの量が増えていくので要注意。CoreGraphics周りはARCでも自分でメモリ解放処理を記述しなければならない。
{
    NSInteger cx = width/2.0;
    NSInteger cy = height/2.0;
    for (NSInteger yy=0;yy<height;yy++) {
        for (NSInteger xx=0;xx<width;xx++) {
            NSUInteger ite = yy*width+xx;
            unsigned char length = sqrtf(powf(xx-cx , 2)+powf(yy-cy, 2)) / cx *255;
            data[ite] = length;
        }
    }
}
↑確認用に画像の中心からの距離(横幅の半分で255になるように)を入れたデータを作成。
描画メソッドの確認画像
↑その結果の画像。


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

NSImageから白黒画像のデータが欲しい(1)
↑この続き。
そもそも欲しいのは白黒画像ではなく、白黒画像のデータなのだ。
Metal Performance Shadersで入力画像としてNSImageオブジェクトがあれば、それを
(void *)data
としてデータ列にして↓このようにMPSImageに突っ込む。
{
    [srcImage.texture replaceRegion:srcImageRegion
                                  mipmapLevel:0
                                        slice:0
                                    withBytes:data
                                  bytesPerRow:28*sizeof(float)
                                bytesPerImage:0];
}
macOSで画像の輝度データを得る
↑ここでも書いてた。

なので、実は白黒画像のNSImageオブジェクトが必要なわけではない。だーっとならんだデータ列が欲しいのだ。
ということでiOSで使っていたコードを参考に次のようなコードを書いてみた。
{
    NSImage *image = sceneView.snapshot;//スクショをカラー画像で得る
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGImageAlphaInfo bitmapInfo = kCGImageAlphaNone;
    
    CGContextRef context = CGBitmapContextCreate(nil,
                                                 width,
                                                 height,
                                                 8,
                                                 width,
                                                 colorSpace,
                                                 bitmapInfo);
    
    NSRect imageRect = NSMakeRect(0, 0, width,height);
    NSGraphicsContext *gctx = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO];
    [NSGraphicsContext setCurrentContext:gctx];
    [image drawInRect:imageRect];
    
    void *data = CGBitmapContextGetData (context);
 

    //dataを使った処理


    //メモリ解放
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);
}
snapshotで得たカラー画像を白黒画像のcolor spaceを持つcontextにdrawする、というなんとも強引なのだが、、、

スクショを白黒画像にして表示した結果

↑確認のためvoid *data→NSImage→NSImageViewとして半分のサイズで重ねて表示してる。ちゃんと白黒画像になる。この白黒画像のcolor spaceを確認すると
kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; Generic Gray Gamma 2.2 Profile
と出るので輝度情報しかもたない真っ当な白黒画像だ。


version memo
macOS High Sierra 10.13.6


追記
本記事でデータ列からNSImageを作成してるが、そのコードはこちらに↓
データ列からNSImageオブジェクトを作成する







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

FC2Ad