【问题标题】:Does anybody have samples of using CoreImage CICategoryTransition filters in iOS?有人有在 iOS 中使用 CoreImage CICategoryTransition 过滤器的示例吗?
【发布时间】:2014-05-05 01:12:18
【问题描述】:

Apple 在 iOS 6 中添加了许多“过渡”核心图像过滤器(在 CICategoryTransition 类别中)。

有没有人知道一个示例项目,它展示了如何使用它们来实际生成图像之间的实时过渡?

到目前为止,我在 iOS 中使用 CI 过滤器的唯一方法是传入源 CIImage,设置各种参数,然后向过滤器询问它的输出 CIImage。

根据我的经验,这相当慢。过滤器的 CICategoryTransition 类别具有时间属性。关于如何使用它的文档非常很薄,但我假设您将时间参数从 0(过渡开始)更改为 1.0(过渡结束),并在指定的阶段。但是,我认为这不足以生成流畅动画所需的 30 FPS。

【问题讨论】:

    标签: ios objective-c core-image cifilter


    【解决方案1】:

    我不同意文档“很薄”。我从Core Image Programming Guide得到这一切

    转换过滤器需要以下任务:

    1. 创建核心图像图像(CIImage 对象)以用于 过渡。

    2. 设置和安排计时器。

    3. 创建一个 CIContext 对象。

    4. 为滤镜创建一个 CIFilter 对象以应用于图像。

    5. 在 OS X 上,设置过滤器的默认值。

    6. 设置过滤器参数。

    7. 设置要处理的源图像和目标图像。

    8. 计算时间。

    9. 应用过滤器。

    10. 绘制结果。

    11. 重复步骤 8-10,直到转换完成。

    获取图像并设置计时器

    - (void)awakeFromNib {
    
    NSTimer    *timer;
    NSURL      *url;
    
    thumbnailWidth  = 340.0;
    thumbnailHeight = 240.0;
    
    url   = [NSURL fileURLWithPath: [[NSBundle mainBundle]
                    pathForResource: @"boots" ofType: @"jpg"]];
    [self setSourceImage: [CIImage imageWithContentsOfURL: url]];
    
    url   = [NSURL fileURLWithPath: [[NSBundle mainBundle]
                    pathForResource: @"skier" ofType: @"jpg"]];
    [self setTargetImage: [CIImage imageWithContentsOfURL: url]];
    
    timer = [NSTimer scheduledTimerWithTimeInterval: 1.0/30.0
                                             target: self
                                           selector: @selector(timerFired:)
                                           userInfo: nil
                                            repeats: YES];
    
    base = [NSDate timeIntervalSinceReferenceDate];
    [[NSRunLoop currentRunLoop] addTimer: timer
                                 forMode: NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] addTimer: timer
                                 forMode: NSEventTrackingRunLoopMode];
    }
    

    设置过渡过滤器

    - (void)setupTransition {
    CGFloat w = thumbnailWidth;
    CGFloat h = thumbnailHeight;
    
    CIVector *extent = [CIVector vectorWithX: 0  Y: 0  Z: w  W: h];
    
    transition  = [CIFilter filterWithName: @"CICopyMachineTransition"];
    // Set defaults on OS X; not necessary on iOS.
    [transition setDefaults];
    [transition setValue: extent forKey: kCIInputExtentKey];
    }
    

    drawRect:复制机转场效果的方法

    - (void)drawRect: (NSRect)rectangle {
    CGRect  cg = CGRectMake(NSMinX(rectangle), NSMinY(rectangle),
                            NSWidth(rectangle), NSHeight(rectangle));
    
    CGFloat t = 0.4 * ([NSDate timeIntervalSinceReferenceDate] - base);
    if (context == nil) {
        context = [CIContext contextWithCGContext:
                        [[NSGraphicsContext currentContext] graphicsPort]
                                          options: nil];
    }
    if (transition == nil) {
        [self setupTransition];
    }
    [context drawImage: [self imageForTransition: t + 0.1]
                inRect: cg
              fromRect: cg];
    }
    

    应用过渡过滤器

    - (CIImage *)imageForTransition: (float)t {
    
    // Remove the if-else construct if you don't want the transition to loop
    if (fmodf(t, 2.0) < 1.0f) {
        [transition setValue: sourceImage  forKey: kCIInputImageKey];
        [transition setValue: targetImage  forKey: kCIInputTargetImageKey];
    } else {
        [transition setValue: targetImage  forKey: kCIInputImageKey];
        [transition setValue: sourceImage  forKey: kCIInputTargetImageKey];
    }
    
    [transition setValue: @( 0.5 * (1 - cos(fmodf(t, 1.0f) * M_PI)) )
                  forKey: kCIInputTimeKey];
    
    CIFilter  *crop = [CIFilter filterWithName: @"CICrop"
                                 keysAndValues:
                   kCIInputImageKey, [transition valueForKey: kCIOutputImageKey],
                   @"inputRectangle", [CIVector vectorWithX: 0  Y: 0
                                       Z: thumbnailWidth  W: thumbnailHeight],
                   nil];
    return [crop valueForKey: kCIOutputImageKey];
    }
    

    使用定时器更新显示

    - (void)timerFired: (id)sender {
    [self setNeedsDisplay: YES];
    }
    

    设置源图像和目标图像

    - (void)setSourceImage: (CIImage *)source {
    sourceImage = source;
    }
    
    - (void)setTargetImage: (CIImage *)target {
    targetImage = target;
    }
    

    我还建议看下面的项目示例CITransitionSelectorSample

    【讨论】:

    • 我整理了与上面非常相似的代码。我希望有更好的表现。上面的代码为过渡中的每一帧创建一个新的 CIImage,这很慢。我编写了代码来处理视频并识别其中的面孔,为此,我能够将传入“原始”视频和传出处理视频的 CVPixelBuffers 映射到 OpenGL 纹理,以便它们实际上使用相同的内存。像素缓冲区在整个视频处理过程中持续存在,因此不需要为每一帧分配新的缓冲区。我希望 CI 转换过滤器有类似的东西
    • 啊,我会继续调查的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 2020-07-01
    • 2012-04-29
    相关资源
    最近更新 更多