我正试图获得类似于只使用CIImage过滤器的彩色遮罩的东西。
基本上,我希望所有的黑色像素都是透明的。我不介意所有非黑色像素最终会有什么颜色,只要它们有最大的alpha。
我在Core Graphics中熟悉的实现这一目标的代码看起来像:
// Convert black sections to transparent using a color mask
const CGFloat maskingColors[6] = { 0, 0, 0, 0, 0, 0 };
CGImageRef result = CGImageCreateWithMaskingColors(image, maskingColors);
我在Core Image中使用了一个彩色矩阵滤波器对其进行了拍摄,但它只是将result
设置为nil
,因为CIVector值大于1.0f
。
// Create color matrix filter
CIFilter *matrix = [CIFilter filterWithName:@"CIColorMatrix"];
// Set filter properties
[matrix setValue:image forKey:kCIInputImageKey];
[matrix setValue:[CIVector vectorWithX:1.0f Y:0.0f Z:0.0f W:0.0f] forKey:@"inputRVector"];
[matrix setValue:[CIVector vectorWithX:0.0f Y:1.0f Z:0.0f W:0.0f] forKey:@"inputGVector"];
[matrix setValue:[CIVector vectorWithX:0.0f Y:0.0f Z:1.0f W:0.0f] forKey:@"inputBVector"];
[matrix setValue:[CIVector vectorWithX:255.0f Y:255.0f Z:255.0f W:0.0f] forKey:@"inputAVector"];
// Get the mapped image
CIImage *result = [matrix valueForKey:kCIOutputImageKey];
注意:就其价值而言,这是一个OSX应用程序
编辑
使用(简单)自定义CIFilter的解决方案。此方法仅适用于OSX,因为iOS不支持自定义过滤器:
CIFilter子类(或多或少是苹果的How To的副本):
#import <QuartzCore/QuartzCore.h>
@interface MaskFilter : CIFilter {
CIImage *inputImage;
}
@end
@implementation MaskFilter
static CIKernel *maskFilterKernel = nil;
+ (void)initialize {
[CIFilter registerFilterName: @"MaskFilter"
constructor: (id)self
classAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
@"Mask Filter", kCIAttributeFilterDisplayName,
[NSArray arrayWithObjects:
kCICategoryColorAdjustment,
kCICategoryStillImage, kCICategoryInterlaced,
kCICategoryNonSquarePixels,nil], kCIAttributeFilterCategories,
nil]
];
}
+ (CIFilter *)filterWithName:(NSString *)name {
CIFilter *filter;
filter = [[self alloc] init];
return filter;
}
- (id)init {
if(maskFilterKernel == nil) {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *code = [NSString stringWithContentsOfFile:[bundle pathForResource:@"MaskFilter" ofType: @"cikernel"] encoding:NSUTF8StringEncoding error:nil];
NSArray *kernels = [CIKernel kernelsWithString:code];
maskFilterKernel = [kernels objectAtIndex:0];
}
return [super init];
}
- (CIImage *)outputImage {
CISampler *src = [CISampler samplerWithImage: inputImage];
return [self apply:maskFilterKernel, src, kCIApplyOptionDefinition, [src definition], nil];
}
@end
完成所有工作的自定义内核(文件名:MaskFilter.cikernel)
kernel vec4 maskFilterKernel(sampler src)
{
vec4 t = sample(src, destCoord());
t.w = (t.x == 0.0 ? (t.y == 0.0 ? (t.z == 0.0 ? 0.0 : 1.0) : 1.0) : 1.0);
return t;
}
使用Filter的工作原理就像内置的Filter:
CIFilter *filter = [MaskFilter filterWithName:@"MaskFilter"];
[filter setValue:ciImage forKey:@"inputImage"];
CIImage *mask = [filter valueForKey: @"outputImage"];
添加一个参数来选择要用作遮罩颜色的颜色应该没有问题。
旧答案
有了内置的方法和类,我只能想出这个相当不合法的解决方案(它只使用核心图像过滤器):
// convert all colors so they are brighter or equal to 0.5, except black
CIFilter *binary = [CIFilter filterWithName:@"CIColorMatrix"];
[binary setValue:inputImage forKey:@"inputImage"];
[binary setValue:[CIVector vectorWithX:1 Y:1 Z:1 W:0] forKey:@"inputRVector"];
[binary setValue:[CIVector vectorWithX:1 Y:1 Z:1 W:0] forKey:@"inputGVector"];
[binary setValue:[CIVector vectorWithX:1 Y:1 Z:1 W:0] forKey:@"inputBVector"];
[binary setValue:[CIVector vectorWithX:0.49999 Y:0.49999 Z:0.49999 W:0] forKey:@"inputBiasVector"];
inputImage = [binary valueForKey:@"outputImage"];
// convert to black/white only colors
binary = [CIFilter filterWithName:@"CIColorPosterize"];
[binary setDefaults];
[binary setValue:inputImage forKey:@"inputImage"];
[binary setValue:@2 forKey:@"inputLevels"];
inputImage = [binary valueForKey:@"outputImage"];
// get mask
CIFilter *mask = [CIFilter filterWithName:@"CIMaskToAlpha"];
[mask setDefaults];
[mask setValue: inputImage forKey:@"inputImage"];
它将黑色转换为透明,将任何其他颜色转换为白色
func filteredImage(cgImage: CGImage) -> UIImage {
if let matrixFilter = CIFilter(name: "CIColorMatrix") {
matrixFilter.setDefaults()
matrixFilter.setValue(CIImage(cgImage: cgImage), forKey: kCIInputImageKey)
let rgbVector = CIVector(x: 0, y: 0, z: 0, w: 0)
let aVector = CIVector(x: 1, y: 1, z: 1, w: 0)
matrixFilter.setValue(rgbVector, forKey: "inputRVector")
matrixFilter.setValue(rgbVector, forKey: "inputGVector")
matrixFilter.setValue(rgbVector, forKey: "inputBVector")
matrixFilter.setValue(aVector, forKey: "inputAVector")
matrixFilter.setValue(CIVector(x: 1, y: 1, z: 1, w: 0), forKey: "inputBiasVector")
if let matrixOutput = matrixFilter.outputImage, let cgImage = CIContext().createCGImage(matrixOutput, from: matrixOutput.extent) {
return UIImage(cgImage: cgImage)
}
}
return self
}
}