如何构造 5x5 矩阵以用作 Swift 中的颜色矩阵?

How to construct 5x5 matrix to apply as color matrix in Swift?

我再次需要一些帮助,将我的 Android 应用程序转换为 iOS...

正如我在其他 post 中提到的,该应用程序是关于图像处理的,它基于 ColorMatrix。问题是 Swift 仅支持(据我所知...)4x4 矩阵,对于亮度或对比度,我在 Android.

中使用 5x5 矩阵

在 Android 这些是我的矩阵:

亮度:

float[] brightMatrix = {
                1f, 0f, 0f, 0f, 32f,
                0f, 1f, 0f, 0f, 32f,
                0f, 0f, 1f, 0f, 32f,
                0f, 0f, 0f, 1f,  0f,
                0f, 0f, 0f, 0f,  1f};

对比度:

float[] contMatrix = {
                1.190f,     0f,     0f, 0f, -12.065f,
                    0f, 1.190f,     0f, 0f, -12.065f,
                    0f,     0f, 1.190f, 0f, -12.065f,
                    0f,     0f,     0f, 1f,       0f,
                    0f,     0f,     0f, 0f,       1f};

但我真的不知道如何在 Swift...

中获得相同的结果

在亮度的情况下,我尝试使用此代码除以 32/255 以获得值 0.12549:

func zoeFilter() -> UIImage? {
   let inImage = CIImage (image: self)
   dynamic let brightFactor = CIFilter (name: "CIColorControls")
   brightFactor?.setValue(inImage, forKey: kCIInputImageKey)
   brightFactor?.setValue(0.12549, forKey: kCIInputBrightnessKey)
   let brightImage = brightFactor?.outputImage
   let cgImage = CIContext().createCGImage(brightImage!, from: brightImage!.extent)
   return UIImage (cgImage: cgImage!)
}

但结果完全不一样...在iOS中就像一团白雾...

关于对比度,我找到了下一个代码,但我不可能将 Android 矩阵转换为此处的一个值 contFactor?.setValue(1, forKey: kCIInputContrastKey) 只知道 1 等于中性:

func chiaFilter() -> UIImage? {
   let inImage = CIImage (image: self)
   dynamic let contFactor = CIFilter (name: "CIColorControls")
   contFactor?.setValue(inImage, forKey: kCIInputImageKey)
   contFactor?.setValue(1, forKey: kCIInputContrastKey)
   let contImage = contFactor?.outputImage
   let cgImage = CIContext().createCGImage(contImage!, from: contImage!.extent)
   return UIImage (cgImage: cgImage!)
}

另一方面,更改曝光很容易,因为 Android 中的矩阵如下:

float[] expMatrix = {
                1.3f,   0f,   0f, 0f, 0f,
                  0f, 1.3f,   0f, 0f, 0f,
                  0f,   0f, 1.3f, 0f, 0f,
                  0f,   0f,   0f, 1f, 0f,
                  0f,   0f,   0f, 0f, 1f};

所以在 Swift 我可以使用下一个代码得到完全相同的结果:

func liaFilter() -> UIImage? {
   let inImage = CIImage (image: self)
   dynamic let expoMatrix = CIFilter (name: "CIColorMatrix")
   expoMatrix?.setDefaults()
   expoMatrix?.setValue(inImage, forKey: kCIInputImageKey)
   expoMatrix?.setValue(CIVector (x: 1.3, y: 0, z: 0, w: 0), forKey: "inputRVector")
   expoMatrix?.setValue(CIVector (x: 0, y: 1.3, z: 0, w: 0), forKey: "inputGVector")
   expoMatrix?.setValue(CIVector (x: 0, y: 0, z: 1.3, w: 0), forKey: "inputBVector")
   expoMatrix?.setValue(CIVector (x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
   let expoImage = expoMatrix?.outputImage
   let cgImage = CIContext().createCGImage(expoImage!, from: expoImage!.extent)
   return UIImage (cgImage: cgImage!)
}

太困惑了...我知道...但是如果有人能知道如何解决 Android 和 iOS 之间的这些问题,那就太好了。

提前致谢!

弗兰克回答后的版本

原图如下:

这是在使用 Android 应用过滤器之后:

float[] brightMatrix = {
                1f, 0f, 0f, 0f, 32f,
                0f, 1f, 0f, 0f, 32f,
                0f, 0f, 1f, 0f, 32f,
                0f, 0f, 0f, 1f,  0f,
                0f, 0f, 0f, 0f,  1f};

这是使用 iOS 应用滤镜的同一张图片:

brightMatrix?.setValue(CIVector (x: 1, y: 0, z: 0, w: 0), forKey: "inputRVector")
brightMatrix?.setValue(CIVector (x: 0, y: 1, z: 0, w: 0), forKey: "inputGVector")
brightMatrix?.setValue(CIVector (x: 0, y: 0, z: 1, w: 0), forKey: "inputBVector")
brightMatrix?.setValue(CIVector (x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
brightMatrix?.setValue(CIVector (x: 32.0/255.0, y: 32.0/255.0, z: 32.0/255.0, w: 0), forKey: "inputBiasVector")

弗兰克提议后的最终解决方案

func zoeFilter() -> UIImage? {
        let inImage = CIImage (image: self)

        dynamic let SRGBMatrix = CIFilter (name: "CILinearToSRGBToneCurve")
        dynamic let brightMatrix = CIFilter (name: "CIColorMatrix")
        dynamic let linearMatrix = CIFilter (name: "CISRGBToneCurveToLinear")

        SRGBMatrix?.setValue(inImage, forKey: kCIInputImageKey)
        let SRGBImage = SRGBMatrix?.outputImage

        brightMatrix?.setDefaults()
        brightMatrix?.setValue(SRGBImage, forKey: kCIInputImageKey)
        brightMatrix?.setValue(CIVector (x: 1, y: 0, z: 0, w: 0), forKey: "inputRVector")
        brightMatrix?.setValue(CIVector (x: 0, y: 1, z: 0, w: 0), forKey: "inputGVector")
        brightMatrix?.setValue(CIVector (x: 0, y: 0, z: 1, w: 0), forKey: "inputBVector")
        brightMatrix?.setValue(CIVector (x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
        brightMatrix?.setValue(CIVector (x: 32.0/255.0, y: 32.0/255.0, z: 32.0/255.0, w: 0), forKey: "inputBiasVector")
        let brightImage = brightMatrix?.outputImage

        linearMatrix?.setDefaults()
        linearMatrix?.setValue(brightImage, forKey: kCIInputImageKey)
        let linearImage = linearMatrix?.outputImage

        let cgImage = CIContext().createCGImage(linearImage!, from: linearImage!.extent)
        return UIImage (cgImage: cgImage!)
    }

您应该也可以通过设置 CIColorMatrix 滤镜的 inputBiasVector 参数来使用亮度和对比度矩阵,如下所示:

// the first 4 should actually be the default, so you probably don't need to set them explicitly
brightMatrix?.setValue(CIVector(x: 1, y: 0, z: 0, w: 0), forKey: "inputRVector")
brightMatrix?.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: "inputGVector")
brightMatrix?.setValue(CIVector(x: 0, y: 0, z: 1, w: 0), forKey: "inputBVector")
brightMatrix?.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
brightMatrix?.setValue(CIVector(x: 32.0/255.0, y: 32.0/255.0, z: 32.0/255.0, w: 0), forKey: "inputBiasVector")

但奇怪的是,您不能使用 CIColorControls 过滤器来实现相同的目的。也许你可以 post 示例图像。