在Swift中为UIImage着色 [英] Colorize a UIImage in Swift
问题描述
我正在尝试编写一个辅助函数,该函数将色罩应用于给定的图像.我的功能必须将图像的所有不透明像素设置为相同的颜色.
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屋!