【问题标题】:Make all black pixels transparent using CIImage使用 CIImage 使所有黑色像素透明
【发布时间】:2019-11-12 19:48:31
【问题描述】:

我正在尝试使用专门的 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 应用程序。

【问题讨论】:

  • 您需要一个简单的解决方案还是最快的解决方案?我曾经遇到过这样的问题,我建议你使用 openGL 进行快速图像重绘,因为你不能只在上面绘制透明像素。
  • 目前是简单的解决方案,但如果您有关于 OpenGL 的提示,那也很好。理想情况下,在这个问题的范围内,我们应该将所有内容都保留在 CIImage 中(以帮助其他人)。
  • 你看过CIFilterCIMaskToAlphaCIColorMap吗?
  • CIMaskToAlpha 如果我们能以严格的纯黑/白(无灰色)获得原始图像,则将起作用。对如何编码的建议持开放态度。 CIColorMap 映射到我认为在这种情况下没有帮助的渐变。
  • 您是否可以选择使用自定义 CIFilter?

标签: objective-c core-image


【解决方案1】:

编辑

使用(简单)自定义 CIFilter 的解决方案。此方法仅适用于 OSX,因为 iOS 不支持自定义过滤器:

CIFilter 子类(或多或少是Apple's 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;
}

使用过滤器就像一个内置过滤器:

CIFilter *filter = [MaskFilter filterWithName:@"MaskFilter"];
[filter setValue:ciImage forKey:@"inputImage"];
CIImage *mask = [filter valueForKey: @"outputImage"];

添加一个参数来选择用作遮罩颜色的颜色应该没问题。

老答案

使用内置方法和类,我只能想出这个相当不雅的解决方案(仅使用 Core Image 过滤器):

// 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"];

【讨论】:

  • 谢谢伙计!自定义过滤器为我打开了一个充满可能性的世界:) 关于如何创建自定义过滤器以输出单像素结果(如 CIAreaMaximumAlpha)的任何提示?
  • 您可以定义输出大小以匹配与输入大小不同的内容。但是由于 Core Image 不支持动态循环(仅具有编译时条件的循环),您将不得不考虑一些智能减少,而不会在步骤之间丢失信息。看看this article Section 26.2.2
【解决方案2】:

它将黑色转换为透明,将任何其他颜色转换为白色

    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
    }
}

【讨论】:

    猜你喜欢
    • 2016-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 2021-09-04
    • 2020-02-14
    相关资源
    最近更新 更多