我正在开发一个着色器来渲染带有胶片框架效果的图像.我制作了以下着色器:

extern "C" {
    namespace coreimage {
        float4 reassemble(sampler source, sampler frame, float imgWidth, float perFrameSize, float epsilon, destination dest) {
            float2 coord = dest.coord();
            float4 srcExtent = source.extent();
            float4 pixel = float4(0, 1, 0, 1);
            
            float sideFrameSize = epsilon + (imgWidth - srcExtent.z)/2 - perFrameSize;
            float offset = sideFrameSize + perFrameSize - epsilon;
            if (coord.x < sideFrameSize) {
                pixel = source.sample(source.transform(float2(coord.x + srcExtent.x + srcExtent.z - sideFrameSize, coord.y)));
            }
            else if (coord.x >= offset && coord.x <= srcExtent.z + offset) {
                pixel = source.sample(source.transform(float2(coord.x + srcExtent.x - offset, coord.y)));
            }
            else if (coord.x >= srcExtent.z + offset + perFrameSize - epsilon) {
                pixel = source.sample(source.transform(float2(coord.x + srcExtent.x - srcExtent.z - offset - perFrameSize + epsilon, coord.y)));
            }
            
            float4 framePixel = frame.sample(frame.transform(coord));
            return mix(pixel, framePixel, framePixel.a);
        }
    }
}

它的运作与预期不谋而合,yields 为the following image辆.

当试图将种植整合到管道中时,就会出现这个问题.当我在调用内核函数之前添加裁剪时,一切都按预期运行.但是,如果我裁剪内核函数的输出图像,似乎首先裁剪了源图像,然后着色器在裁剪后的图像上运行.

if let source = self.kernel.apply(extent: frameImage.extent,
                                                  roiCallback: { _, rect -> CGRect in
                                                        return rect
                                                    },
                                                  arguments: [scaled.transformed(by: .init(translationX: 0, y: perFrameWidth - vOffset)), frameImage, image.extent.width, perFrameWidth, hOffset]) {
                    return source.cropped(to: frameImage.extent.insetBy(dx: 80, dy: 200))
                }

The resulting image由上面的代码生成.

虽然这可能是一个优化,但它是相当意想不到的.如何修改此行为以确保修剪着色器的输出图像,而不是原始图像?您的真知灼见将不胜感激.


我想更详细地解释这个问题.着色器的第一个参数是图像,重要的是要注意,我不会直接裁剪它.相反,裁剪发生在输出图像上.奇怪的是,我传递给着色器的图像似乎也被裁剪了.更重要的是,我try 在调用着色器之后进行裁剪,这很奇怪,着色器接收到裁剪后的图像.

Original image

Output image without crop

Output image with crop

推荐答案

正如您正确猜测的那样,Core Image在这里执行了优化:它将您对图像执行的不同过滤器和操作整合到尽可能少的处理操作中.特别是对于裁剪,它试图只处理在最终结果中可见的像素.这一点在(旧的和过时的)Core Image Programming Guide中有所概述.

为此,它从后到前分析过滤器图,以确定需要输入图像的哪一部分来计算所需的输出图像.这称为region of interest(ROI),通常取决于应该产生的输出区域(domain of definition,DOD).这也被描述为here.

作为过滤器开发人员,您有责任告诉Core Image您的内核需要读取输入图像(ROI)的哪个区域才能生成给定的输出区域.这就是内核调用中的roiCallback参数的用途:对于给定的输入索引(如果您的内核使用多个输入图像)和给定的输出区域(DOD),您必须返回该输入图像的ROI.

在前面的代码中,您告诉Core Image,您的内核执行1:1映射,即对于给定的输出区域,您只需要从输入图像中读取相同的区域.这意味着Core Image也只从输入中获得loaded个区域,并将其传递给内核. However,您的内核实际上在与输出coord不同的位置对输入图像进行采样,因此提供的输入区域是不够的.

如果您按如下方式编写roiCallback,您就是在告诉Core Image,您始终需要whole输入图像,而不管要生成输出的哪个区域.这样,您的内核始终具有可用于采样的输入图像的所有像素.

let inputExtent = frameImage.extent // best do that outside of the block to not capture the input image inside the ROI callback
let roiCallback = { _, _ in 
    return inputExtent
}

请注意,这种方法也不理想,因为Core Image现在不能再优化了.它总是需要加载整个图像,并可能使用流水线中以前的任何过滤器来处理它,而不管实际输出有多小.理想情况下,你会计算出过滤器really对于给定的DOD需要多少ROI,并将其返回到您的roiCallback.

Ios相关问答推荐

SwiftUI.从自定义视图修改器访问自定义视图子视图

在许多UIButton中对齐文本,即使SF Symbols(或其他图像)具有不同的宽度?

在金属中设置纹理的UV坐标以编程方式变形纹理

Swift在SceneKit中为scnnode添加自定义几何体(视图)

SWIFT AVFoundation翻转相机功能不起作用

在TVOS中访问SWIFT中的objc++函数时发送给类的无法识别的 Select 符

BezierPath 中绘制图像形状轮廓的算法(Canny 边缘检测器)

如何使用自定义数据源在本地react 本机 ios 应用程序中加载 Tradingview 小部件?

swiftui 图像放大时无法正确拖动

以正确的方式在 Text() 中使用 colored颜色

通过 segue 传递数据

如何比较两个 UIImage 对象

如何像在 Facebook 应用程序中一样以编程方式打开设置?

如何在 UILabel 中找到文本子字符串的 CGRect?

如何更改uitableview删除按钮文本

AFNetworking 2.0 向 GET 请求添加标头

UIView - 加载视图时如何获得通知?

更新字段时,UITextField值已更改未触发

Info.plist 实用程序错误:无法打开 Info.plist,因为没有这样的文件

UITableView 中的圆形 UIImageView 没有性能影响?