2

我目前正在 CPU 上运行代码,该代码对灰度NSImage 的列和行求和(即只有 1 个 samplePerPixel)。我想我会尝试将代码移动到 GPU(如果可能的话)。我发现一个 CoreImage 过滤器CIRowAverageCIColumnAverage看起来很相似。

在 Apple Docs on writing custom Core Image filters他们说,

请记住,您的代码无法逐个像素地积累知识。编写代码时的一个好策略是从实际内核中移动尽可能多的不变计算并将其放置在过滤器的 Objective-C 部分中。

这暗示可能无法使用过滤器内核对像素求和。如果是这样,上述函数如何获得一个区域的平均值?

所以我的问题是,实现对图像的行或列求和以获得像素总值的最佳方法是什么。我应该坚持CPU吗?

4

2 回答 2

5

Core Image 过滤器通过一系列缩减来执行此平均。该团队的一位前工程师在此 GPU Gems 章节中描述了如何为 CIAreaAverage 过滤器完成此操作(在第 26.2.2 节“查找质心”下)。

我在这里通过减少我的答案来讨论类似的平均值。我在 iOS 上需要这个功能,所以我编写了一个片段着色器,它在水平和垂直维度上将图像缩小了 4 倍,在像素之间进行采样,以便在每一步将 16 个像素平均为一个。一旦图像被缩小到足够小的尺寸,剩余的像素就会被读出并平均以产生一个最终值。

这种减少在 GPU 上执行起来仍然非常快,而且我能够在 iPhone 4 上在约 6 毫秒内从 640x480 视频帧中提取平均颜色。当然你会有更多的马力来玩在 Mac 上。

您可以采取类似的方法,在每一步仅减少一个方向或另一个方向。如果您有兴趣获得像素值的总和,则需要注意 GPU 上使用的像素格式的精度限制。默认情况下,RGBA 颜色值存储为 8 位值,但某些 GPU 上的 OpenGL (ES) 扩展可以让您渲染为 16 位甚至 32 位浮点纹理,从而扩展您的动态范围。我不确定,但我相信 Core Image 可以让您在 Mac 上使用 32 位浮点组件。

于 2013-01-23T18:24:02.987 回答
1

仅供参考 CIAreaAverage 过滤器 - 它的编码如下:

    CGRect inputExtent = [self.inputImage extent];
CIVector *extent = [CIVector vectorWithX:inputExtent.origin.x
                                       Y:inputExtent.origin.y
                                       Z:inputExtent.size.width
                                       W:inputExtent.size.height];
CIImage* inputAverage = [CIFilter filterWithName:@"CIAreaAverage" keysAndValues:@"inputImage", self.inputImage, @"inputExtent", extent, nil].outputImage;

//CIImage* inputAverage = [self.inputImage imageByApplyingFilter:@"CIAreaMinimum" withInputParameters:@{@"inputImage" : inputImage, @"inputExtent" : extent}];
EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] };
CIContext *myContext = [CIContext contextWithEAGLContext:myEAGLContext options:options];

size_t rowBytes = 32 ; // ARGB has 4 components
uint8_t byteBuffer[rowBytes]; // Buffer to render into

[myContext render:inputAverage toBitmap:byteBuffer rowBytes:rowBytes bounds:[inputAverage extent] format:kCIFormatRGBA8 colorSpace:nil];

const uint8_t* pixel = &byteBuffer[0];
float red   = pixel[0] / 255.0;
float green = pixel[1] / 255.0;
float blue  = pixel[2] / 255.0;
NSLog(@"%f, %f, %f\n", red, green, blue);

您的输出应如下所示:

2015-05-23 15:58:20.935 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:20.981 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
于 2015-05-23T23:25:42.323 回答