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

如何实现图像Masked Blur效果:保留指定清晰区域并添加边框

实现局部清晰+全局模糊的可行思路

嘿,我之前刚好做过类似的需求,踩过一些坑,给你几个亲测可行的实现思路,应该能解决你的问题:

思路一:Stack + ClipPath 组合(最直观易上手)

这个思路的核心是分层控制显示区域:底层放全图模糊效果,上层只显示清晰图的ROI区域,最后叠加边框。完全避开了你之前遇到的“模糊图覆盖清晰区域”的问题。

具体步骤:

  • 第一层:放模糊处理后的完整图像
  • 第二层:放原始清晰图像,用ClipPath裁剪出你需要的感兴趣区域(ROI),这样只有ROI部分会显示清晰图,其他区域会被裁剪掉,露出底层的模糊图
  • 第三层:在ROI的位置放一个带边框的容器,实现高亮效果

代码示例(Flutter环境):

Stack(
  children: [
    // 底层:全图模糊
    ImageFiltered(
      imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
      child: Image.asset('assets/your_image.jpg'),
    ),
    // 中层:裁剪出清晰的ROI
    ClipPath(
      clipper: _ROIClipper(roiRect: Rect.fromLTWH(100, 100, 200, 200)),
      child: Image.asset('assets/your_image.jpg'),
    ),
    // 顶层:ROI边框
    Positioned.fromRect(
      rect: Rect.fromLTWH(100, 100, 200, 200),
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.redAccent, width: 2),
        ),
      ),
    ),
  ],
)

// 自定义裁剪器,只保留ROI区域
class _ROIClipper extends CustomClipper<Path> {
  final Rect roiRect;

  _ROIClipper({required this.roiRect});

  @override
  Path getClip(Size size) {
    final path = Path();
    path.addRect(roiRect);
    return path;
  }

  @override
  bool shouldReclip(covariant _ROIClipper oldClipper) {
    return oldClipper.roiRect != roiRect;
  }
}

思路二:ExcludeClipPath 反向控制(更高效的图层复用)

如果不想重复加载两次图像,这个思路更合适:只加载一次清晰图,然后用ExcludeClipPath让模糊效果避开ROI区域。

原理:

  • 底层放原始清晰图
  • 上层放模糊后的图像,但用ExcludeClipPath排除掉ROI区域,这样ROI部分不会被模糊图覆盖,依然显示清晰的底层图像
  • 最后叠加边框

代码示例:

Stack(
  children: [
    // 底层:原始清晰图
    Image.asset('assets/your_image.jpg'),
    // 上层:模糊图,但排除ROI区域
    ExcludeClipPath(
      clipPath: _ROIClipper(roiRect: Rect.fromLTWH(100, 100, 200, 200)),
      child: ImageFiltered(
        imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
        child: Container(
          width: double.infinity,
          height: double.infinity,
          color: Colors.transparent,
          child: Image.asset('assets/your_image.jpg', fit: BoxFit.fill),
        ),
      ),
    ),
    // ROI边框
    Positioned.fromRect(
      rect: Rect.fromLTWH(100, 100, 200, 200),
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.blueAccent, width: 2),
        ),
      ),
    ),
  ],
)

思路三:CustomPainter 直接绘制(最灵活的方案)

你之前尝试CustomPainter没成功,大概率是绘制顺序或者模糊效果的应用方式不对。这个方案直接在画布上控制每一步的绘制,适合需要动态调整ROI或者模糊参数的场景。

核心步骤:

  1. 先绘制整个模糊后的图像
  2. 再在ROI位置绘制原始清晰的图像区域
  3. 最后绘制ROI的边框

代码示例:

// 注意:需要先通过ImageProvider获取ui.Image对象
CustomPaint(
  painter: _ROIBlurPainter(
    image: _loadedImage, // 预加载好的ui.Image
    roiRect: Rect.fromLTWH(100, 100, 200, 200),
    blurSigma: 5,
  ),
  child: SizedBox(
    width: _loadedImage.width.toDouble(),
    height: _loadedImage.height.toDouble(),
  ),
)

class _ROIBlurPainter extends CustomPainter {
  final ui.Image image;
  final Rect roiRect;
  final double blurSigma;

  _ROIBlurPainter({
    required this.image,
    required this.roiRect,
    required this.blurSigma,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 1. 绘制全图模糊效果
    final blurPaint = Paint()
      ..imageFilter = ImageFilter.blur(sigmaX: blurSigma, sigmaY: blurSigma);
    canvas.drawImage(image, Offset.zero, blurPaint);

    // 2. 绘制清晰的ROI区域
    final srcRect = roiRect; // 假设图像尺寸和画布一致,若不一致需做坐标转换
    final dstRect = roiRect;
    canvas.drawImageRect(image, srcRect, dstRect, Paint());

    // 3. 绘制ROI边框
    final borderPaint = Paint()
      ..color = Colors.greenAccent
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;
    canvas.drawRect(roiRect, borderPaint);
  }

  @override
  bool shouldRepaint(covariant _ROIBlurPainter oldDelegate) {
    return oldDelegate.image != image ||
        oldDelegate.roiRect != roiRect ||
        oldDelegate.blurSigma != blurSigma;
  }
}

为什么你之前的叠加方法不可行?

直接把清晰图叠在模糊图上的话,清晰图会覆盖整个画布,包括非ROI区域,所以看不到模糊效果。而上面的思路都是通过裁剪/排除区域的方式,让清晰图只在ROI区域显示,非ROI区域露出模糊图,完美解决了覆盖问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:02:46