0

私はこれを試しました:

CIFilter *dodgeFilter = [CIFilter filterWithName:@"CIColorDodgeBlendMode"];

交換する:

GPUImageDivideBlendFilter *divideBlendFilter = [[GPUImageDivideBlendFilter alloc] init];

しかし、効果は同じではありません。

4

3 に答える 3

1

内蔵フィルター

で試しましたCIDivideBlendModeか?

CIImage *img1 = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"img1.jpg"]];
CIImage *img2 = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"img2.jpg"]];

CIFilter *filterBuiltin = [CIFilter filterWithName:@"CIDivideBlendMode"
                                     keysAndValues:@"inputImage", img1,
                                                   @"inputBackgroundImage", img2, nil];
CIImage *outputImageBuiltin = [filterBuiltin outputImage];
UIImage *filteredImageBuiltin = [self imageWithCIImage:outputImageBuiltin];

カスタム フィルタ

CIFilteriOS8 でできるようになった今、既存の GPUImageFilter に基づいてカスタムを作成してみるのは楽しいだろうと思いました。GPUImageFilterこれにより、 anyを対応するものに変換できるようになりCIFilterます。

開始する前に、カスタム フィルターとコア イメージ カーネル言語リファレンスを作成する前に知っておくべきことを確認してください。

GPUImageDivideBlendFilterシェーダーに非常によく似たカスタム カーネルを作成することから始めます。*_branch11 つの例外は、Core Image Kernel 言語でサポートされていないように見える制御フロー部分です*_branch2

CIFilter の作成は簡単です。

  1. ImageDivideBlendFilter.cikernelXcode プロジェクトに新しい (カスタム フィルター カーネル) ファイルを作成します。

    kernel vec4 GPUImageDivideBlendFilter(sampler image1, sampler image2)
    {
        float EPSILON = 1e-4;
        vec4 base = sample(image1, samplerCoord(image1));
        vec4 overlay = sample(image2, samplerCoord(image2));
    
        float ra1 = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
        float ra2 = (base.r * overlay.a * overlay.a) / overlay.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
    
        // https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CIKernelLangRef/ci_gslang_ext.html#//apple_ref/doc/uid/TP40004397-CH206-TPXREF101
        // "Other flow control statements (if, for, while, do while) are supported only when the loop condition can be inferred at the time the code compiles"
        float ra_branch2 = step(EPSILON, overlay.a) * step(base.r / overlay.r, base.a / overlay.a);
        float ra_branch1 = step(ra_branch2, 0.5);
    
        float ra = ra1 * ra_branch1 + ra2 * ra_branch2;
    
    
        float ga1 = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
        float ga2 = (base.g * overlay.a * overlay.a) / overlay.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
    
        float ga_branch2 = step(EPSILON, overlay.a) * step(base.g / overlay.g, base.a / overlay.a);
        float ga_branch1 = step(ga_branch2, 0.5);
    
        float ga = ga1 * ga_branch1 + ga2 * ga_branch2;
    
    
        float ba1 = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
        float ba2 = (base.b * overlay.a * overlay.a) / overlay.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
    
        float ba_branch2 = step(EPSILON, overlay.a) * step(base.b / overlay.b, base.a / overlay.a);
        float ba_branch1 = step(ba_branch2, 0.5);
    
        float ba = ba1 * ba_branch1 + ba2 * ba_branch2;
    
        return vec4(ra, ga, ba, 1.0);
    }
    
  2. フィルターのインターフェースと実装を追加する

    // ImageDivideBlendFilter.h
    #import <CoreImage/CoreImage.h>
    
    @interface ImageDivideBlendFilter : CIFilter
    
    @end
    
    
    // ImageDivideBlendFilter.m
    #import "ImageDivideBlendFilter.h"
    
    @interface ImageDivideBlendFilter()
    {
        CIImage *_image1;
        CIImage *_image2;
    }
    
    @end
    
    @implementation ImageDivideBlendFilter
    
    static CIColorKernel *imageDivideBlendKernel = nil;
    
    + (void)initialize
    {
        // This will load the kernel code which will compiled at run time. We do this just once to optimize performances
        if (!imageDivideBlendKernel)
        {
            NSBundle *bundle = [NSBundle bundleForClass:[self class]];
            NSString *code = [NSString stringWithContentsOfFile:[bundle pathForResource: @"ImageDivideBlendFilter" ofType: @"cikernel"] encoding:NSUTF8StringEncoding error:nil];
            NSArray *kernels = [CIColorKernel kernelsWithString:code];
            imageDivideBlendKernel = [kernels firstObject];
        }
    }
    
    - (CIImage *)outputImage
    {
        return [imageDivideBlendKernel applyWithExtent:_image1.extent roiCallback:nil arguments:@[_image1, _image2]];
    }
    
    + (CIFilter *)filterWithName: (NSString *)name
    {
        CIFilter  *filter;
        filter = [[self alloc] init];
        return filter;
    }
    
    @end
    
  3. 新しく作成したカスタム フィルターをアプリケーションで使用する準備が整いました。

    - (void)filterDemo
    {
        CIImage *img1 = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"img1.jpg"]];
        CIImage *img2 = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"img2.jpg"]];
    
        [ImageDivideBlendFilter class]; // preload kernel, it speeds up loading the filter if used multiple times
    
        CIFilter *filterCustom = [CIFilter filterWithName:@"ImageDivideBlendFilter" keysAndValues:@"image1", img2, @"image2", img1, nil];
        CIImage *outputImageCustom = [filterCustom outputImage];
    
        UIImage *filteredImageCustom = [self imageWithCIImage:outputImageCustom];
    }
    
    - (UIImage *)imageWithCIImage:(CIImage *)ciimage
    {
        CIContext *context = [CIContext contextWithOptions:nil];
        CGImageRef cgimg = [context createCGImage:ciimage fromRect:[ciimage extent]];
        UIImage *newImg = [UIImage imageWithCGImage:cgimg];
    
        CGImageRelease(cgimg);
    
        return newImg;
    }
    

ビルトイン フィルターとカスタム フィルターは同じ結果を生成します。

編集:Swiftバージョン

Swift で CIFiltering を作成する方法を示すサンプル プロジェクトを Github https://github.com/tcamin/CustomCoreImageFilteringDemoで利用できるようにしました。

于 2014-12-03T10:13:21.990 に答える
0

また、これが質問に関係ないことはわかっていますが、これを指摘する必要があると思います.カーネルコードには、特に前乗算関連の関数が1つあります。残りの 3 つとは別にアルファ チャンネルを操作する場合は、サンプラー (またはカラー) オブジェクトの事前乗算を解除します。完成品ができたら、それらを premultiply で再結合します。計算で 2 つのサンプラー (またはカラー) オブジェクトを変更、混合、または使用しない場合は、どちらも行わないでください。

于 2015-05-04T02:32:49.430 に答える
0

回答の CIColorKernel コードは機能しません。実際、複数のサンプラ オブジェクト (イメージ) をカーネルに渡そうとすると失敗します。

于 2015-05-04T02:26:05.663 に答える