跳转到内容

遮罩(Mask)、形状抠图与条件区域处理

复制本页

在图像处理中,“遮罩(Mask)”本质上是一张单通道(1-band)8-bit 灰度图:值为 255(白色)代表完全选中或完全不透明,值为 0(黑色)代表完全未选中或完全透明,1..254 则代表平滑过渡的羽化边缘。

在 libvips 生态中,实现遮罩抠图与局部区域处理主要有三种模式:

  1. 将灰度遮罩直接附加为图像的 Alpha 通道(BandJoin / joinChannel);
  2. 使用 Porter-Duff dest-in 混合模式按形状裁切底图(BlendModeDestIn);
  3. 根据遮罩在“前景图”与“背景图”之间逐像素条件混合(ifthenelse 或 Alpha 合成)。
以单通道灰度图表示的 Alpha 遮罩
单通道灰度遮罩:PNG640 × 360,1 通道(白=不透明,黑=透明)
将单通道遮罩与 RGB 通道合并后生成的 RGBA 图像
附加遮罩后的输出:PNG640 × 360,4 通道 RGBA

1. 将单通道灰度遮罩附加为 Alpha 通道(BandJoin)

Section titled “1. 将单通道灰度遮罩附加为 Alpha 通道(BandJoin)”

如果你有一张 3 通道 RGB 照片,以及一张同尺寸的 1 通道灰度蒙版(例如由 SVG 光栅化、文字渲染或分割模型生成),可以直接用 BandJoin 把灰度图拼作第 4 个通道(Alpha):

// 确保原图为 3 通道 RGB(若已有 Alpha 则先提取前 3 个通道)
if baseImg.Bands() > 3 {
if err := baseImg.ExtractBand(0, 3); err != nil {
return err
}
}
// 确保 maskImg 为 1 通道灰度图(若为多通道则提取第 0 通道)
if maskImg.Bands() > 1 {
if err := maskImg.ExtractBand(0, 1); err != nil {
return err
}
}
// 将 1 通道遮罩追加为第 4 通道 (RGBA)
if err := baseImg.BandJoin(maskImg); err != nil {
return err
}

2. 使用 SVG 形状与 dest-in 混合模式做圆角或图形抠图

Section titled “2. 使用 SVG 形状与 dest-in 混合模式做圆角或图形抠图”

当遮罩本身是一张带透明通道的 SVG(例如圆角矩形、圆形头像框或复杂矢量徽章)时,最简捷的做法是:先将原图确保为 4 通道 RGBA,然后把 SVG 蒙版以 BlendModeDestIn(dest-in) 合成上去——dest-in 会保留底图的颜色,但将其 Alpha 乘上蒙版的 Alpha:

// 构造一个 500×500 的圆角矩形 SVG 蒙版
svgMask := []byte(`<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" rx="64" ry="64" fill="#ffffff"/>
</svg>`)
mask, err := vips.NewImageFromBuffer(svgMask)
if err != nil {
return err
}
defer mask.Close()
if !cropImg.HasAlpha() {
if err := cropImg.AddAlpha(); err != nil {
return err
}
}
// BlendModeDestIn:仅保留与 SVG 不透明区域重叠的底图像素
if err := cropImg.Composite(mask, vips.BlendModeDestIn, 0, 0); err != nil {
return err
}

3. 局部区域滤镜与条件混合(ifthenelse vs Alpha 合成)

Section titled “3. 局部区域滤镜与条件混合(ifthenelse vs Alpha 合成)”

假设你要实现“背景虚化”或“局部打码”:中心主体保持清晰,其余区域应用高斯模糊。

  • 在 pyvips 与 vips CLI 中,可以直接使用三元条件算子 mask.ifthenelse(sharp_img, blurred_img, blend=True):遮罩值越接近 255 越取 sharp_img,越接近 0 越取 blurred_img,blend=True 会按 0..255 线性插值过渡。
  • 在 govips 与 sharp 中,虽然没有公开导出独立的 Ifthenelse 方法,但将单通道遮罩附加给前景图(BandJoin / joinChannel),再以 BlendModeOver 合成到模糊背景图上,数学效果与 ifthenelse(..., blend=True) 完全一致。
// govips:将灰度遮罩附加为清晰前景的 Alpha,再以 Over 混合到模糊背景图上
if err := foreground.BandJoin(maskGray); err != nil {
return err
}
if err := blurredBg.Composite(foreground, vips.BlendModeOver, 0, 0); err != nil {
return err
}