Cocoa 制作一个CoreImage过滤器,将所有行像素相加,类似于CIRowAverage?
我目前正在CPU上运行代码,对灰度图像的列和行进行求和(即每像素仅1个样本)。我想我会尝试将代码移动到GPU(如果可能的话)。我找到了一个CoreImage过滤器,它看起来很相似 在苹果的文档中,他们写道 请记住,您的代码无法逐像素积累知识。编写代码时的一个好策略是将尽可能多的不变计算从实际内核中移出,并将其放置在过滤器的Objective-C部分 这意味着可能无法使用过滤器内核对像素进行求和。如果是这样,上述函数如何获得一个区域的平均值Cocoa 制作一个CoreImage过滤器,将所有行像素相加,类似于CIRowAverage?,cocoa,core-image,cifilter,Cocoa,Core Image,Cifilter,我目前正在CPU上运行代码,对灰度图像的列和行进行求和(即每像素仅1个样本)。我想我会尝试将代码移动到GPU(如果可能的话)。我找到了一个CoreImage过滤器,它看起来很相似 在苹果的文档中,他们写道 请记住,您的代码无法逐像素积累知识。编写代码时的一个好策略是将尽可能多的不变计算从实际内核中移出,并将其放置在过滤器的Objective-C部分 这意味着可能无法使用过滤器内核对像素进行求和。如果是这样,上述函数如何获得一个区域的平均值 所以我的问题是,实现对图像行或列求和以获得像素总值的最佳
所以我的问题是,实现对图像行或列求和以获得像素总值的最佳方法是什么。我应该坚持使用CPU吗?核心图像过滤器通过一系列缩减来执行此平均。团队中的一位前工程师描述了如何在内部(第26.2.2节“找到质心”)对CIAreaAverage过滤器执行此操作 我讨论了一个类似的平均值,通过减少。我在iOS上需要这个功能,所以我编写了一个片段着色器,在水平和垂直维度上将图像减少了四倍,在像素之间进行采样,以便在每一步平均16个像素。一旦图像缩小到足够小的尺寸,剩余的像素将被读出并平均以产生一个最终值 这种减少在GPU上的执行速度仍然非常快,我能够在iPhone 4上以6毫秒的时间从640x480视频帧中提取平均颜色。你当然会有更多的马力在Mac上玩
您可以采取类似的方法,通过在每个步骤中仅在一个方向或另一个方向上减少。如果您对获取像素值的总和感兴趣,则需要注意GPU上使用的像素格式的精度限制。默认情况下,RGBA颜色值存储为8位值,但某些GPU上的OpenGL(ES)扩展可以使您能够渲染为16位甚至32位浮点纹理,从而扩展动态范围。我不确定,但我相信Core Image允许您在Mac上使用32位浮点组件。供您参考,在CireaAverage过滤器上,其编码如下:
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
您的输出应该如下所示:
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
谢谢你的建议。我认为,转向GPU是个骗局。我的目的是处理像素亮度有意义的科学数据(光子到达事件)。保持每件事情的线性是非常重要的,我不愿意把这类工作转移到GPU上,除非我能确切地理解它是如何工作的。不幸的是,CoreImage插件似乎将所有内容都转换为RGB,有时还会向图像添加特殊的偏移量和缩放因子(对于CIGaussianBlur来说也是如此)。也许我会在需要擦亮的时候着手解决这个问题!我需要学习OpenGL。