2011年6月1日水曜日

イメージを描画する(6)

前回の続きで、ヒストグラムの平坦化してみました。ほぼ同じです。データの読込みをCore Graphics でなくて NSBitmapImageRep でおこなっています。また引数を指定してイメージ・データのを指定できるようにしました。いつものように決め打ち、手抜きのだめコードです。

#import <Cocoa/Cocoa.h>
#import <Accelerate/Accelerate.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    if (argc < 3) {
        
        NSLog(@"Too few arguments required for.");
        [pool drain];
        return EXIT_FAILURE;
        
    }
    
    NSMutableDictionary *paths = [NSMutableDictionary dictionary];
    NSFileManager *fManager = [NSFileManager defaultManager];
    
    NSString *path1
        = [[NSString stringWithUTF8String:argv[1]] stringByExpandingTildeInPath];
    
    NSString *path2
        = [[NSString stringWithUTF8String:argv[2]] stringByExpandingTildeInPath];
    
    if ([fManager fileExistsAtPath:path1] == YES) {
        [paths setValue:path1 forKey:@"source"];
        [paths setValue:path2 forKey:@"distination"];
    }
    else {
        NSLog(@"Can not find a source path.");
        [paths removeAllObjects];
        [pool drain];
        return EXIT_FAILURE;
    }
    
    NSData *data = [NSData dataWithContentsOfFile:[paths valueForKey:@"source"]];
    NSBitmapImageRep *bitmapImageRep = [NSBitmapImageRep imageRepWithData:data];
    
    if (!bitmapImageRep) {
        NSLog(@"\"%@ \"format can not be handled."
              ,[[paths valueForKey:@"source"] pathExtension]);
        [paths removeAllObjects];
        [pool drain];
        return EXIT_FAILURE;
    }
    
    NSBitmapFormat alphaFirst, nonPremultiply, floatingPoint;
    NSInteger bpp, bpr, spp, pixelsHigh, pixelsWide;
    BOOL isPlanar, hasAlpha;
    NSColorSpace *colorSpace;
    NSColorSpaceModel colorSpaceModel;

    alphaFirst = [bitmapImageRep bitmapFormat] & NSAlphaFirstBitmapFormat;
    nonPremultiply = [bitmapImageRep bitmapFormat] & NSAlphaNonpremultipliedBitmapFormat;
    floatingPoint = [bitmapImageRep bitmapFormat] & NSFloatingPointSamplesBitmapFormat;
    bpp = [bitmapImageRep bitsPerPixel];
    bpr = [bitmapImageRep bytesPerRow];
    spp = [bitmapImageRep samplesPerPixel];
    pixelsHigh = [bitmapImageRep pixelsHigh];
    pixelsWide = [bitmapImageRep pixelsWide];
    isPlanar = [bitmapImageRep isPlanar];
    hasAlpha = [bitmapImageRep hasAlpha];
    colorSpace = [bitmapImageRep colorSpace];
    colorSpaceModel = [colorSpace colorSpaceModel];
    
    if (colorSpaceModel != NSRGBColorSpaceModel ||
        (bpp/spp) != 8 ||
        (floatingPoint == NSFloatingPointSamplesBitmapFormat) ) {
        
        NSLog(@"A color space is supported 8-bit RGB model only:%@, "
              @"Bits per pixel:%d, "
              @"Samples per pixel:%d, "
              ,[bitmapImageRep colorSpaceName]
              ,bpp
              ,spp);
        
        [paths removeAllObjects];
        [pool drain];
        return EXIT_FAILURE;
    }
    
    // -------------------- vImage_Bufferの作成 --------------------//
    vImage_Buffer org, src, dist;
    vImage_Error error;
    
    org.data = [bitmapImageRep bitmapData];
    org.height = (vImagePixelCount)pixelsHigh;
    org.width = (vImagePixelCount)pixelsWide;
    org.rowBytes = bpr;
    
    src.data = (unsigned char *)calloc(pixelsHigh * pixelsWide * 4, sizeof(unsigned char));
    src.height = (vImagePixelCount)pixelsHigh;
    src.width = (vImagePixelCount)pixelsWide;
    src.rowBytes = pixelsWide * 4;
    
    dist.data = (unsigned char *)calloc(pixelsHigh * pixelsWide * 4, sizeof(unsigned char));
    dist.height = (vImagePixelCount)pixelsHigh;
    dist.width = (vImagePixelCount)pixelsWide;
    dist.rowBytes = pixelsWide * 4;
    

    // RGB,RGBA,ARGB -> ARGB にする。
    if (spp == 3) {
        vImageConvert_RGB888toARGB8888(&org, NULL, 255, &src, FALSE, 0);
    }
    else if (alphaFirst == NSAlphaFirstBitmapFormat){
        
        uint8_t permutMap[4] = {3,0,1,2};
        vImagePermuteChannels_ARGB8888(&org, &src, permutMap, 0);
        
    }
    else {
        
        uint8_t permutMap[4] = {0,1,2,3};
        vImagePermuteChannels_ARGB8888(&org, &src, permutMap, 0);
        
    }
    
    // premultiply されてるものは解除。
    if (nonPremultiply != NSAlphaNonpremultipliedBitmapFormat) {
        vImageUnpremultiplyData_ARGB8888(&src, &src, 0);
    }
    
    // 平坦化
    error = vImageEqualization_ARGB8888(&src, &dist,kvImageLeaveAlphaUnchanged);
    
    // 解除したものをもとに戻す。
    if (nonPremultiply != NSAlphaNonpremultipliedBitmapFormat) {
        vImagePremultiplyData_ARGB8888(&dist, &dist, 0);
    }
    
    if (error != 0) {
        free(src.data);
        free(dist.data);
    }
    
    
    // もういらない
    free(src.data);
    
    //-------------------- 書き出し用の画像を作成 --------------------//
    CGContextRef context
    = CGBitmapContextCreate(dist.data,
                            pixelsWide,
                            pixelsHigh,
                            8,
                            pixelsWide * 4,
                            [colorSpace CGColorSpace],
                            kCGImageAlphaPremultipliedFirst);
    
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    
    // もういらない
    CGContextRelease(context);
    free(dist.data);
    
    NSBitmapImageRep *imageRep
        = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
    
    // もういらない
    CGImageRelease(cgImage);
    
    NSData *outputData = [imageRep TIFFRepresentation];
    
    [outputData writeToFile:[paths valueForKey:@"distination"]
                 atomically:YES];
    
    
    [paths removeAllObjects];
    [pool drain];
    return 0;
}

結果

Photoshop で確認。左が平坦化前、右が平坦化後のヒストグラムです。扱うイメージ・データの色に偏りがあると大幅に色相が変化します。

Equalization transforms an image so that it has a more uniform histogram. A truly uniform histogram is one in which each intensity level occurs with equal frequency. These functions approximate that histogram.

真に均一なヒストグラムは各強度レベルが同じになるが、vImage のヒストグラム関数は近似する。とあります。なるほど。

0 件のコメント:

コメントを投稿