iOS:概述部分透明图像的不透明部分

时间:2012-02-02 04:59:02

标签: ios image-processing graphics uiimage

我有一个应用程序,要求在部分透明UIImage周围绘制纯黑色轮廓。不是在图像的框架周围,而是围绕图像本身的所有不透明部分。即,想到一个透明的PNG,上面有一个不透明的白色“X” - 我需要用黑色勾勒出“X”。

为了使问题变得棘手,在绘制轮廓之后,将调整原始图像的不透明度,但轮廓必须保持不透明 - 因此我生成的轮廓必须仅包含 轮廓,而不是原始图像。

我目前的技术是:

  • 创建一个具有原始图片尺寸的新UIView
  • 复制UIImage 4次,并将重复项添加为UIView的子视图,每个UIImage从原始位置沿对角线偏移几个像素。
  • UIView转换为图片(通过典型的UIGraphicsGetImageFromCurrentImageContext方法)。
  • 使用CGImageMaskCreateCGImageCreateWithMask,从此新图片中减去原始图像,只剩下轮廓。

有效。即使只有4个偏移图像,结果看起来也很不错。然而,它非常低效,并且在iPhone 4上造成了4秒的稳定延迟。

所以我需要的是一个很好,快速,有效的方法来实现同样的东西,iOS 4.0完全支持。

有什么好主意吗? :)

4 个答案:

答案 0 :(得分:3)

我想指出的是,虽然有些人建议进行边缘检测,但这不是一个合适的解决方案。边缘检测用于在图像数据中查找边缘,其中数据中没有明显的精确边缘表示。

对于你来说,边缘定义得更好,你正在寻找定义明确的轮廓。在您的情况下,边缘是任何像素,它位于完全透明的像素上,旁边是一个不完全透明的像素,简单就是这样!迭代图像中的每个像素,如果它们满足这些条件,则将它们设置为黑色。

或者,对于抗锯齿结果,获取图像的布尔表示,并将一个小的抗锯齿圆内核传递给它。我知道你说不支持自定义过滤器,但是如果你可以直接访问图像数据,那么手动实现就不会太难了......

干杯,希望这会有所帮助。

答案 1 :(得分:2)

为了提出新的想法:

当前实现的一个变体将使用CALayer对阴影的支持,它根据图层的实际像素内容计算,而不仅仅是它的边界矩形,并且它使用GPU。您可以尝试将shadowOpacity放大到一些巨大的值,以试图消除羽化;如果你无法渲染到合适的CGContext,只取出alpha图层并手动处理它以对alpha值应用阈值测试,将它们推到完全不透明或完全透明。

即使在ES 1下,您也可以通过各种方式在GPU上实现最终处理步骤。您可以使用alpha测试来应用实际阈值,然后,您可以将深度缓冲区填充为1.0,禁用颜色输出和深度测试,使用深度为0.5的阴影绘制版本,绘制没有深度为1.0的阴影然后启用颜色输出和深度测试,并在0.75的深度绘制纯黑色全屏四边形。所以就像使用深度缓冲区来模拟模板一样(因为在使用ES 2的设备之前使用的Apple Apple不支持模板缓冲区)。

当然,假设CALayer阴影出现在合成器之外,我没有检查过。

或者,如果您愿意限制对ES 2设备(所有3GS +)的支持,那么您可以将图像上传为纹理并在GPU上完成整个过程。但这在技术上会使一些支持iOS 4的设备不受支持,所以我认为不是一种选择。

答案 2 :(得分:1)

您只需要实现edge detection算法,但不要使用亮度或颜色来确定边缘的位置,而是使用不透明度。有许多不同的方法可以解决这个问题。例如,您可以查看每个像素及其邻居,以确定不透明度超过您设置的阈值的区域。每当您需要在MacOS X或iOS中查看图像的每个像素时,请考虑Core Image。有一系列有用的博客文章starting with this one着眼于实现自定义核心图像过滤器 - 我将从那里开始构建边缘检测过滤器。

答案 3 :(得分:0)

而是使用UIView,我建议只按下面的上下文:

UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0);
//draw your image 4 times and mask it whatever you like, you can just copy & paste
//current drawing code here.
....
outlinedimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

这比你的UIView要快得多。