You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CIFilter randomGenerator()生成胶片颗粒出现网格图案的问题排查

问题:CoreImage实现复古胶片颗粒时出现规律性横竖网格异常

仿照Apple官方文档实现复古胶片颗粒效果,但叠加颗粒并裁剪至原图尺寸时,出现规律性横竖网格状异常图案。该问题在不同尺寸图像中均存在,图像越大图案越明显,小尺寸(如100x100)图像无此问题。已将颗粒效果应用于纯色图展示异常:纯色背景上可见明显的横竖网格状颗粒拼接痕迹。

以下是颗粒生成函数代码:

private func applyRandomGrain() {

/// generate grain & convert to grayscale
    let grainGenerator = CIFilter.randomGenerator()
    let grayscale = CIFilter.minimumComponent()
    grayscale.inputImage = grainGenerator.outputImage

/// adjust brightness of grain image
    let exposureFilter = CIFilter.exposureAdjust()
    exposureFilter.inputImage = grayscale.outputImage
    exposureFilter.ev = Float(settings.grainExposure)

/// adjust intensity of grain image with opacity
    let alphaVector = CIVector(x: 0, y: 0, z: 0, w: settings.grainOpacity)
    let alphaFilter = CIFilter.colorMatrix()
    alphaFilter.inputImage = exposureFilter.outputImage
    alphaFilter.aVector = alphaVector

    guard let inputImage = outputImage else {
        return
    }

/// apply grain image to original image
    let composite = CIFilter.sourceOverCompositing()
    composite.backgroundImage = inputImage
    composite.inputImage = alphaFilter.outputImage

    guard let imageWithGrain = composite.outputImage else {
        return
    }

    outputImage = imageWithGrain.cropped(to: inputImage)
}

原因分析

CIFilter.randomGenerator()生成的是周期性重复的随机纹理,它的默认输出是固定尺寸的tile(通常为512x512)。当叠加到比tile大的图像上时,CoreImage会自动重复这个tile来覆盖整个区域,从而产生明显的网格状拼接痕迹——这就是你看到的横竖异常图案。小尺寸图像因为小于tile尺寸,不会触发重复,因此无此问题。

解决方法

让随机纹理生成器直接输出与原图尺寸匹配的纹理,从源头避免tile重复。修改后的代码如下:

private func applyRandomGrain() {
    guard let inputImage = outputImage else {
        return
    }
    
    /// 生成匹配原图尺寸的随机颗粒并转为灰度
    let grainGenerator = CIFilter.randomGenerator()
    let extent = inputImage.extent
    // 缩放随机纹理到原图尺寸
    grainGenerator.transform = CGAffineTransform(scaleX: extent.width, y: extent.height)
    
    let grayscale = CIFilter.minimumComponent()
    grayscale.inputImage = grainGenerator.outputImage

    /// 调整颗粒亮度
    let exposureFilter = CIFilter.exposureAdjust()
    exposureFilter.inputImage = grayscale.outputImage
    exposureFilter.ev = Float(settings.grainExposure)

    /// 调整颗粒透明度
    let alphaVector = CIVector(x: 0, y: 0, z: 0, w: settings.grainOpacity)
    let alphaFilter = CIFilter.colorMatrix()
    alphaFilter.inputImage = exposureFilter.outputImage
    alphaFilter.aVector = alphaVector

    /// 叠加颗粒到原图
    let composite = CIFilter.sourceOverCompositing()
    composite.backgroundImage = inputImage
    composite.inputImage = alphaFilter.outputImage

    guard let imageWithGrain = composite.outputImage else {
        return
    }

    outputImage = imageWithGrain.cropped(to: inputImage)
}

关键修改说明

  • 提前获取原图的extent(范围),计算缩放变换并赋值给randomGenerator的transform属性,让随机纹理直接覆盖整个原图区域,避免后续重复拼接。
  • 将获取inputImage的逻辑前置,确保生成颗粒时就能匹配原图尺寸,流程更合理。

如果不想调整生成器变换,也可以用CIAffineClamp滤镜包裹颗粒纹理,防止CoreImage重复tile,但直接调整生成器变换是更高效的方案。


内容的提问来源于stack exchange,提问作者Trevor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 08:47:10