请帮助 CGBitmapContext 和 16 位图像

发布于 2024-09-28 09:21:58 字数 2649 浏览 4 评论 0原文

我很想知道我在这里做错了什么。我是 CGImageRefs 的新手,所以任何建议都会有帮助。

我正在尝试创建一个位图图像,该图像的像素值是另一个位图像素的加权和,并且两个位图每个通道都是 16 位。由于某种原因,我可以毫无困难地让它在 8 位图像上工作,但在 16 位图像上却严重失败。我的猜测是我只是没有正确设置。我尝试过使用 CGFloats、float 和 UInt16s 作为数据类型,但没有任何效果。输入图像没有 Alpha 通道。我得到的输出图像看起来像彩色的雪。

标题中的相关内容:

UInt16 *inBaseAddress;
UInt16 *outBaseAddress;
CGFloat inAlpha[5];
CGFloat inRed[5];
CGFloat inGreen[5];
CGFloat inBlue[5];
CGFloat alphaSum, redSum, greenSum, blueSum;
int shifts[5];
CGFloat weight[5];
CGFloat weightSum;

我使用以下方法创建输入位图的上下文(使用 CGImageSourceCreateImageAtIndex(source, 0, NULL) 创建的 CGImageRef):

size_t width = CGImageGetWidth(inBitmap);
size_t height = CGImageGetHeight(inBitmap);
size_t bitmapBitsPerComponent = CGImageGetBitsPerComponent(inBitmap);
size_t bitmapBytesPerRow = (pixelsWide * 4 * bitmapBitsPerComponent / 8);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(inImage);

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast;


CGContextRef inContext = CGBitmapContextCreate (NULL,width,height,bitmapBitsPerComponent,bitmapBytesPerRow,colorSpace,bitmapInfo);

输出位图的上下文以相同的方式创建。我使用以下方法将 inBitmap 绘制到 inContext 中:

CGRect rect = {{0,0},{width,height}}; 
CGContextDrawImage(inContext, rect, inBitmap);

然后我像这样初始化 inBaseAddress 和 outBaseAddress:

inBaseAddress = CGBitmapContextGetData(inContext);
outBaseAddress = CGBitmapContextGetData(outContext);

然后我用 inBaseAddress 中的值填充 outBaseAddress:

for (n = 0; n < 5; n++)
{
    inRed[n] = inBaseAddress[inSpot + 0 + shifts[n]];
    inGreen[n] = inBaseAddress[inSpot + 1 + shifts[n]];
    inBlue[n] = inBaseAddress[inSpot + 2 + shifts[n]];
    inAlpha[n] = inBaseAddress[inSpot + 3 + shifts[n]];

}

alphaSum = 0.0;
redSum = 0.0;
greenSum = 0.0;
blueSum = 0.0;

for (n = 0; n < 5; n++)
{
    redSum  += inRed[n] * weight[n];
    greenSum += inGreen[n] * weight[n];
    blueSum += inBlue[n] * weight[n];
    alphaSum += inAlpha[n] * weight[n];

}

outBaseAddress[outSpot + 0] = (UInt16)roundf(redSum);
outBaseAddress[outSpot + 1] = (UInt16)roundf(greenSum);
outBaseAddress[outSpot + 2] = (UInt16)roundf(blueSum);
outBaseAddress[outSpot + 3] = (UInt16)roundf(alphaSum);

作为我尝试过的简单检查:

outBaseAddress[outSpot + 0] = inBaseAddress[inSpot + 0];
outBaseAddress[outSpot + 1] = inBaseAddress[inSpot + 1];
outBaseAddress[outSpot + 2] = inBaseAddress[inSpot + 2];
outBaseAddress[outSpot + 3] = inBaseAddress[inSpot + 3];

它有效并且至少意味着上下文和指针位图数据正在工作。

感谢您的任何意见。这非常令人沮丧,因为它在 8 位图像上运行得很好。

I'd LOVE to know what I'm doing wrong here. I'm a bit of a newbie with CGImageRefs so any advice would help.

I'm trying to create a bitmap image that has as it's pixel values a weighted sum of the pixels from another bitmap, and both bitmaps are 16bits per channel. For some reason I had no trouble getting this to work with 8bit images but it fails miserably with 16bit. My guess is that I'm just not setting things up correctly. I've tried using CGFloats, floats and UInt16s as the data types but nothing has worked. The input image has no alpha channel. The output image I get looks liked colored snow.

relevant stuff from the header:

UInt16 *inBaseAddress;
UInt16 *outBaseAddress;
CGFloat inAlpha[5];
CGFloat inRed[5];
CGFloat inGreen[5];
CGFloat inBlue[5];
CGFloat alphaSum, redSum, greenSum, blueSum;
int shifts[5];
CGFloat weight[5];
CGFloat weightSum;

