浮動小数点グレースケール画像データを必要とする画像処理作業を行っています。以下の方法-imagePlanarFData:
は、現在、入力からこのデータを抽出する方法ですCIImage
。
- (NSData *)byteswapPlanarFData:(NSData *)data
swapInPlace:(BOOL)swapInPlace;
{
NSData * outputData = swapInPlace ? data : [data mutableCopy];
const int32_t * image = [outputData bytes];
size_t length = [outputData length] / sizeof(*image);
for (int i = 0;
i < length;
i++) {
int32_t * val = (int32_t *)&image[i];
*val = OSSwapBigToHostInt32(*val);
}
return outputData;
}
- (NSData *)imagePlanarFData:(CIImage *)processedImage;
{
NSSize size = [processedImage extent].size;
if (size.width == 0) {
return nil;
}
dispatch_once(&_onceToken, ^ {
_colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
_bytesPerRow = size.width * sizeof(float);
_cgx = CGBitmapContextCreate(NULL, size.width, size.height, 32, _bytesPerRow, _colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents);
// Work-around for CIImage drawing EXC_BAD_ACCESS when running with Guard Malloc;
// see <http://stackoverflow.com/questions/11689233/ciimage-drawing-exc-bad-access>
NSDictionary * options = nil;
if (getenv("MallocStackLogging") || getenv("MallocStackLoggingNoCompact")) {
NSLog(@"Forcing CIImageContext to use software rendering; see %@",
@"<http://stackoverflow.com/questions/11689233/ciimage-drawing-exc-bad-access>");
options = @{ kCIContextUseSoftwareRenderer: @YES };
}
_cix = [CIContext contextWithCGContext:_cgx
options:options];
_rect = CGRectMake(0, 0, size.width, size.height);
});
float * data = CGBitmapContextGetData(_cgx);
CGContextClearRect(_cgx, _rect);
[_cix drawImage:processedImage
inRect:_rect
fromRect:_rect];
NSData * pixelData = [NSData dataWithBytesNoCopy:data
length:_bytesPerRow * size.height
freeWhenDone:NO];
// For whatever bizarre reason, CoreGraphics uses big-endian floats (!)
return [self byteswapPlanarFData:pixelData swapInPlace:NO];
}
コメントで述べたように、フロートピクセルデータがビッグエンディアンの順序でCGBitmapContextから出力されたのを見て非常に驚きました。(これは試行錯誤でしか判断できませんでした。)こうして追加の方法-byteswapPlanarFData:swapInPlace:
が導入され、すべてが世界にうまくいったように見えました...しばらくの間。
しかし今、私はこの処理されたデータをに戻したいと思いますCGImage
。
以前、私のコードはfloat * data
上記で抽出されたバッファーを取得し、それを直接使用して新しいものをレンダリングし、次のようCGImage
にラップしました。NSImage
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bytesPerRow * size.height, NULL);
CGImageRef renderedImage = CGImageCreate(size.width, size.height, 32, 32, bytesPerRow, colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents, provider, NULL, false, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
NSImage * image = [[NSImage alloc] initWithCGImage:renderedImage
size:size];
CGImageRelease(renderedImage);
だから今私はこれをやっています:
pixelData = [mumble imagePlanarFData:processedImage];
// Swap data back to how it was before...
pixelData = [mumble byteswapPlanarFData:pixelData
swapInPlace:YES];
float * data = (float *)[pixelData bytes];
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, bytesPerRow * size.height, NULL);
CGImageRef renderedImage = CGImageCreate(size.width, size.height, 32, 32, bytesPerRow, colorSpace, kCGImageAlphaNone | kCGBitmapFloatComponents, provider, NULL, false, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
NSImage * image = [[NSImage alloc] initWithCGImage:renderedImage
size:size];
CGImageRelease(renderedImage);
上記は機能しません。代わりに、CoreGraphicsから破損した画像と一連の苦情が届きます。
Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: CMMConvLut::ConvertFloat 1 input (inf)
Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: ApplySequenceToBitmap failed (-171)
Mar 21 05:56:46 aoide.local LabCam[34235] <Error>: ColorSyncTransformConvert - failed width = 160 height = 199 dstDepth = 7 dstLayout = 0 dstBytesPerRow = 1920 srcDepth = 7 srcLayout = 0 srcBytesPerRow = 640
どこが間違っているのですか?