【问题标题】:Gradually change color of UIImage from RGB to Grayscale逐渐将 UIImage 的颜色从 RGB 更改为 Grayscale
【发布时间】:2015-11-05 19:53:31
【问题描述】:

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

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

我对此进行了研究,但找不到任何逐渐改变它的答案。显然,一次以光线比例渲染它是可能的。

有没有可能在 Swift 中做到这一点?

编辑

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

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

【问题讨论】:

  • 你能解释一下根据滚动位置改变它的意思吗?您是希望图像的饱和度从左到右逐渐变化,还是希望图像的整个可见部分使用一个随滚动位置而变化的饱和度值?我的回答假设您想要从左到右改变饱和度。西蒙的回答会让你根据滚动位置改变整个当前可见区域的饱和度。
  • @DuncanC 查看我上面的编辑
  • @freshking 您可以使用 CGColorSpaceCreateDeviceGray 创建上下文并在其上绘制图像。这将比过滤器快 10 倍。在我的机器 0.07121700048446655 对 0.6915000081062317 使用 CIColorControls

标签: swift uiimage swift2 rgb grayscale


【解决方案1】:

我尝试即时实现 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
    }
}

【讨论】:

  • 酷。所以你使用了我和西蒙的解决方案的混合体。顺便说一句,您是在设备上还是在模拟器上进行测试?我发现 CI 过滤器在设备上的表现要好得多。
  • 哦,我不知道。当我在模拟器中测试它时,性能太差了,我什至懒得在设备上测试它。我仍然发现问题不在于滤镜,而在于每次更改滤镜时都必须更改图像。当您使用大图像时,这不是很有效。我想这里就是这种情况。
  • 顺便说一句,很高兴提供一个解决方案并让某人去实施它,而不是要求回答者编写代码。
  • 其实我在实现这个的时候还没有看到你的回答。所以这更像是“伟大的思想都一样”的情况;-)
  • 嗨,好东西!我通过在后台线程中进行处理来实时应用核心图像过滤器。我已经能够将它们应用于视频提要,因此如果您再次访问此内容,可能值得考虑。干杯,
【解决方案2】:

可能最简洁的方法是设置一个核心图像过滤器来回拨图像的颜色饱和度。我不太确定“根据滚动位置”更改为灰度是什么意思。你是说你想让你的图像在左边完全饱和,然后在右边完全灰度,从彩色逐渐过渡到黑白?

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

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

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

【讨论】:

    【解决方案3】:

    考虑使用具有饱和度参数的 CoreImage CIColorControls 过滤器。只需将饱和度值与归一化的滚动位置关联起来,瞧,您就有了想要的效果。

    西蒙

    【讨论】:

      猜你喜欢
      • 2015-02-24
      • 2020-05-25
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      相关资源
      最近更新 更多