Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 检索UIImage的像素alpha值_Iphone_Uikit_Core Graphics_Quartz Graphics - Fatal编程技术网

Iphone 检索UIImage的像素alpha值

Iphone 检索UIImage的像素alpha值,iphone,uikit,core-graphics,quartz-graphics,Iphone,Uikit,Core Graphics,Quartz Graphics,我目前正在尝试获取UIImageView中像素的alpha值。我从[UIImageView image]获得了CGImage,并由此创建了一个RGBA字节数组。阿尔法是预乘的 CGImageRef image = uiImage.CGImage; NSUInteger width = CGImageGetWidth(image); NSUInteger height = CGImageGetHeight(image); CGColorSpaceRef colorSpace = CGColorSp

我目前正在尝试获取UIImageView中像素的alpha值。我从[UIImageView image]获得了CGImage,并由此创建了一个RGBA字节数组。阿尔法是预乘的

CGImageRef image = uiImage.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
rawData = malloc(height * width * 4);
bytesPerPixel = 4;
bytesPerRow = bytesPerPixel * width;

NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(
    rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);
然后,我使用UIImageView中的坐标计算给定alpha通道的数组索引

int byteIndex = (bytesPerRow * uiViewPoint.y) + uiViewPoint.x * bytesPerPixel;
unsigned char alpha = rawData[byteIndex + 3];
然而,我没有得到我期望的值。对于图像的完全黑色透明区域,我得到alpha通道的非零值。我是否需要转换UIKit和核心图形之间的坐标,即:y轴是否反转?还是我误解了预乘α值

更新:

@尼古拉·鲁赫的建议是关键。事实上,我不需要在UIKit坐标和核心图形坐标之间进行转换。但是,在设置混合模式后,我的alpha值达到了我的预期值:

CGContextSetBlendMode(context, kCGBlendModeCopy);

是的,CGContext的y轴指向上,而在UIKit中它指向下

阅读代码后编辑:

您还希望在绘制图像之前将“混合模式”设置为“替换”,因为您需要的是图像的alpha值,而不是之前在上下文缓冲区中的alpha值:

CGContextSetBlendMode(context, kCGBlendModeCopy);
思考后编辑:

通过构建尽可能最小的CGBitmapContext(1x1像素?可能8x8像素?试试看),并在绘制之前将上下文转换到所需位置,可以更高效地执行查找:

CGContextTranslateCTM(context, xOffset, yOffset);
我是否需要转换UIKit和核心图形之间的坐标,即:y轴是否反转

这是可能的。在CGImage中,像素数据的英文读取顺序为:从左到右,从上到下。因此,阵列中的第一个像素是左上角;第二像素是在顶行上从左起的一个像素;等等

假设你有这个权利,你也应该确保你在一个像素内看到正确的组件。也许您期望RGBA,但要求ARGB,反之亦然。或者,也许你的字节顺序错了(我不知道iPhone的尾端是什么)

还是我误解了预乘α值

听起来不像


对于那些不知道的人来说:预乘意味着颜色分量被alpha预乘;无论颜色分量是否被其预乘,alpha分量都是相同的。您可以通过将颜色分量除以alpha来反转(不进行乘法运算)。

我在研究如何使用图像数据的alpha值(而不是矩形边界框)在精灵之间进行碰撞检测时发现了这个问题/答案。上下文是一个iPhone应用程序。。。我正在尝试进行上述建议的1像素绘制,但仍存在一些问题,但我找到了一种更简单的方法,可以使用图像本身的数据和此处的辅助函数创建CGContextRef:

CGContextRef context = CGBitmapContextCreate(
                 rawData, 
                 CGImageGetWidth(cgiRef), 
                 CGImageGetHeight(cgiRef), 
                 CGImageGetBitsPerComponent(cgiRef), 
                 CGImageGetBytesPerRow(cgiRef), 
                 CGImageGetColorSpace(cgiRef),
                 kCGImageAlphaPremultipliedLast     
    );
这绕过了上面示例中所有难看的硬编码。最后一个值可以通过调用CGImageGetBitmapInfo()来检索,但在我的例子中,它从图像返回一个值,该值导致ContextCreate函数中出现错误。只有某些组合是有效的,如下所述:


希望这是有帮助的

如果您只需要单个点的alpha值,那么您只需要一个alpha-only单点缓冲区。我相信这已足够:

// assume im is a UIImage, point is the CGPoint to test
CGImageRef cgim = im.CGImage;
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel, 
                                         1, 1, 8, 1, NULL,
                                         kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(-point.x, 
                                   -point.y, 
                                   CGImageGetWidth(cgim), 
                                   CGImageGetHeight(cgim)), 
               cgim);
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;

我认为这就解决了翻转问题。

CGImageRef表示静态图像。一旦有了字节数组,我就扔掉CGImage,然后重复使用字节数组进行alpha查找。在这种情况下,你的优化会起作用吗?不,当然你需要图像来反复绘制。我的方法可以更有效地进行少量查找。如果你要做大量的查找,请坚持使用你的代码。我也在尝试这一点(我正在做大量的查找-每次点击一次)。它在模拟器上运行得很好,但在iPhone4上却不行。坐标看起来不错(左下角为0,0),但命中测试是一团混乱。看,嘿,提伯特-我意识到这个问题已经得到了回答,但几天前我做了类似的事情。不应绘制整个图像,然后索引到字节数组中,而应仅将源图像的1px绘制到1px×1px位图上下文中。您可以使用CGContextDrawImage中的rect参数来输入正确的像素,速度快了1000倍:-)感谢@Ben Gotow的评论-我只绘制一次图像,然后继续使用相同的字节数组@Nikolai Ruhe还建议使用单像素绘制,但他说,如果我不需要多次绘制图像,但需要重复查找alpha,那么我的阵列方法会更快。只是快速更新(几年后)在为类似问题使用此问题和此处的另一个问题之后:CGContextDrawImage上的rect参数用于控制“绘制图像的边界框在用户空间中的位置和尺寸”。因此,如果将该rect设置为1x1大小,则在绘制图像之前,它会将整个图像缩小到1x1。为了得到正确的像素,你需要像Nikolai的回答一样使用CGContextTranslateCTM,并保持rect的大小与源图像相同,以防止缩放。嗨,我正在尝试使用你发布的代码,但无法获得“rawData”、“bytePerPixel”变量的数据类型。你能告诉我答案吗?这很有帮助。请记住,在这里,您的BytesPerRow可能不是宽度*bytesPerPixel。为了优化,可以将其填充到16字节边界。当你遍历rawData时,如果你不考虑这一点,你最终会使用填充字节作为像素数据。这也意味着你的malloced的rawData可能太小,无法容纳位图,并且可能存在缓冲区溢出。我想知道这是否是为什么我在iPhone上很难使用它的原因,但它在模拟器上可以正常工作?出于某种原因,我不得不对
CGContextDrawImage(…
)使用以下行:
CGContextDraw
// assume im is a UIImage, point is the CGPoint to test
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel, 
                                             1, 1, 8, 1, NULL,
                                             kCGImageAlphaOnly);
UIGraphicsPushContext(context);
[im drawAtPoint:CGPointMake(-point.x, -point.y)];
UIGraphicsPopContext();
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;