ios - Objective-C中基于触摸的图像处理

标签 ios iphone objective-c image-processing touch

好的,我正在构建这个应用程序,它可以在iPhone / iPad中进行一些用户交互式图像操作。
这基本上是一种与触摸有关的功能,可以根据触摸对任何图像进行重塑。在应用程序Facetune中可以找到非常相似的内容。

我的算法需要根据触摸运动来计算控制点。然后基于这些控制点,我将生成一个用于对图像进行插值的结果网格。我的整个方法工作正常。唯一的问题是实时性很慢。我在用

dispatch_async(dispatch_get_main_queue(), ^{

在触摸移动功能,但仍然很慢。将图像重新缩放至约360 *可以加快处理速度,但会降低图像质量。

我的触摸移动代码是:
- (void)updateImage
{
    int bytesPerRow = CGImageGetBytesPerRow([staticBG.image CGImage]);
    int height = CGImageGetHeight([staticBG.image CGImage]);
    int width = CGImageGetWidth([staticBG.image CGImage]);
    CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider([staticBG.image CGImage]));
    unsigned char *baseImage = (unsigned char *)CFDataGetBytePtr(pixelData);

    unsigned char *output_image;
    output_image = [self wrappingInterpolation :baseImage :orig :changed :width :height :bytesPerRow];

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
    CGContextRef context = CGBitmapContextCreate(output_image, width, height, 8, bytesPerRow, colorSpaceRef, bitmapInfo);
    CGImageRef imageRef = CGBitmapContextCreateImage (context);
    UIImage *newimage = [UIImage imageWithCGImage:imageRef];
    CGColorSpaceRelease(colorSpaceRef);
    CGContextRelease(context);
    CFRelease(imageRef);

    free(output_image);
    resultView.image = newimage;
    //staticBG.hidden = YES;
}

wrapInterpolation方法对图像像素进行实际的图像处理,该方法经过高度优化,可以实时运行。 orig和更改的参数只是两个float * float matix,它具有我需要的控制点。我在这里看到固定的开销,它每次都从UIImage获取像素数据,然后创建CGImageRef,CGCOntextRef,ColorSpaceRef等。然后再次释放它。
无论如何,我可以优化这些?
如果可能,建议任何其他可能的提速方法。但是我真的对OpenGL或着色器一无所知,因此我可能无法通过着色器来完成这些工作。

最佳答案

没错,瓶颈在于内存管理。

当您将原始位图数据提取到CFDataRef pixelData上时,您将解压缩完整图像并将其完全复制。然后,插值例程再次创建详细的数据副本并将其存储到output_image中。
然后释放两次内存,一次释放通过属性分配释放的旧映像,一次释放free(...)命令。

就数字而言:iPhone 5可以3264x2448的分辨率拍摄照片,这意味着22MB的RGB格式(每通道8b),是包装程序的两倍。并且这种双重分配和双重复制(以及双重释放)以触发事件的速率发生。您还必须添加例程用于处理输入数据的时间:在每个像素上循环意味着在8MP图像中进行800万次迭代。这无疑需要大量的计算能力。

请注意,您要实现的目标在某种程度上类似于实时视频/图像处理。至于视频处理,则应采用特定的技术。 OpenGL确实是您最好的选择,但是需要更多的努力。一些基本的建议可能是

  • 避免分配两次:因为您已经在复制数据,所以如果您的算法允许就地转换,则直接在baseImage上工作。
  • 缓存图像数据:并非每次都提取位图数据。如果您的算法“可加”地工作,请保留相同的CFDataRef并每次对其进行处理。

    在您的例程中,始终将staticBG用作输入数据:这表明算法始终会更改基本图像。您可以一次全部缓存原始图像数据。
  • 避免包装在UIImage:CALayer具有有用的属性contents,可以将其设置为CGImageRef来显示内容。另外,您正在做的事情与动画有关,因此您确实可以删除UI内容并在CA级别上工作,这更加灵活(而且速度更快)。参见Apple's documentation
  • 如果确实必须使用中间存储器,则重用相同的存储器并复制到其上:图像的大小可能不会改变,并且至少可以节省分配时间。
  • 预渲染最终结果:实际上,您可以按照屏幕的大小工作,并存储制作完整尺寸图像所需的信息。然后,在后续阶段中进行操作。

  • 这些建议可以避免所有不必要的分配,如果您的算法不具有累加性或无法就地运行,那么剩下的只是复制操作。有关算法的一些建议(您可能已经实现):
  • 尽可能处理数据。
  • 仅在实际上将要修改的像素上循环。
  • 仅复制您需要处理的数据。
  • 如果可以,将像素视为向量并使用优化的函数。看看Accelerate framework。有许多例程可以直接在图像上工作。
  • 尽可能使用Quartz 2D


  • 不过,最好的建议是:切换到OpenGL 。即使在最佳情况下,您仍然有一个问题:无法避免的对CGBitmapContextCreateImage的调用。 Documentation说您的数据是由CoreGraphics复制的:这意味着每一帧至少需要一个完整的数据副本。据我所知,您不能实时修改正在显示的缓冲区。最好的近似值是由OpenGL提供的,它几乎在硬件级别运行,并写入缓冲区,该缓冲区直接冲入由CoreAnimation显示的EAGLContext中。

    这是一种非常不同的方法,但是非常快。某些视觉效果(如高斯模糊)需要大量功能,但需要在OpenGL下实时运行。您可以开始看这个GLImageProcessing,这是一个非常有趣的光栅图像处理示例。此外,OpenGL也非常适合图像变形:您可以在平面网格上将图像显示为纹理,然后使其变形。

    关于ios - Objective-C中基于触摸的图像处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19972026/

    相关文章:

    ios - AppDelegate 中的 XMPP 框架代码

    ios - 悬停时动画 alpha 属性

    iphone - 是否可以在安装 Xcode 4 后安装 Xcode 3?

    objective-c - Objective C 中的公共(public)和私有(private)伞头

    objective-c - 使用从 NSOperation 子类 (ARC) 到主线程的 block 回调

    objective-c - 使用 int 作为 NSDictionary 键?

    ios - 不影响 iPad 设备的设备方向设置

    iphone - 将地理坐标转换为CGPoint并在UIView中画线

    iphone - 如何向导航栏添加栏按钮

    iphone - UINavigationcontroller 的背景图片