哈基马赛克

由 YOLO 模型自动识别人物敏感区域,并用猫猫图案覆盖,提供可复用的打码服务。
作者: 蜥蜴


背景

在运行于二次元社群的聊天机器人中,对图片做打码处理是常见需求。传统方式需要人工使用 Photoshop 或在线工具逐张处理,效率较低,也难以应对群聊中图片集中出现的情况。

koishi-plugin-hajimi-lizard 将识别与覆盖流程交由机器人自动完成:检测图片中的目标区域后,使用猫头与猫纹路图案进行覆盖,既实现打码目的,也让处理结果具有统一风格。

插件修改自 AutoHajimiMosaic,在此致谢原作者的开源贡献。


工具定位

koishi-plugin-hajimi-lizard 是一款基于 Koishi 框架的图片处理插件,当前版本为 1.2.0,依赖 Koishi ^4.18.7 与 Python 3.8+。

能力 说明
自动识别 使用 YOLO 模型检测图片中的目标区域
图案覆盖 使用猫头与猫纹路图案覆盖检测区域
批量处理 单次可处理多张图片
服务化调用 以 Koishi Service 形式导出 ctx.hajimi.processImages
首次依赖安装 启动时自动安装 Python 依赖并下载模型文件
自定义图案 支持替换猫头与猫纹路图案

工作流程

1
2
用户发送图片 → 机器人下载图片 → Python 调用模型检测
→ 生成掩码 → 图案覆盖 → 返回处理结果

各环节说明如下:

  1. 图片接收:从聊天消息中提取图片元素,获取其 URL
  2. 图片下载:下载至 cache/hajimi/input/<时间戳>/ 目录
  3. 模型推理:启动 Python 子进程,调用分类模型与分割模型
  4. 图案覆盖:对检测到的区域执行透视变换,贴合猫头与猫纹路图案
  5. 结果返回:输出至 cache/hajimi/output/<时间戳>/,并将文件路径返回给调用方

安装

前置条件

  • 已搭建并可正常运行的 Koishi 项目(koishi-app)
  • 已安装 Python 3.8+,且 python 命令可在终端直接调用,或准备 Python 解释器的完整路径
  • 良好的网络连接(首次启动时需下载 pip 依赖与模型文件)

