Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.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
使用Accelerate框架和vDSP进行iPhone图像处理_Iphone_Image Processing_Accelerate Framework_Vdsp - Fatal编程技术网

使用Accelerate框架和vDSP进行iPhone图像处理

使用Accelerate框架和vDSP进行iPhone图像处理,iphone,image-processing,accelerate-framework,vdsp,Iphone,Image Processing,Accelerate Framework,Vdsp,更新:请参阅下面的附加问题和更多代码 我正在尝试为模糊图像编码一个类别。我的出发点是。虽然这(在其他人建议的修复之后)效果很好,但对于我的要求来说,它的速度太慢了一个数量级-在3GS上,可能需要3秒钟才能完成一个像样的模糊,我希望全屏的模糊时间能降到0.5秒以下(越快越好) 他提到加速框架是一种性能增强,所以我花了最后一天的时间来研究它,特别是苹果文档中提到的vDSP_f3x3 通过执行以下操作过滤图像: 具有3x3的二维卷积 内核单精度 完美-我有一个合适的过滤器矩阵,我有一个图像。。。但这就

更新:请参阅下面的附加问题和更多代码

我正在尝试为模糊图像编码一个类别。我的出发点是。虽然这(在其他人建议的修复之后)效果很好,但对于我的要求来说,它的速度太慢了一个数量级-在3GS上,可能需要3秒钟才能完成一个像样的模糊,我希望全屏的模糊时间能降到0.5秒以下(越快越好)

他提到加速框架是一种性能增强,所以我花了最后一天的时间来研究它,特别是苹果文档中提到的vDSP_f3x3

通过执行以下操作过滤图像: 具有3x3的二维卷积 内核单精度

完美-我有一个合适的过滤器矩阵,我有一个图像。。。但这就是我被难倒的地方

vDSP_f3x3假设图像数据为(浮点*),但我的图像来自

srcData = (unsigned char *)CGBitmapContextGetData (context);
上下文来自CGBitmapContextCreate和KCgimageAlphaPremultipledFirst,因此我的srcData实际上是ARGB,每个组件8位

我怀疑我真正需要的是具有浮点组件的上下文,但是,kCGBitMapFloatComponents仅在Mac OS上可用,而在iOS上不可用:-(

有没有一种使用加速框架将整数组件转换为vDSP_f3x3所需的浮点组件的快速方法?我的意思是我可以自己做,但当我做这件事时,然后是卷积,然后再转换回,我怀疑我会使它比现在更慢,因为我可以一边做卷积

也许我的方法不对

有没有人给我一些使用vDSP在iphone上进行图像处理的小贴士?我能找到的文档非常面向参考,在这类事情上不太适合新手

如果有人有一个真正快速模糊(和高质量,而不是降低分辨率,然后重新缩放的东西,我已经看到,看起来裤子)的参考,这将是了不起的

编辑:

谢谢@Jason。我已经这样做了,它几乎可以工作了,但现在我的问题是,虽然图像确实模糊了,但每次调用它都会左移1个像素。它似乎也会使图像变黑变白,但这可能是其他原因

这段代码中有什么明显不正确的地方吗?我还没有对它进行优化,它有点粗糙,但希望卷积代码足够清晰

CGImageRef CreateCGImageByBlurringImage(CGImageRef inImage, NSUInteger pixelRadius, NSUInteger gaussFactor)
{
unsigned char *srcData, *finalData;

CGContextRef context = CreateARGBBitmapContext(inImage);
if (context == NULL) 
    return NULL;

size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);

int componentsPerPixel = 4; // ARGB

CGRect rect = {{0,0},{width,height}}; 
CGContextDrawImage(context, rect, inImage); 

// Now we can get a pointer to the image data associated with the bitmap
// context.

srcData = (unsigned char *)CGBitmapContextGetData (context);

if (srcData != NULL)
{

    size_t dataSize = bpr * height;
    finalData = malloc(dataSize);
    memcpy(finalData, srcData, dataSize);

    //Generate Gaussian kernel

    float *kernel;  

    // Limit the pixelRadius

    pixelRadius = MIN(MAX(1,pixelRadius), 248);
    int kernelSize = pixelRadius * 2 + 1;

    kernel = malloc(kernelSize * sizeof *kernel);

    int gauss_sum =0;

    for (int i = 0; i < pixelRadius; i++)
    {
        kernel[i] = 1 + (gaussFactor*i);
        kernel[kernelSize - (i + 1)] = 1 + (gaussFactor * i);
        gauss_sum += (kernel[i] + kernel[kernelSize - (i + 1)]);
    }

    kernel[(kernelSize - 1)/2] = 1 + (gaussFactor*pixelRadius);

    gauss_sum += kernel[(kernelSize-1)/2];

    // Scale the kernel

    for (int i=0; i<kernelSize; ++i) {
        kernel[i] = kernel[i]/gauss_sum;
    }

    float * srcAsFloat,* resultAsFloat;

    srcAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);
    resultAsFloat = malloc(width*height*sizeof(float)*componentsPerPixel);

   // Convert uint source ARGB to floats

    vDSP_vfltu8(srcData,1,srcAsFloat,1,width*height*componentsPerPixel);

    // Convolve (hence the -1) with the kernel

    vDSP_conv(srcAsFloat, 1, &kernel[kernelSize-1],-1, resultAsFloat, 1, width*height*componentsPerPixel, kernelSize);

    // Copy the floats back to ints

    vDSP_vfixu8(resultAsFloat, 1, finalData, 1, width*height*componentsPerPixel);

    free(resultAsFloat);
    free(srcAsFloat);

}

