好的,我正在构建这个应用程序,它可以在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。 这些建议可以避免所有不必要的分配,如果您的算法不具有累加性或无法就地运行,那么剩下的只是复制操作。有关算法的一些建议(您可能已经实现):
不过,最好的建议是:切换到OpenGL 。即使在最佳情况下,您仍然有一个问题:无法避免的对
CGBitmapContextCreateImage
的调用。 Documentation说您的数据是由CoreGraphics复制的:这意味着每一帧至少需要一个完整的数据副本。据我所知,您不能实时修改正在显示的缓冲区。最好的近似值是由OpenGL提供的,它几乎在硬件级别运行,并写入缓冲区,该缓冲区直接冲入由CoreAnimation显示的EAGLContext
中。这是一种非常不同的方法,但是非常快。某些视觉效果(如高斯模糊)需要大量功能,但需要在OpenGL下实时运行。您可以开始看这个GLImageProcessing,这是一个非常有趣的光栅图像处理示例。此外,OpenGL也非常适合图像变形:您可以在平面网格上将图像显示为纹理,然后使其变形。
关于ios - Objective-C中基于触摸的图像处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19972026/