【问题标题】:How is the image data interpreted for a grayscale image on an iPhone?iPhone 上灰度图像的图像数据是如何解释的?
【发布时间】:2010-12-14 07:41:52
【问题描述】:

在以下情况下,如何理解灰度图像的图像数据:我从“样本缓冲区”捕获视频数据并提取 80x20 部分,然后将其转换为灰度 UIImage。但是当我检查原始像素字节时,我无法以一种允许我继续并“二值化”它们的方式来理解它们(我的真正目标)。

当我使用 UIImageWriteToSavedPhotosAlbum 简单地将 UIImage 保存到相册以验证我拥有什么样的图像数据时,我确实得到了一张纯白色的 80x20 图像(它实际上是浅灰色的)。我捕获了一张纯白色的图像来简化事情,希望只看到介于 200 左右和 255 之间的值,但图像数据的某些部分充满了零,这清楚地表明了黑色像素的行。任何帮助表示赞赏。相关代码和图像数据(一次16个像素)如下。

以下是我从 CMSampleBufferRef 视频数据的一部分创建 80x20 灰度图像的方法:

UIImage *imageFromImage(UIImage *image, CGRect rect)
{   
    CGImageRef sourceImageRef = [image CGImage];  
    CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);  
    
    CGImageRef grayScaleImg = grayscaleCGImageFromCGImage(newImageRef);
    CGImageRelease(newImageRef);  
    
    UIImage *newImage = [UIImage imageWithCGImage:grayScaleImg scale:1.0 orientation:UIImageOrientationLeft]; 
    
    return newImage;  
}  

CGImageRef grayscaleCGImageFromCGImage(CGImageRef inputImage) 
{
    size_t width = CGImageGetWidth(inputImage);
    size_t height = CGImageGetHeight(inputImage);
    
    // Create a gray scale context and render the input image into that
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 
                    4*width, colorspace, kCGBitmapByteOrderDefault);
    
    CGContextDrawImage(context, CGRectMake(0,0, width,height), inputImage);
    
    // Get an image representation of the grayscale context which the input
    //    was rendered into.
    CGImageRef outputImage = CGBitmapContextCreateImage(context);
    
    // Cleanup
    CGContextRelease(context);
    CGColorSpaceRelease(colorspace);
    
    return (CGImageRef)[(id)outputImage autorelease];
}

然后,当我使用以下代码将像素数据转储到控制台时:

    CGImageRef inputImage = [imgIn CGImage];
CGDataProviderRef dataProvider = CGImageGetDataProvider(inputImage);
CFDataRef imageData = CGDataProviderCopyData(dataProvider);
const UInt8 *rawData = CFDataGetBytePtr(imageData);

size_t width = CGImageGetWidth(inputImage);
    size_t height = CGImageGetHeight(inputImage);

    size_t numPixels = height * width;
for (int i = 0; i < numPixels ; i++)
{   
   if ((i % 16) == 0)
          NSLog(@" -%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-%i-\n\n", rawData[i],         
             rawData[i+1], rawData[i+2], rawData[i+3], rawData[i+4], rawData[i+5], 
             rawData[i+6], rawData[i+7], rawData[i+8], rawData[i+9], rawData[i+10], 
             rawData[i+11], rawData[i+12], rawData[i+13], rawData[i+14], rawData[i+15]);
}

我一直得到如下输出:

-216-217-214-215-217-215-216-213-214-214-214-215-215-217-216-216-

-219-219-216-219-220-217-212-214-215-214-217-220-219-217-214-219-

-216-216-218-217-218-221-217-213-214-212-214-212-212-214-214-213-

-213-213-212-213-212-214-216-214-212-210-211-210-213-210-213-208-

-212-208-208-210-206-207-206-207-210-205-206-208-209-210-210-207-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-

(对于剩余的字节,此模式重复,80 字节的像素数据在 200 中,取决于光照,然后是 240 字节的零 - 因为图像是 80x20,所以总共有 1600 字节)

【问题讨论】:

    标签: iphone image-processing uiimage grayscale


    【解决方案1】:

    这个:

    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 
                    4*width, colorspace, kCGBitmapByteOrderDefault);
    

    应该是:

    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 
                    width, colorspace, kCGBitmapByteOrderDefault);
    

    换句话说,对于一个 8 位灰度图像,每行的字节数与宽度相同。

    【讨论】:

    • 你搞定了 ergosys。非常感谢。我完全被困住了,我是一个图像处理菜鸟。
    【解决方案2】:

    您可能忘记了图像步幅 - 您假设您的图像存储为宽度*高度,但有几个系统将它们存储为步幅*高度,其中步幅 > 宽度。零是您应该跳过的填充。

    顺便问一下,“二值化”是什么意思?我猜你的意思是量化到更少的灰度?

    【讨论】:

    • 二值化图像意味着将其所有像素变为白色或黑色。通常这样做是这样的:“如果图像中的像素的强度值小于阈值,则将结果图像中的相应像素设置为黑色。否则,如果像素强度值大于或等于阈值强度,生成的像素设置为白色。因此,创建一个二值化图像,或只有 2 种颜色的图像,黑色 (0) 和白色 (255)。"
    • 我从未听说过图像步幅。让我看看这个。也许这就是这里发生的事情。
    • 我将其称为转换为“双层图像”/“1 位单色图像”或量化为黑白。如果您希望将来证明您的应用程序,则不应假设您的图像格式总是使用 8 位颜色组件。
    • 我什至没有想到这一点。欣赏洞察力。
    • @Rubistro Stride 通常定义为表示一行所需的字节数,包括填充。 OP 正在谈论使用灰度和“二值化”图像,这可能意味着 1 位双电平、8 位灰度或 16 位灰度,从而导致 ceil(width/8)、width*1 或 width*2 的步幅。除非图像宽度是 8 个二级像素或 1 个灰度像素,否则绝对不是 1 的步幅。
    猜你喜欢
    • 2011-08-30
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    • 2018-11-28
    • 2020-03-07
    • 2021-05-16
    相关资源
    最近更新 更多