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

epfja78i  于 2022-11-26  发布在  iOS
关注(0)|答案(1)|浏览(152)

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

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-then语句,只对CGRect中包含的像素着色,但是,所有其他像素仍然会通过内核。
换句话说,无论CGRect有多小,上述内核都将处理8192 x 8192图像中的所有67,108,864个像素,而不是上述CGRect中的100个像素。
注意,我并不是在寻找一个裁剪过的图像。我仍然希望输出是8192 x 8129像素,在x:20,y:20处有一个10 x 10的正方形。
我认为ROI回调函数可能是解决方案,但它仍然显示整个图像都被染成红色,而不仅仅是我指定的区域。

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:

我尝试了下面Frank Rupprecht的建议,结果如下:

下面是渲染阶段的外观(如果有帮助的话):
1.将输出渲染到CV泛指elBuffer
1.将CV泛指elBuffer转换为CIImage,并将CImage存储在下一帧中,以便下一次通过内核。
1.缩放并转换步骤2中的CIImage,以在MTKView可绘制对象中显示。
在步骤2中进行中间渲染的原因是为了保持图像的原始分辨率,并且不会因渲染到可绘制对象时发生的缩放和平移而更改。

abithluo

abithluo1#

您可以使用apply(...)方法中的extend参数来指定套用核心的区域:

kernel.apply(extent: CGRect(x: 20, y: 20, width: 10, height: 10), roiCallback:...)

这应该只在图像的指定区域运行内核。你不需要改变ROICallback,因为这只指定了需要输入图像的哪一部分来产生渲染区域的输出 *,所以只要在roiCallback中返回输入rect就可以了。
另一个优化:由于您只从输入中读取输出坐标处的单个像素(因此从输入到输出的Map为1:1),因此您可以使用CIColorKernel,方法是更改内核代码,如下所示:

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 Image知道这是一个1:1Map。

相关问题