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

如何为含不同灰度值的图像应用蒙版?仅去除纯黑色区域

解决蒙版仅移除纯黑色区域的问题

我需要将一张带有灰色区域的蒙版应用到原始图像,要求保留除纯黑色以外的所有内容,但找到的代码效果相反,会移除白色像素。当前用该代码处理纯色背景时,灰色区域会出现孔洞,不符合需求。

现有问题代码

func maskImage(image: UIImage, mask: UIImage) -> UIImage {
    let imageReference = (image.cgImage)!
    let maskReference = (mask.cgImage)!

    let imageMask = CGImage(
        maskWidth: maskReference.width
        , height: maskReference.height
        , bitsPerComponent: maskReference.bitsPerComponent
        , bitsPerPixel: maskReference.bitsPerPixel
        , bytesPerRow: maskReference.bytesPerRow
        , provider: maskReference.dataProvider!
        , decode: nil
        , shouldInterpolate: true
    )

    return (UIImage(cgImage: (imageReference.masking(imageMask!))!))
}

问题原因

CGImage的masking(_:)方法遵循灰度蒙版规则:

  • 纯黑色(像素值0):完全透明,移除原图对应区域
  • 纯白色(像素值255):完全不透明,保留原图对应区域
  • 灰色(0-255之间):半透明,原图对应区域会出现透明度

现有代码直接使用原蒙版,若蒙版中存在白色/灰色区域,会导致对应原图区域被透明/半透明,和需求完全相反。我们需要的是仅让蒙版的纯黑色区域对应原图透明,其他所有区域(灰、白)都完全保留,因此必须先预处理蒙版,将所有非纯黑的像素转为纯白色。

解决方案代码

func maskImageKeepNonBlack(image: UIImage, mask: UIImage) -> UIImage? {
    guard let maskCG = mask.cgImage else { return nil }
    let maskSize = CGSize(width: maskCG.width, height: maskCG.height)
    
    // 创建灰度色彩空间,用于处理蒙版
    guard let colorSpace = CGColorSpaceCreateDeviceGray() else { return nil }
    // 创建单通道灰度位图上下文
    guard let context = CGContext(
        data: nil,
        width: Int(maskSize.width),
        height: Int(maskSize.height),
        bitsPerComponent: 8,
        bytesPerRow: Int(maskSize.width),
        space: colorSpace,
        bitmapInfo: CGImageAlphaInfo.none.rawValue
    ) else { return nil }
    
    // 将原蒙版绘制到灰度上下文
    context.draw(maskCG, in: CGRect(origin: .zero, size: maskSize))
    
    // 获取并修改像素数据:仅保留纯黑,其余转为纯白
    guard let pixelData = context.data else { return nil }
    let pixels = pixelData.bindMemory(to: UInt8.self, capacity: Int(maskSize.width * maskSize.height))
    
    for i in 0..<pixels.count {
        // 非纯黑像素全部设为255(纯白)
        if pixels[i] != 0 {
            pixels[i] = 255
        }
    }
    
    // 创建处理后的蒙版CGImage
    guard let processedMask = context.makeImage() else { return nil }
    // 创建符合mask要求的CGImage
    guard let imageMask = CGImage(
        maskWidth: processedMask.width,
        height: processedMask.height,
        bitsPerComponent: processedMask.bitsPerComponent,
        bitsPerPixel: processedMask.bitsPerPixel,
        bytesPerRow: processedMask.bytesPerRow,
        provider: processedMask.dataProvider!,
        decode: nil,
        shouldInterpolate: true
    ) else { return nil }
    
    // 应用蒙版到原图
    guard let originalCG = image.cgImage, let maskedCG = originalCG.masking(imageMask) else { return nil }
    return UIImage(cgImage: maskedCG)
}

代码说明

  1. 蒙版预处理:将原蒙版转为单通道灰度图,遍历所有像素,仅保留纯黑色(值为0),其他像素统一设为255(纯白色)。
  2. 蒙版应用:使用处理后的蒙版调用masking(_:),此时只有蒙版纯黑对应的原图区域会被移除,其余区域完全保留,不会出现灰色孔洞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:25:19