自定义CIKernel位移映射

5
我正在尝试创建一个位移映射CIKernel,用于iOS 8,该映射将像素从地图R通道水平移动和从G通道垂直移动。 必须相对于源图像大小选择地图像素坐标mapPixel = ((dest.x / source.width) * map.width, (dest.y / source.height) * map.height)
我测试的输入图像大小为2048 x 2048, 地图是红绿柏林噪声2560 x 2560
在Quartz Composer中,cikernel几乎按预期工作,只是未将地图应用于整个图像。
kernel vec4 coreImageKernel(sampler image, sampler displaceMap, float scaleX, float scaleY)
{
 vec2 destination = destCoord();

 vec2 imageSize = samplerSize(image);
 float xPercent = destination.x / imageSize.x;
 float yPercent = destination.y / imageSize.y;

 vec2 mapSize = samplerSize(displaceMap);
 vec2 mapCoord = vec2(mapSize.x * xPercent, mapSize.y * yPercent);

 vec4 mapPixel = sample(displaceMap, mapCoord);
 float ratioShiftX = ((mapPixel.x) * 2.0) - 1.0;
 float ratioShiftY = ((mapPixel.y) * 2.0) - 1.0;
 vec2 pixelShift = vec2(ratioShiftX * scaleX, ratioShiftY * scaleY);

 return sample(image, destination - pixelShift);
}

这是 filter 函数的样子:

function __image main(__image image, __image displaceMap, __number scaleX, __number scaleY) {
  return coreImageKernel.apply(image.definition, null, image, displaceMap, scaleX, scaleY);
}

但是,当我在CIFilter中加载cikernel时,结果与我在Quartz Composer中看到的远不相同。

以下是我在CIFilter中的应用函数:

override var outputImage:CIImage? {
    if let inputImage = inputImage {
        if let inputMap = inputMap {
            let args = [inputImage as AnyObject, inputMap as AnyObject, inputScaleX, inputScaleY]

            return CIDisplacementMapFilter.kernel?.applyWithExtent(inputImage.extent, roiCallback: {
                    (index, rect) in

                    if index == 0 {
                        return rect
                    }

                    return CGRectInfinite
                }, arguments: args)
        }
    }

    return nil
}

我猜测ROI是错误的,采样器是平铺的,但我无法弄清楚。

2个回答

1
事实证明内核是错误的。这里有一个能完成工作的内核。
kernel vec4 displace(sampler source, sampler map, float scaleX, float scaleY)
{

vec2 d = destCoord();
vec4 mapPixel = sample(map, samplerTransform(map, d));
float shiftX = ((mapPixel.x * 2.0) - 1.0) * scaleX;
float shiftY = ((mapPixel.y * 2.0) - 1.0) * scaleY;

vec2 s = samplerTransform(source, d + vec2(shiftX, shiftY));

return sample(source, s);
}

谢谢。如果有人感兴趣,我会发布Metal代码的答案。 - kaharoth

0

这是适用于Metal的相同代码

#include <metal_stdlib>
using namespace metal;
#include <CoreImage/CoreImage.h>

extern "C" {
  namespace coreimage {
    float4 displaceFilterKernel(sampler source, sampler map, float scaleX, float scaleY)
    {
      float2 d = map.coord();
      float4 mapPixel = map.sample(d);
      float shiftX = ((mapPixel.x * 2.0) - 1.0) * scaleX;
      float shiftY = ((mapPixel.y * 2.0) - 1.0) * scaleY;
      float2 s = float2(d.x, 1.0 - d.y) + float2(shiftX, shiftY);
      return sample(source, s);
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接