Rust图像处理第7节-马赛克像素化:分块取平均色实现打码风格

🦀 Rust + WASM 实战系列 第 7 篇 阅读时间:约 5 分钟 | 实战可运行

📌 写在前面

模糊是把像素"柔化",马赛克是把像素"涂掉" ------同一块内全变成一个颜色

原理极简:分块 → 算块平均色 → 整块涂成平均色。3 个步骤搞定。


🚀 TL;DR

scss 复制代码
原图        分块 (10×10)       每块取平均色          输出
██████      ██ ██ ██ ██        整个块都涂同一个色    像素化
██████  →   ██ ██ ██ ██   →   (取 100 像素均值)  →  ████
██████      ██ ██ ██ ██                            ████
██  ██      ██ ██ ██ ██                            ████
block_size 视觉效果
5 轻微像素化
10 标准马赛克 ⭐
20 抽象艺术
50 色块拼贴

📖 目录

  1. [马赛克 vs 模糊:本质区别](#马赛克 vs 模糊:本质区别 "#%E4%B8%80%E9%A9%AC%E8%B5%9B%E5%85%8B-vs-%E6%A8%A1%E7%B3%8A%E6%9C%AC%E8%B4%A8%E5%8C%BA%E5%88%AB")
  2. [核心算法:3 步搞定](#核心算法:3 步搞定 "#%E4%BA%8C%E6%A0%B8%E5%BF%83%E7%AE%97%E6%B3%953-%E6%AD%A5%E6%90%9E%E5%AE%9A")
  3. 关键代码
  4. 前端效果展示
  5. 边界处理
  6. [进阶:彩色 vs 灰度马赛克](#进阶:彩色 vs 灰度马赛克 "#%E5%85%AD%E8%BF%9B%E9%98%B6%E5%BD%A9%E8%89%B2-vs-%E7%81%B0%E5%BA%A6%E9%A9%AC%E8%B5%9B%E5%85%8B")
  7. 应用场景
  8. 参考资料

一、马赛克 vs 模糊:本质区别

维度 模糊(任务 6) 马赛克(任务 7)
粒度 每个像素都重算 一块像素共用一个值
信息保留 平滑过渡,细节保留 细节完全丢失
可逆性 模糊后无法还原 不可还原(信息已丢)
算法 邻域平均 / 中值 块内平均 → 整块填充
用途 降噪、美化 隐私打码、艺术化

马赛克 = "硬模糊" ,不仅柔化,直接涂掉


二、核心算法:3 步搞定

markdown 复制代码
1. 分块:把图片按 block_size × block_size 切成网格
2. 算色:对每块的所有像素求平均 RGB
3. 填充:把整块都涂成这个平均色

栗子(block_size = 2)

原图 4×4(每块内故意画成 R/B 混合):

css 复制代码
R R R B      ← 第 1 行
R B B B      ← 第 2 行
B B B R      ← 第 3 行
B B R R      ← 第 4 行

按 2×2 分块(4×4 / 2×2 = 2×2 = 4 块):

css 复制代码
┌─────┬─────┐
│ R R │ R B │   块 1(3R, 1B)→ 平均 ≈ 橙红
│ R B │ B B │   块 2(2R, 2B)→ 平均 ≈ 紫
├─────┼─────┤
│ B B │ B R │   块 3(0R, 4B)→ 平均 ≈ 蓝
│ B B │ R R │   块 4(2R, 2B)→ 平均 ≈ 紫
└─────┴─────┘

输出(每块涂成自己的平均色,细节被"抹"成统一色):

复制代码
┌─────┬─────┐
│≈橙红│ ≈紫 │
├─────┼─────┤
│ ≈蓝 │ ≈紫 │
└─────┴─────┘

这才是马赛克的真正效果------把每块的细节"抹"成统一色。


三、关键代码

rust 复制代码
// 1. 双重循环:按 block_size 步长遍历"块起点"
for by in (0..h).step_by(block_size) {
    for bx in (0..w).step_by(block_size) {
        // 2. 算这一块的平均色
        let mut sum = (0u32, 0u32, 0u32);
        let mut count = 0u32;
        let y_end = (by + block_size).min(h);
        let x_end = (bx + block_size).min(w);
        for y in by..y_end {
            for x in bx..x_end {
                let i = ((y * w + x) * 4) as usize;
                sum.0 += pixels[i]     as u32;
                sum.1 += pixels[i + 1] as u32;
                sum.2 += pixels[i + 2] as u32;
                count += 1;
            }
        }
        let avg = ((sum.0 / count) as u8,
                   (sum.1 / count) as u8,
                   (sum.2 / count) as u8);

        // 3. 整块都涂成 avg
        for y in by..y_end {
            for x in bx..x_end {
                let i = ((y * w + x) * 4) as usize;
                result[i]     = avg.0;
                result[i + 1] = avg.1;
                result[i + 2] = avg.2;
                result[i + 3] = pixels[i + 3];  // 保留 alpha
            }
        }
    }
}

四、前端效果展示

五、边界处理

图片大小通常不能被 block_size 整除

ini 复制代码
500 × 500 图 + block_size = 30
30 × 16 = 480  → 还剩 20 像素

解法:.min(h) 截断

rust 复制代码
let y_end = (by + bs).min(h);   // 不能超过图片高度
let x_end = (bx + bs).min(w);   // 不能超过图片宽度

效果:

ini 复制代码
完整块:30×30 = 900 像素
边缘小块:30 × 20 = 600 像素

所有块都正确处理,没越界。


六、进阶:彩色 vs 灰度马赛克

灰度马赛克

有时想要"老式电视打码"风格(人脸变马赛克但保持灰色调):

rust 复制代码
// 把整块算成灰度
let gray = (0.2126 * avg.0 as f32
         + 0.7152 * avg.1 as f32
         + 0.0722 * avg.2 as f32) as u8;

result[i]     = gray;
result[i + 1] = gray;
result[i + 2] = gray;

用途:新闻报道打码、保护隐私。

圆形马赛克

只对中心区域打码(保留边缘):

rust 复制代码
// 判断像素到中心的距离
let dx = x as f32 - cx;
let dy = y as f32 - cy;
let dist = (dx * dx + dy * dy).sqrt();

if dist < radius {
    // 在圆内,打码
} else {
    // 圆外,原图
}

用途:证件照编辑、视频中的人脸打码。

像素艺术

block_size 调到图片宽度 / 32 之类:

rust 复制代码
let block_size = (w / 32) as u32;  // 32 块宽度的马赛克

效果类似 Minecraft 风格。


七、应用场景

场景 推荐 block_size
隐私打码(人脸、车牌) 10~20
艺术化(海报、封面) 5~15
抽象化(背景) 50~100
8-bit 复古游戏风 w / 32
调试(看缩略图) 视情况

跟模糊的选用

想要 用什么
柔化但看清细节 均值模糊(任务 6)
完全打码 马赛克(任务 7)
去除椒盐噪声 中值模糊(任务 6)
艺术化 两者都行

八、参考资料

  • Photoshop 文档:Filter → Pixelate → Mosaic
  • GIMP 文档:Filters → Blur → Pixelize
  • OpenCV 文档cv2.blur() vs 自定义马赛克
  • PIL/Pillow 库Image.EFFECT.MOSAIC(早期版本)

🎁 写在最后

马赛克 = 最暴力的"打码" 。一行公式都没有,分块 + 平均 + 填充 3 步就完事。

比均值模糊更彻底 :模糊后还能看出人脸,马赛克后真·看不出来

下篇预告:《暗角 & 复古胶片:四周衰减中心高亮 》------ 用距离做权重,离中心越远越暗,敬请期待。


📦 项目地址pixel-math-wasm 🦀 Rust + WebAssembly 实战系列


🏷️ 标签#Rust #WebAssembly #图像处理 #马赛克 #像素化 #打码 #算法

相关推荐
用户2986985301413 小时前
在 React 中使用 JavaScript 将 Excel 转换为 PDF
javascript·react.js·webassembly
SmalBox16 小时前
【节点】[Zigzag节点]原理解析与实际应用
unity3d·游戏开发·图形学
doiito17 小时前
【Agent Harness】Gliding Horse 设计细节 -- 不跟风开发自己的AI Agent
架构·rust·agent
doiito19 小时前
【Agent Harness】Gliding Horse 核心设计理念,不跟风开发自己的AI Agent
ai·rust·架构设计·系统设计·ai agent
花褪残红青杏小1 天前
Rust图像处理第6节- 均值模糊 & 中值模糊:3×3 邻域的两种经典玩法
rust·webassembly·图形学
子兮曰1 天前
前端工具链的「Rust 化」:一场没有赢家的军备竞赛?
前端·后端·rust
星栈1 天前
写 Dioxus Demo 不难,难的是把它写成项目
前端·rust·前端框架
mCell2 天前
【锐评】桌面端技术营销:别拿跑分当工程判断
前端·rust·electron
SmalBox2 天前
【节点】[Whirl节点]原理解析与实际应用
unity3d·游戏开发·图形学