【问题标题】:Rewriting an Android OpenGL filter to Metal (for CIFilter)将 Android OpenGL 过滤器重写为 Metal(用于 CIFilter)
【发布时间】:2019-06-21 13:41:37
【问题描述】:

我们在 GLSL (ES) 中为 Android 版本的应用编写了许多图像过滤器。从 iOS 12 开始,OpenGL 已被弃用,CIFilter 内核必须使用 Metal 编写。

我以前有一些 OpenGL 的背景,但是在 Metal 中编写 CIFilter 内核对我来说是新的。

这是过滤器之一。你能帮我把它作为 CIFilter 内核翻译成 Metal 吗?这将为我提供一个很好的例子,这样我就可以翻译其他人了。

#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 vTextureCoord;
uniform samplerExternalOES sTexture;
uniform float texelWidth;
uniform float texelHeight;
uniform float intensivity;
void main() {
    float SIZE = 1.25 + (intensivity / 100.0)*2.0;
    vec4 color;
    float min = 1.0;
    float max = 0.0;
    float val = 0.0;
    for (float x = -SIZE; x < SIZE; x++) {
        for (float y = -SIZE; y < SIZE; y++) {
            color = texture2D(sTexture, vTextureCoord + vec2(x * texelWidth, y * texelHeight));
            val = (color.r + color.g + color.b) / 3.;
            if (val > max) { max = val; } else if (val < min) { min = val; }
        }
    }
    float range = 5. * (max - min);
    gl_FragColor = vec4(pow(1. - range, SIZE * 1.5));
    gl_FragColor = vec4((gl_FragColor.r + gl_FragColor.g + gl_FragColor.b) / 3. > 0.75 ? vec3(1.) : gl_FragColor.rgb, 1.);
}

【问题讨论】:

  • 这里有一些关于金属着色语言的资源:@​​987654321@希望对您有所帮助
  • 您能否提供一个示例输入和输出图像以及强度参数的预期范围?通过检查这个内核应该做什么并不是很明显。
  • @warrenm 你好,沃伦!该内核生成输入图像的草图版本。强度参数范围为 (0,100)。这是一个示例:原始 - imgur.com/SlARGMy, p=100 -> imgur.com/IqRw4A1, p=50 -> imgur.com/Lygjaqs, p=0 -> imgur.com/oypgOo0

标签: android ios opengl-es metal core-image


【解决方案1】:

这是试图复制您描述的过滤器的内核的 Metal 源代码:

#include <metal_stdlib>
#include <CoreImage/CoreImage.h>

using namespace metal;

extern "C" {
namespace coreimage {

float4 sketch(sampler src, float texelWidth, float texelHeight, float intensity40) {
    float size = 1.25f + (intensity40 / 100.0f) * 2.0f;

    float minVal = 1.0f;
    float maxVal = 0.0f;
    for (float x = -size; x < size; ++x) {
        for (float y = -size; y < size; ++y) {
            float4 color = src.sample(src.coord() + float2(x * texelWidth, y * texelHeight));
            float val = (color.r + color.g + color.b) / 3.0f;
            if (val > maxVal) {
                maxVal = val;
            } else if (val < minVal) {
                minVal = val;
            }
        }
    }

    float range = 5.0f * (maxVal - minVal);

    float4 outColor(pow(1.0f - range, size * 1.5f));
    outColor = float4((outColor.r + outColor.g + outColor.b) / 3.0f > 0.75f ? float3(1.0f) : outColor.rgb, 1.0f);
    return outColor;
}

}
}

我假设您已经熟悉 basics 如何将 Metal 着色器正确构建到可由 Core Image 加载的库中。

您可以在运行时通过加载默认 Metal 库并请求“sketch”函数来实例化您的内核(名称是任意的,只要它与内核源代码匹配即可):

NSURL *libraryURL = [NSBundle.mainBundle URLForResource:@"default" withExtension:@"metallib"];
NSData *libraryData = [NSData dataWithContentsOfURL:libraryURL];

NSError *error;
CIKernel *kernel = [CIKernel kernelWithFunctionName:@"sketch" fromMetalLibraryData:libraryData error:&error];

然后您可以将此内核应用到映像中,方法是将其包装在您自己的 CIFilter 子类中,或者直接调用它:

CIImage *outputImage = [kernel applyWithExtent:CGRectMake(0, 0, width, height)
                                   roiCallback:^CGRect(int index, CGRect destRect)
                        { return destRect; }
                                     arguments:@[inputImage, @(1.0f/width), @(1.0f/height), @(60.0f)]];

我尝试为每个参数选择合理的默认值(第一个参数应该是 CIImage 的实例),但当然可以根据需要调整这些值。

【讨论】:

  • 非常感谢,沃伦
  • 乐于助人!感谢您的赏金。
  • 是否可以将其包装在 CIFilter 中(由 Metal 支持)?否则会导致性能问题?
  • @RoiMulia 我希望它能正常工作。如果您尝试并遇到困难,请随时在 [metal] 标签中发布另一个问题。
  • 嘿@warrenm!感谢你的回复。我创建了一个关于我的问题的新问题:stackoverflow.com/questions/57121127/…。如果你能看一下,我会很高兴,我试图让这个问题尽可能地提供信息。谢谢!
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 2016-06-07
  • 2016-04-01
  • 2020-01-01
  • 2019-02-22
  • 1970-01-01
  • 2019-05-06
  • 2023-02-25
相关资源
最近更新 更多