我的程序中有一个大的1D动态数组,表示磁盘上的FITS图像,即它保存图像的所有像素值。数组的类型是 double 。目前,我只关心单色图像。
由于Cocoa不直接支持FITS格式,我使用CFITSIO库读取图像。这有效 - 我可以按照自己的意愿操作数组,并使用库将结果保存到磁盘。
但是,我现在想要显示图像。我认为这是NSImage或NSView可以做的事情。但类引用似乎没有列出一个可以采用C数组并最终返回NSImage对象的方法。我找到的最接近的是 -initWithData:(NSData *)。但我不能100%确定这是否是我需要的。
我在这里咆哮错误的树吗?任何可以处理这个的类或方法的指针都是
编辑:
这是更新后的代码。请注意,我将每个像素设置为0xFFFF。这只会导致灰色图像。这只是一个测试。加载实际的FITS文件时,我将0xFFFF替换为imageArray[i * width + j]
。这在8位中完美地工作(当然,我将每个像素值除以256以将其表示为8位)。
NSBitmapImageRep *greyRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
pixelsWide:width
pixelsHigh:height
bitsPerSample:16
samplesPerPixel:1
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSCalibratedWhiteColorSpace
bytesPerRow:0
bitsPerPixel:16];
NSInteger rowBytes = [greyRep bytesPerRow];
unsigned short*pix = (unsigned short*)[greyRep bitmapData];
NSLog(@"Row Bytes: %d",rowBytes);
if(temp.bitPix == 16) // 16 bit image
{
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{
pix[i * rowBytes + j] = 0xFFFF;
}
}
}
我也尝试过直接使用Quartz2D。这确实产生了正确的图像,即使是16位也是如此。但奇怪的是,数据数组将0xFF视为白色,而不是0xFFFF。所以我仍然需要将所有内容除以0xFF - 在此过程中丢失数据。 Quartz2D代码:
short* grey = (short*)malloc(width*height*sizeof(short));
for(int i=0;i<width*height; i++)
{
grey[i] = imageArray[i];
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapContext = CGBitmapContextCreate(grey, width, height, 16, width*2, colorSpace, kCGImageAlphaNone);
CFRelease(colorSpace);
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);
NSImage *greyImage = [[NSImage alloc] initWithCGImage:cgImage size:NSMakeSize(width, height)];
有什么建议吗?
答案 0 :(得分:3)
initWithData
仅适用于系统已经知道的图像类型。对于未知类型 - 和原始像素数据 - 您需要自己构建图像表示。您可以通过Core Graphics执行此操作,如Kirby链接到的答案中所建议的那样。或者,您可以通过创建和添加NSImage
来使用NSBitmapImageRep
。
确切的细节将取决于像素数据的格式,但这里是灰度图像的过程示例,其中源数据(samples
数组)在范围[0表示为double, 1]:
/* generate a greyscale image representation */
NSBitmapImageRep *greyRep =
[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes: nil // allocate the pixel buffer for us
pixelsWide: xDim
pixelsHigh: yDim
bitsPerSample: 8
samplesPerPixel: 1
hasAlpha: NO
isPlanar: NO
colorSpaceName: NSCalibratedWhiteColorSpace // 0 = black, 1 = white in this color space
bytesPerRow: 0 // passing 0 means "you figure it out"
bitsPerPixel: 8]; // this must agree with bitsPerSample and samplesPerPixel
NSInteger rowBytes = [greyRep bytesPerRow];
unsigned char* pix = [greyRep bitmapData];
for ( i = 0; i < yDim; ++i )
{
for ( j = 0; j < xDim; ++j )
{
pix[i * rowBytes + j] = (unsigned char)(255 * (samples[i * xDim + j]));
}
}
NSImage* greyscale = [[NSImage alloc] initWithSize:NSMakeSize(xDim,yDim)];
[greyscale addRepresentation:greyRep];
[greyRep release];
编辑(回应评论)
我不确定是否支持16位样本,但您似乎已经确认它们是。
您所看到的仍然是将像素视为unsigned char
,即8位。因此,您只设置每一行的一半,并且您将每个像素(每次一个字节)设置为两个字节值0xFF00
- 不是非常真实的白色,而是非常接近。
你需要先工作16位,首先从代表中转换你得到的值:
unsigned short * pix = (unsigned short*) [greyRep bitmapData];
然后为像素分配16位值:
if ( j % 2 )
{
pix[i * rowBytes + j] = 0xFFFF;
}
else
{
pix[i * rowBytes + j] = 0;
}
请注意,rowBytes
以字节为单位,因此我们需要坚持unsigned char
pix
并在分配时进行投射,这有点丑陋:
if ( j % 2 )
{
*((unsigned short*) (pix + i * rowBytes + j * 2)) = 0xFFFF;
}
else
{
*((unsigned short*) (pix + i * rowBytes + j * 2)) = 0;
}
(我已经改变了子句的顺序,因为== 0
似乎是多余的。实际上对于这样的事情来说,使用?:
语法会更加简洁,但这个C语言足够多了。)< / p>
答案 1 :(得分:1)
以下是您的代码的解决方案。这扩展到支持所有3个频道。每个通道为16位。请注意,我将imageArray [i]分配给每个通道。这只是因为我目前还没有编写可以读取彩色FITS文件的代码,所以为了测试我只是将图像分配给每个通道。当然,结果是屏幕上的灰度图像。但如果有人想要,可以很容易地修改它,以便将红色分配给红色,依此类推。
NSBitmapImageRep *colorRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
pixelsWide:width
pixelsHigh:height
bitsPerSample:16
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:(3*2*width)
bitsPerPixel:48];
rowBytes = [greyRep bytesPerRow];
NSLog(@"Row Bytes: %d",rowBytes);
pix = [colorRep bitmapData];
for(i=0;i<height*width;++i)
{
*((unsigned short*)(pix + 6*i)) = imageArray[i];
*((unsigned short*)(pix + 6*i + 2)) = imageArray[i];
*((unsigned short*)(pix + 6*i + 4)) = imageArray[i];
}
NSImage *theImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
[greyScale addRepresentation:colorRep];
[myimageView setImage:theImage];
答案 2 :(得分:0)