首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何告诉CIKernel只处理图像的特定区域?

如何告诉CIKernel只处理图像的特定区域?
EN

Stack Overflow用户
提问于 2022-11-20 21:32:18
回答 1查看 40关注 0票数 1

我有一个简单的CIKernel,它把像素染成红色:

代码语言:javascript
复制
extern "C" float4 BasicFilter (coreimage::sampler input, coreimage::destination dest) {
    float4 inputPixel = input.sample(input.transform(dest.coord()));
    
    float4 color = float4(1.0, 0.0, 0.0, 0.5);
    
    float r = (inputPixel.r * (1 - color.a)) + (color.r * color.a);
    float g = (inputPixel.g * (1 - color.a)) + (color.g * color.a);
    float b = (inputPixel.b * (1 - color.a)) + (color.b * color.a);
    float a = 1.0;
    
    return float4(r,g,b,a);
}

默认情况下,这个内核运行在任何时候的单个像素上,返回一个红色的、有色的图像。我希望它能实时工作,每一帧。因此,我认为限制它只处理图像特定区域中的像素是很重要的。我该怎么做?

例如:

  • 输入图像: 8192 x 8192
  • 区域到着色红色: CGRect(x: 20,y: 20,宽度: 10,高度: 10)

我可以在内核中写一个if语句,只对CGRect中包含的像素进行着色。然而,所有其他像素仍将通过内核。

换句话说,不管CGRect多么小,上面的内核将处理8192x8192图像中的所有67,108,864像素,而不是上面的CGRect中的100个像素。

注意,我不是在找剪裁过的图像。我仍然希望输出是8192 x 8129像素,在x:20,y:20处有10×10平方的颜色。

我认为ROI回调函数可能是解决方案,但它仍然显示整个图像被染成红色,而不仅仅是我指定的区域。这是我提供的ROI回调:

代码语言:javascript
复制
let roiCallback: CIKernelROICallback = { index, rect -> CGRect in
                return CGRectCGRect(x: 20, y: 20, width: 10, height: 10)
}

我也尝试过:

步骤1:将输入图像裁剪到所需区域并对其进行处理;步骤2:步骤1对原始输入图像的复合输出。

这并没有导致较高的FPS。似乎在步骤2中,所有67,108,164像素仍然必须由CISourceOverCompositing处理,而不是改进。

我在MTKView中呈现最后的输出。

有没有更有效的解决方案?

编辑01:

下面我尝试了弗兰克·鲁普普雷希特的建议。这是产出:

如果有帮助,这就是呈现阶段的样子:

CVPixelBuffer

  • Convert

  • 将输出呈现给CIImage,并存储CImage,以便在下一帧中通过内核。

  • 缩放并将CIImage从第2步转换为MTKView drawable.

中的显示。

在步骤2中进行中间呈现的原因是保留图像的原始分辨率,而不被呈现到可绘制时发生的缩放和转换所改变。

EN

回答 1

Stack Overflow用户

发布于 2022-11-21 09:23:28

您可以指定内核应用于在extend方法中使用apply(...)参数的区域:

代码语言:javascript
复制
kernel.apply(extent: CGRect(x: 20, y: 20, width: 10, height: 10), roiCallback:...)

这应该只在映像的指定区域上运行内核。您不需要更改ROICallback,因为这只指定需要输入映像的哪一部分才能生成呈现区域的输出,所以只返回roiCallback中的输入rect就可以了。

另一个优化:因为您只从输入读取输出坐标下的单个像素(因此从输入到输出有1:1的映射),所以您可以使用CIColorKernel来代替,方法是像这样修改内核代码:

代码语言:javascript
复制
extern "C" float4 BasicFilter (coreimage::sample input) {
    float4 inputPixel = input; // this is already just a single pixel value
    
    float4 color = float4(1.0, 0.0, 0.0, 0.5);
    
    float r = (inputPixel.r * (1 - color.a)) + (color.r * color.a);
    float g = (inputPixel.g * (1 - color.a)) + (color.g * color.a);
    float b = (inputPixel.b * (1 - color.a)) + (color.b * color.a);
    float a = 1.0;
    
    return float4(r,g,b,a);
}

然后将内核初始化为CIColorKernel而不是CIKernel。在apply上,您也不需要指定一个roiCallback,因为Core知道它是1:1的映射。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74512170

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档