size_t bitmapByteCount = bpr * height;

CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, finalData, bitmapByteCount, &providerRelease);

CGImageRef cgImage = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context),
                                   CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context), 
                                   dataProvider, NULL, true, kCGRenderingIntentDefault);

CGDataProviderRelease(dataProvider);
CGContextRelease(context); 


return cgImage;
}
然后,正如预期的那样,我的结果是原始源的克隆。在颜色上,并没有向左移动。这对我来说意味着是卷积出错了,但我看不出在哪里:-(

思考:实际上考虑到这一点,在我看来,卷积需要知道输入像素是ARGB格式的,否则卷积将把值相乘,而不知道它们的含义(即它将乘以R*B等).这可以解释为什么我会得到一个B&W的结果,我认为,但不是转变。再次,我认为可能需要比我的天真版本更多的东西


最后一个想法:我认为向左移动是过滤器的自然结果,我需要查看图像尺寸并可能将其填充…因此我认为代码实际上工作正常,因为我已经填充了它。

您肯定希望转换为
float
来执行过滤,因为这是加速函数所采用的,另外,如果您想进行任何额外的处理,它会更加灵活。二维卷积(过滤器)的计算时间很可能会使转换所花费的时间相形见绌。请看一看函数
vDSP_vfltu8()
,它将快速将uint8数据转换为浮点。
vDSP_vfixu8()
将其转换回uint8

要执行模糊,您可能需要一个比3x3更大的卷积内核,因此我建议使用函数
vDSP\u imgfir()
,它可以接受任何内核大小

编辑响应:

有几件事:

  • 您需要独立地对每个颜色通道执行过滤。也就是说,您需要将R、G和B组件拆分为它们自己的图像(类型为float),对它们进行过滤,然后将它们重新多路复用到ARGB图像中

  • vDSP_conv
    计算一维卷积,但要使图像模糊,确实需要二维卷积。
    vDSP_imgfir
    基本上计算二维卷积。为此,还需要二维核。您可以查找二维高斯函数的公式来生成核。
    注意:如果内核是可分离的(即高斯函数),实际上可以使用一维卷积执行二维卷积.我不想讨论这意味着什么,但基本上你必须对列执行一维卷积,然后对结果行执行一维卷积。除非你知道你在做什么,否则我不会走这条路


  • 因此,在Jason出色的帮助下回答我自己的问题,这里提供了最后的工作代码片段,以供参考,以防它对其他人有所帮助。正如您所看到的,策略是将源ARGB(为了性能,我忽略了A,并假设数据是XRGB)拆分为3个浮点数组,应用过滤器,然后重新复用结果

    这是一种享受,但速度非常慢。我正在使用16x16的大内核来获得严重的模糊,在我的3GS上,全屏图像大约需要5秒钟,所以这不是一个可行的解决方案

    下一步是寻找替代方案…但谢谢你让我站起来并开始运行

        vDSP_vfltu8(srcData+1,4,srcAsFloatR,1,pixels);
        vDSP_vfltu8(srcData+2,4,srcAsFloatG,1,pixels);
        vDSP_vfltu8(srcData+3,4,srcAsFloatB,1,pixels);
    
        // Now apply the filter to each of the components. For a gaussian blur with a 16x16 kernel
        // this turns out to be really slow!
    
        vDSP_imgfir (srcAsFloatR, height, width, kernel,resultAsFloatR, frows, fcols);
        vDSP_imgfir (srcAsFloatG, height, width, kernel,resultAsFloatG, frows, fcols);
        vDSP_imgfir (srcAsFloatB, height, width, kernel,resultAsFloatB, frows, fcols);
    
        // Now re-multiplex the final image from the processed float data
    
        vDSP_vfixu8(resultAsFloatR, 1, finalData+1, 4, pixels);
        vDSP_vfixu8(resultAsFloatG, 1, finalData+2, 4, pixels);
        vDSP_vfixu8(resultAsFloatB, 1, finalData+3, 4, pixels);
    

    虽然Accelerate框架比简单的串行代码要快,但使用它模糊图像可能永远看不到最好的性能

    我的建议是使用OpenGL ES 2.0着色器(适用于支持此API的设备)来执行双通道框模糊。基于我的基准测试,GPU可以随时处理此类图像处理操作
        vDSP_vfltu8(srcData+1,4,srcAsFloatR,1,pixels);
        vDSP_vfltu8(srcData+2,4,srcAsFloatG,1,pixels);
        vDSP_vfltu8(srcData+3,4,srcAsFloatB,1,pixels);
    
        // Now apply the filter to each of the components. For a gaussian blur with a 16x16 kernel
        // this turns out to be really slow!
    
        vDSP_imgfir (srcAsFloatR, height, width, kernel,resultAsFloatR, frows, fcols);
        vDSP_imgfir (srcAsFloatG, height, width, kernel,resultAsFloatG, frows, fcols);
        vDSP_imgfir (srcAsFloatB, height, width, kernel,resultAsFloatB, frows, fcols);
    
        // Now re-multiplex the final image from the processed float data
    
        vDSP_vfixu8(resultAsFloatR, 1, finalData+1, 4, pixels);
        vDSP_vfixu8(resultAsFloatG, 1, finalData+2, 4, pixels);
        vDSP_vfixu8(resultAsFloatB, 1, finalData+3, 4, pixels);