方式一:通过插件市场安装(推荐)

  1. 启动 Koishi 项目,打开控制台(默认地址 http://localhost:5140)。
  2. 进入左侧「插件市场」。
  3. 在搜索框中输入 hajimi-lizard。
  4. 找到插件后点击「添加」,Koishi 会自动完成依赖安装与配置写入。

安装过程中会执行 postinstall 脚本,自动下载 YOLO 模型文件。请确保网络可用。

方式二:通过 npm 安装

在 Koishi 项目根目录执行:

1
npm install koishi-plugin-hajimi-lizard

随后在 koishi.yml 中手动添加配置:

1
2
3
4
5
6
plugins:
hajimi-lizard:
pythonPath: ''
patternPath: ''
headPath: ''
autoClean: true

方式三:通过 yarn / pnpm 安装

若项目使用 yarn 或 pnpm,可执行:

1
2
3
4
5
# yarn
yarn add koishi-plugin-hajimi-lizard

# pnpm
pnpm add koishi-plugin-hajimi-lizard

首次启动

首次启动插件时,插件会执行以下流程:

  1. 校验 pythonPath 是否可用(执行 python --version)
  2. 校验 src/requirements.txt 的哈希值,与缓存文件 cache/hajimi/.deps_installed 是否一致
  3. 若不一致,则执行 python -m pip install -r src/requirements.txt
  4. 安装完成后写入新的依赖哈希

依赖内容如下:

1
2
3
4
opencv_python==4.10.0.84
streamlit==1.41.1
ultralytics==8.3.58
imagecodecs>=2025.3.30

由于使用了哈希比对,后续启动时只要 requirements.txt 未改动,不会重复安装。

验证安装

在任意已接入机器人的聊天窗口发送一张图片,并附带指令:

1
猫赛克 [图片]

若机器人返回处理后的图片,则说明安装成功。


配置

配置项

配置项 类型 默认值 说明
pythonPath string '' Python 解释器路径。为空时按 PYTHON_PATH 环境变量、python 命令的顺序查找
patternPath string '' 猫纹路图案路径。为空时使用内置 src/assets/pattern.png
headPath string '' 猫头图案路径。为空时使用内置 src/assets/head.png
autoClean boolean true 是否在处理完成后清理本次输入目录

配置示例

1
2
3
4
5
6
plugins:
hajimi-lizard:
pythonPath: 'C:\Users\yourPC\AppData\Local\Programs\Python\Python313\python.exe'
patternPath: ''
headPath: ''
autoClean: true

pythonPath 的解析顺序为:配置项 → PYTHON_PATH 环境变量 → python 命令。若 python 命令不可用,需显式指定完整路径。

自定义图案

准备两张 PNG 图片(建议支持透明通道),并在配置中指向其路径:

1
2
3
4
plugins:
hajimi-lizard:
patternPath: 'C:/Users/yourPC/Desktop/my_pattern.png'
headPath: 'C:/Users/yourPC/Desktop/my_head.png'

仅支持本地文件路径,不支持网络 URL。


使用流程

指令列表

指令 说明 示例
猫赛克 处理本条消息中附带的全部图片 猫赛克 [图片]

指令仅接受消息中已附带的图片,不支持以 URL 文本形式传入。


流程一:单张图片处理

步骤 1:发送指令与图片

在群聊或私聊中,附带一张图片并发送:

1
猫赛克 [图片]

步骤 2:等待处理

机器人会立即返回提示:

1
图片处理中,请稍候...

同时调用 ctx.hajimi.processImages 完成推理与覆盖。

步骤 3:接收结果

处理完成后,机器人撤回提示消息,并发送处理后的图片。若处理失败,机器人返回「处理失败」,并在日志中记录错误详情。


流程二:多张图片处理

在同一条消息中附带多张图片:

1
猫赛克 [图片][图片][图片]

插件会将全部图片一并下载至同一输入目录,调用一次 Python 脚本批量处理,随后按顺序返回处理结果。

若消息中不含图片,机器人返回「请在指令后附带图片」。


流程三:作为服务调用

其他 Koishi 插件可通过 ctx.hajimi 服务调用本插件的能力。

声明依赖

1
2
3
4
import { Context, h } from 'koishi'
import {} from 'koishi-plugin-hajimi-lizard'

export const inject = ['hajimi']

调用示例

1
2
3
4
5
6
7
8
9
const urls = [
'https://example.com/a.jpg',
'https://example.com/b.png'
]

const results = await ctx.hajimi.processImages(urls)
for (const filePath of results) {
await session.send(h.image(`file://${filePath}`))
}

接口说明

方法 参数 返回值 说明
processImages(urls) string[] — 图片 URL 数组 string[] — 处理后图片的本地文件路径数组 按顺序处理并返回结果路径

补充说明:

  • 返回值可能是 cache/hajimi/output/<时间戳>/ 下的实际文件路径
  • 若 autoClean 为 true,输入目录会在处理完成后被删除;输出目录需由调用方自行管理
  • 若返回空数组,说明本次未生成输出文件,通常意味着没有检测到目标区域
  • 图片下载超时为 10 秒
  • 仅识别 jpg、jpeg、png、webp 四种扩展名

使用场景

场景一:群聊内自动打码

在群聊中由用户发送图片并附带 猫赛克 指令,机器人处理后返回覆盖猫猫图案的图片。适用于对单张或少量图片进行即时处理。

场景二:批量处理目录

借助外部脚本或定时任务,将目录下的图片 URL 列表传入 processImages,批量处理并保存结果。例如定时提取指定目录中的图片并调用服务:

1
2
3
4
5
ctx.setInterval(async () => {
const urls = listImagesFromFolder('/path/to/folder')
const results = await ctx.hajimi.processImages(urls)
saveResults(results)
}, 24 * 60 * 60 * 1000)

场景三:与其他插件联动

在自有插件中调用 ctx.hajimi.processImages,可在打码之后继续执行其他处理(加水印、写入审核队列等),或根据不同的输入参数切换不同的覆盖图案。


技术实现

技术栈

技术 用途
Koishi 机器人框架
TypeScript 插件开发
Python 3.8+ 模型推理进程
YOLOv8(ultralytics) 目标分类与分割
OpenCV 图像处理与透视变换
imagecodecs 图像读写

服务化结构

插件以 Koishi Service 形式实现,通过 ctx.plugin(HajimiService, config) 注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export class HajimiService extends Service {
constructor(ctx: Context, config: Config) {
super(ctx, 'hajimi')
// ...
}

async processImages(urls: string[]): Promise<string[]> { /* ... */ }
}

declare module 'koishi' {
interface Context {
hajimi: HajimiService
}
}

package.json 中通过 service.implements: ['hajimi'] 声明该服务,其他插件可通过 inject: ['hajimi'] 引用。

目录结构

路径 用途
cache/hajimi/input/<时间戳>/ 本次处理的输入图片
cache/hajimi/output/<时间戳>/ 本次处理的输出图片
cache/hajimi/.deps_installed 依赖哈希缓存文件,用于判断是否需要重新安装
src/batch_process.py Python 处理脚本
src/assets/pattern.png 默认猫纹路图案
src/assets/head.png 默认猫头图案

处理流程

processImages 的核心逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
async processImages(urls: string[]): Promise<string[]> {
const stamp = Date.now()
const input = join(this.inputDir, String(stamp))
const output = join(this.outputDir, String(stamp))

// 并发下载全部图片
await Promise.all(urls.map(async (url, i) => { /* ... */ }))

// 调用 Python 脚本
const { exitCode, stderr } = await runPythonScript(
this.pythonExec,
[this.batchScript, input, output,
'--pattern_image', this.patternImage,
'--head_image', this.headImage],
this.hajimiDir
)
if (exitCode !== 0) throw new Error(stderr)

// 收集输出文件
const files = fs.readdirSync(output).map(f => join(output, f))
if (this.autoClean) fs.rmSync(input, { recursive: true, force: true })

return files
}

Python 脚本

src/batch_process.py 负责实际的模型推理与图案覆盖。其处理逻辑为:

  1. 加载分类模型与分割模型
  2. 遍历输入目录下的全部图片
  3. 使用分类模型判断内容类别
  4. 使用分割模型生成掩码
  5. 对每个掩码执行透视变换并覆盖图案
  6. 将结果保存至输出目录

关键步骤为透视变换:

1
2
matrix = cv2.getPerspectiveTransform(src_points, dst_points)
transformed_head = cv2.warpPerspective(head_image, matrix, image.shape[:2][::-1])

通过计算检测区域四个角点与图案四角的对应关系,生成透视变换矩阵,从而将图案贴合至目标区域。


Python 环境配置

Windows

方式一:使用系统环境变量

  1. 从 python.org 下载并安装 Python 3.8 及以上版本
  2. 安装时勾选「Add Python to PATH」
  3. 在命令行中执行 python --version 验证安装

方式二:在插件配置中指定路径

Python 解释器路径通常形如:

1
C:\Users\<用户名>\AppData\Local\Programs\Python\Python313\python.exe

将上述路径填入 pythonPath 即可。

Linux / macOS

通常无需额外配置,系统自带的 python3 可通过 python 软链或 PYTHON_PATH 环境变量被插件识别:

1
2
3
4
5
# 检查 Python 版本
python3 --version

# 或设置环境变量
export PYTHON_PATH=/usr/bin/python3

首次依赖安装

若首次依赖安装失败,可按以下方向排查:

问题 排查方向
Python 不可用 检查解释器路径与 PYTHON_PATH 环境变量
pip 安装失败 检查网络连接,必要时更换 pip 源
依赖冲突 检查 Python 版本是否 ≥ 3.8
模型文件缺失 重新安装插件以触发模型下载

性能建议

输入分辨率

建议将输入图片控制在 1920×1080 以内。分辨率越高,模型推理与透视变换耗时越长。

批量数量

单次建议不超过 5 张。多图并发会同时占用内存与 CPU,数量过多可能造成内存峰值。

GPU 加速

若安装了 CUDA 版本的 PyTorch,ultralytics 会自动使用 GPU 进行推理,速度可显著提升。若无独立显卡,可适当降低批量数量以补偿。

临时文件管理

保持 autoClean 为 true,避免输入目录持续累积。输出目录不会自动清理,如需长期运行,建议额外设置定期清理策略。


注意事项

1. Python 环境依赖

插件所有识别逻辑均在 Python 进程中执行。若 pythonPath 配置错误,插件在启动时会抛出「Python 不可用」并拒绝加载。

2. 模型文件

模型随插件安装时自动下载。若下载失败,可重新安装插件以触发下载流程。

3. 首次启动较慢

首次启动需要安装 pip 依赖并下载模型文件,耗时视网络情况而定。后续启动无此过程。

4. 服务调用方需自行管理输出文件

autoClean 仅清理输入目录,输出目录不会自动清理。调用 processImages 的插件应自行管理返回的文件路径。

5. 用途限制

插件仅用于对图片进行覆盖处理,识别结果取决于所使用的模型。请勿将处理后的图片用于侵权或违规场景。


常见问题

Q1:启动时提示「Python 不可用」?

说明 python --version 执行失败。请确认已安装 Python,并在 pythonPath 中指定完整解释器路径,或设置 PYTHON_PATH 环境变量。

Q2:处理速度过慢?

可从以下方向调整:

  • 降低输入图片分辨率
  • 减少单次处理的图片数量
  • 安装 CUDA 版本的 PyTorch 以启用 GPU 加速
  • 检查 CPU 占用情况

Q3:模型文件从哪里获取?

模型文件由插件在安装时通过 postinstall 脚本自动下载。如需自定义模型,可替换对应文件,但需保证文件结构与插件兼容。

Q4:可以识别哪些内容?

识别范围由所使用的模型决定。默认模型用于识别人物敏感部位,若替换为自定义模型,可识别其他目标。

Q5:可以自定义覆盖图案吗?

可以。通过配置 patternPath 与 headPath 指向自定义的 PNG 图片(建议带透明通道)即可。

Q6:服务调用返回空数组?

说明本次未生成输出文件,通常意味着没有检测到目标区域。可检查输入图片是否符合模型识别的类别。

Q7:输出目录需要手动清理吗?

autoClean 仅清理本次的输入目录。输出目录会持续累积,建议由调用方按需处理,或配置定期清理。

Q8:支持 macOS?

支持。Python 环境配置见上文「Python 环境配置」一节。


开发计划

  • 提供可配置的模型下载源
  • 支持 GPU 加速自动检测
  • 增加更多覆盖图案选项
  • 优化处理性能,支持实时处理
  • 支持视频流处理
  • 提供 Web 管理界面

获取工具