在Swift中为UIImage着色 [英] Colorize a UIImage in Swift

查看:359
本文介绍了在Swift中为UIImage着色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个辅助函数,该函数将色罩应用于给定的图像.我的功能必须将图像的所有不透明像素设置为相同的颜色.

I am trying to write an helper function that applies a color mask to a given image. My function has to set all opaque pixels of an image to the same color.

这是我到目前为止所拥有的:

Here is what I have so far :

extension UIImage {

    func applyColorMask(color: UIColor, context: CIContext) -> UIImage {

        guard let cgImageInput = self.cgImage else {
            print("applyColorMask: \(self) has no cgImage attribute.")
            return self
        }

        // Throw away existing colors, and fill the non transparent pixels with the input color
        // s.r = dot(s, redVector), s.g = dot(s, greenVector), s.b = dot(s, blueVector), s.a = dot(s, alphaVector)
        // s = s + bias
        let colorFilter = CIFilter(name: "CIColorMatrix")!
        let ciColorInput = CIColor(cgColor: color.cgColor)
        colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputRVector")
        colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputGVector")
        colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputBVector")
        colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
        colorFilter.setValue(CIVector(x: ciColorInput.red, y: ciColorInput.green, z: ciColorInput.blue, w: 0), forKey: "inputBiasVector")
        colorFilter.setValue(CIImage(cgImage: cgImageInput), forKey: kCIInputImageKey)

        if let cgImageOutput = context.createCGImage(colorFilter.outputImage!, from: colorFilter.outputImage!.extent) {
            return UIImage(cgImage: cgImageOutput)
        } else {
            print("applyColorMask: failed to apply filter to \(self)")
            return self
        }
    }
}

该代码对黑白效果很好,但在应用更有趣的颜色时效果不理想.请参阅原始图像和下面的屏幕截图:边框和图像使用相同的颜色.尽管它们是不同的.我的功能做错了.我是否错过了滤波器矩阵中的某些内容?

The code works fine for black and white but not what I expected when applying funnier colors. See the original image and the screenshots below: the same color is used for the border and for the image. Though they're different. My function is doing wrong. Did I miss something in the filter matrix ?

原始图像(中间有白点):

The original image (there's white dot at the center):

从上到下:用UIColor(1.0, 1.0, 1.0, 1.0)过滤的图像插入到具有相同颜色边框的UIImageView中.然后与UIColor(0.6, 0.5, 0.4, 1.0)相同.最后是UIColor(0.2, 0.5, 1.0, 1.0)

From top to bottom: The image filtered with UIColor(1.0, 1.0, 1.0, 1.0) inserted into a UIImageView which has borders of the same color. Then the same with UIColor(0.6, 0.5, 0.4, 1.0). And finally with UIColor(0.2, 0.5, 1.0, 1.0)

编辑

运行 Filterpedia 也能得到相同的结果.我对CIColorMatrix过滤器的理解可能是错误的. 文档说:

Running Filterpedia gives me the same result. My understanding of the CIColorMatrix filter may be wrong then. The documentation says:

此过滤器执行如下的矩阵乘法以进行变换 颜色向量:

This filter performs a matrix multiplication, as follows, to transform the color vector:

  • s.r =点(s,redVector)
  • s.g =点(s,greenVector)
  • s.b =点(s,blueVector)
  • s.a =点(s,alphaVector)
  • s = s +偏见
  • s.r = dot(s, redVector)
  • s.g = dot(s, greenVector)
  • s.b = dot(s, blueVector)
  • s.a = dot(s, alphaVector)
  • s = s + bias

然后,假设我用(0,0,0,0)vectros抛出了所有RGB数据,然后将(0.5,0,0,0)中红作为偏移矢量;我希望图像的所有完全不透明像素为(127,0,0).下面的屏幕截图显示它稍微更轻(红色= 186):

Then, let say I throw up all RGB data with (0,0,0,0) vectros, and then pass (0.5, 0, 0, 0) mid-red as the bias vector; I would expect my image to have all its fully opaque pixels to (127, 0, 0). The screenshots below shows that it is slightly lighter (red=186):

这是我想做的一些伪代码:

Here is some pseudo code I want to do:

// image "im" is a vector of pixels
// pixel "p" is struct of rgba values
// color "col" is the input color or a struct of rgba values
for (p in im) {
    p.r = col.r
    p.g = col.g
    p.b = col.b
    // Nothing to do with the alpha channel
}

推荐答案

我终于按照@dfd的建议编写了一个CIColorKernel,它工作正常:

I finally wrote a CIColorKernel, as @dfd suggested and it works fine:

class ColorFilter: CIFilter {

    var inputImage: CIImage?
    var inputColor: CIColor?

    let kernel: CIColorKernel = {
        let kernelString = "kernel vec4 colorize(__sample pixel, vec4 color)\n"
            + "{\n"
            + "    pixel.rgb = color.rgb;\n"
            + "    return pixel;\n"
            + "}\n"

        return CIColorKernel(source: kernelString)!
    }()

    override var outputImage: CIImage? {

        guard let inputImage = inputImage else {
            print("\(self) cannot produce output because no input image provided.")
            return nil
        }
        guard let inputColor = inputColor else {
            print("\(self) cannot produce output because no input color provided.")
            return nil
        }

        let inputs = [inputImage, inputColor] as [Any]
        return kernel.apply(extent: inputImage.extent, arguments: inputs)
    }
}


总而言之,我首先使用的CIColorMatrix似乎不是线性的(使用偏置矢量时).赋予红色0.5(浮点)值不会在[0-255]间隔内输出红色127色的图像.


To summarize, the CIColorMatrix I used first seems not to be linear (when using the bias vector). Giving a red 0,5 (float) value did not output an image with red 127 color in the [0-255] interval.

编写自定义过滤器是我的解决方案.

Writing a custom filter was my solution.

这篇关于在Swift中为UIImage着色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