逐渐将 UIImage 的颜色从 RGB 更改为灰度

Gradually change color of UIImage from RGB to Grayscale

我在 UIScrollView 中有一个 UIImage,可以从一端滚动到另一端。假设左边是 0.0%,右边是 100.0%。

UIImage 是 RGB 范围内的彩色图像,我想根据滚动位置逐渐变为灰度。

我对此进行了研究,但找不到逐步更改它的任何答案。显然可以立即以光线比例渲染它。

是否可以在 Swift 中执行此操作?

编辑

感谢邓肯提供技术上正确的答案。这确实有效,但不幸的是它在滚动时滞后。这就是为什么我使用 Joerns 解决方案将两张图像放在彼此上方(一张彩色图像和一张灰度图像)并相应地更改 alpha 值。 如果有人想要 Duncan 的建议代码,请点击此处:

if let image = image
{
    let icon = CIImage(CGImage: image)

    if let filter = CIFilter(name: "CIColorControls")
    {
        filter.setValue(icon, forKey: kCIInputImageKey)
        filter.setValue(0.0, forKey: kCIInputSaturationKey)

        if let ciImage = filter.outputImage
        {
            let context = CIContext(options:nil)
            let cgImage = context.createCGImage(ciImage, fromRect: ciImage.extent)

            imageView.image = UIImage(CIImage: cgImage)
        }
    }
}

最简洁的方法可能是设置一个 Core Image 滤镜来降低图像的色彩饱和度。我不太清楚你所说的更改为灰度 "depending on the scroll position" 是什么意思。你是说你想让你的图像在左边完全饱和,然后在右边完全灰度化,从彩色到黑白逐渐过渡?

为了获得这种效果,我可能会执行以下操作:

使用核心图像滤镜创建灰度图像版本。 将彩色图像放在底部,黑白图像放在顶部。然后创建一个线性渐变并将其应用到顶部图像的遮罩层。最终效果是顶部的黑白图像将完全覆盖不透明的彩色图像,并完全暴露透明的彩色图像,并且您会看到 2 的混合,其中黑白图像部分透明。

您可能也可以通过堆叠多个 Core Image 滤镜来获得相同的效果,但我以前没有实际这样做过,只是阅读一下。

考虑使用具有饱和度参数的 CoreImage CIColorControls 滤镜。只需 link 标准化滚动位置的饱和度值,瞧,您就会得到想要的效果。

西蒙

我试图即时实现 CoreImage 过滤器,但性能很糟糕。所以我最终得到了一张彩色图像和一张灰度图像。两个图像视图都是堆叠在一起的,并且它们的 alpha 根据滚动位置而改变。当您滚动时,结果是从彩色到灰度的平滑过渡:

class ViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet weak var scrollView: UIScrollView!
    let cgImage = UIImage(named: "image.jpg")!.CGImage!
    let colorImage = UIImageView()
    let grayscaleImage = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()

        let image = UIImage(named: "image.jpg")!
        colorImage.image = image
        scrollView.addSubview(colorImage)

        let beginImage = CIImage(CGImage: cgImage)
        let filter = CIFilter(name: "CIColorControls")!
        filter.setValue(beginImage, forKey: kCIInputImageKey)
        filter.setValue(0, forKey: kCIInputSaturationKey)
        grayscaleImage.image = UIImage(CIImage: filter.outputImage!)
        scrollView.addSubview(grayscaleImage)

        scrollView.contentSize = image.size
        colorImage.frame = CGRectMake(0, 0, image.size.width, image.size.height)
        grayscaleImage.frame = CGRectMake(0, 0, image.size.width, image.size.height)
    }

    func scrollViewDidScroll(scrollView: UIScrollView) {
        let percentage = scrollView.contentOffset.x / (scrollView.contentSize.width - scrollView.bounds.size.width)
        colorImage.alpha = percentage
        grayscaleImage.alpha = 1 - percentage
    }
}