I create the context for the input bitmap (a CGImageRef created with CGImageSourceCreateImageAtIndex(source, 0, NULL)) using:

size_t width = CGImageGetWidth(inBitmap);
size_t height = CGImageGetHeight(inBitmap);
size_t bitmapBitsPerComponent = CGImageGetBitsPerComponent(inBitmap);
size_t bitmapBytesPerRow = (pixelsWide * 4 * bitmapBitsPerComponent / 8);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(inImage);

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast;


CGContextRef inContext = CGBitmapContextCreate (NULL,width,height,bitmapBitsPerComponent,bitmapBytesPerRow,colorSpace,bitmapInfo);

The context for the output bitmap is created in the same way. I draw the inBitmap into the inContext using:

CGRect rect = {{0,0},{width,height}}; 
CGContextDrawImage(inContext, rect, inBitmap);

Then I initialize the inBaseAddress and outBaseAddress like so:

inBaseAddress = CGBitmapContextGetData(inContext);
outBaseAddress = CGBitmapContextGetData(outContext);

Then I fill the outBaseAddress with values from the inBaseAddress:

for (n = 0; n < 5; n++)
{
    inRed[n] = inBaseAddress[inSpot + 0 + shifts[n]];
    inGreen[n] = inBaseAddress[inSpot + 1 + shifts[n]];
    inBlue[n] = inBaseAddress[inSpot + 2 + shifts[n]];
    inAlpha[n] = inBaseAddress[inSpot + 3 + shifts[n]];

}

alphaSum = 0.0;
redSum = 0.0;
greenSum = 0.0;
blueSum = 0.0;

for (n = 0; n < 5; n++)
{
    redSum  += inRed[n] * weight[n];
    greenSum += inGreen[n] * weight[n];
    blueSum += inBlue[n] * weight[n];
    alphaSum += inAlpha[n] * weight[n];

}

outBaseAddress[outSpot + 0] = (UInt16)roundf(redSum);
outBaseAddress[outSpot + 1] = (UInt16)roundf(greenSum);
outBaseAddress[outSpot + 2] = (UInt16)roundf(blueSum);
outBaseAddress[outSpot + 3] = (UInt16)roundf(alphaSum);

As a simple check I've tried:

outBaseAddress[outSpot + 0] = inBaseAddress[inSpot + 0];
outBaseAddress[outSpot + 1] = inBaseAddress[inSpot + 1];
outBaseAddress[outSpot + 2] = inBaseAddress[inSpot + 2];
outBaseAddress[outSpot + 3] = inBaseAddress[inSpot + 3];

which works and at least means that the contexts and pointers to the bitmap data are working.

Thanks for any input. This has been pretty frustrating since it worked just fine with 8bit images.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深府石板幽径 2024-10-05 09:21:58

好的,我已经弄清楚了。我需要将 16 位 图像的 bitmapInfo 设置为 kCGBitmapByteOrder16Little,将 8bit 图像的 bitmapInfo 设置为 kCGBitmapByteOrder32Little。实际上,我对此感到有点惊讶,因为我本以为会是相反的情况(16 位为 32Little,8 位为 16Little)。

我还需要将指向位图的指针键入为 UInt8*UInt16*。看来我还必须在 bitmapContext 中包含一个 Alpha 通道。我不知道为什么,但如果没有它,返回的上下文总是为零。

OK, I've got it figured out. I needed to set the bitmapInfo to kCGBitmapByteOrder16Little for the 16bit images and to kCGBitmapByteOrder32Little for the 8bit images. I'm a bit surprised by this actually as would have expected it to be the other way around (32Little for 16 bit and 16Little for 8bit).

I also needed to type def the pointers to the bitmaps as UInt8* and UInt16*. It also appears that I have to include an alpha channel in the bitmapContext. I'm not sure why but the context returned was always nil without it.

囍笑 2024-10-05 09:21:58

听起来像是字节顺序问题

It sounds like a byte ordering problem

弥繁 2024-10-05 09:21:58

您是否检查过 CGImageGetBitsPerComponent 是否返回 16?作为一种风格问题,如果您假设要创建每像素 16 位的位图上下文(因为您将数据视为 UInt16*),则应该显式设置 set size_t位图BitsPerComponent = 16

你的 shifts 数组是做什么用的?这似乎是最有可能出错的地方,因为它会影响您正在读取的地址,但您根本没有解释它。 shifts 中的值是 16 的倍数吗?

Have you checked that CGImageGetBitsPerComponent is returning 16? As a matter of style, if you're assuming you're creating a bitmap context with 16 bits per pixel (since you treat the data as UInt16*), you should set explicitly set size_t bitmapBitsPerComponent = 16.

What is your shifts array for? It seems like the most likely place for error, since it's affecting the address you're reading from, but you don't explain it at all. Are the values in shifts multiples of 16?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文