网页端, 40mb离线模型, 自动抠图, 不用 Python,不用服务器,不用 API Key, 不用显卡

0 阅读3分钟

图片

一张照片,点一下抠完。

不用后端,不用 GPU 服务器,不用调 API。

浏览器直接搞定。

我机器是可是个老古董, AMD5500, 用40mb的模型, 一次抠图8s多。

图片

核心代码:

import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm"

const file = document.getElementById("file").files[0]
const png = await removeBackground(file)
URL.createObjectURL(png)

图选完,几秒出透明 PNG。图不离开本机。

流程图

    上传图片
        │
        ▼
  加载 ISNet ONNX 模型
        │
        ▼
  WebGPU / WebGL / WASM 推理
        │
        ▼
  输出透明 PNG(Blob)
        │
        ▼
  棋盘格预览 + 下载

1.1 痛点

做电商,天天抠图。

一张一张用 PS,抠头发抠花边,半小时一张。

网上抠图工具,图传到人家服务器。

隐私没了,还要付费。

能不能浏览器本地跑?

@imgly/background-removal,纯前端,零后端。

图片

1.2 包简介

GitHub 约 6.8 千星。

底层 ONNX Runtime Web,推理模型 ISNet。

| 模型 | 大小 | | :-- | :-- | | isnet_fp16 | ~80MB,默认推荐 | | isnet_quint8 | ~40MB,最快够用 |

设备自动选:WebGPU → WebGL → WASM

有显卡跑显卡,没显卡跑 CPU。

1.3 CDN 引入

<script type="module">
import { removeBackground } from "https://cdn.jsdelivr.net/npm/@imgly/background-removal@1.7.0/+esm"
</script>

jsDelivr 的 +esm 自动打包,国内直连。

不用 npm,不用 publicPath,库自动从 CDN 拉模型。

1.4 模型精度

ISNet 是专门做图像分割的模型。

isnet_fp16,80MB,精度最高。

isnet_quint8,40MB,量化版,速度快一倍,精度略有损失。

人像抠图两个都够用,发丝细节选 FP16。

物品抠图选 QuInt8,速度快,肉眼看不出差别。

1.5 设备自动降级

WebGPU → WebGL → WASM

有 WebGPU 用 WebGPU,跑最快。

没有 WebGPU,降级 WebGL。

连 WebGL 都没有,降级 WASM 纯 CPU 跑。

整个过程自动判断,开发者不用写兼容代码。

1.6 进度回调

progress: (key, current, total) => {
  const pct = Math.round((current / total) * 100)
}

key 告诉你当前阶段:

download    下载模型
load        加载模型
run         前向推理
postprocess 后处理

total 为 0 时表示该阶段无进度信息,忽略即可。

1.7 输出格式

// PNG,透明背景
removeBackground(file, { output: { format: "image/png" } })

// JPEG,白底,可调 quality
removeBackground(file, { output: { format: "image/jpeg", quality: 0.85 } })

// WebP,体积小
removeBackground(file, { output: { format: "image/webp", quality: 0.9 } })

| 格式 | 透明 | 体积 | | :-- | :-- | :-- | | PNG | ✓ | 最大 | | JPEG | ✗ | 最小 | | WebP | ✓ | 中等 |

默认输出 PNG。

1.8 输出类型

// 主体(默认)
removeBackground(file, { output: { type"foreground" } })

// 背景
removeBackground(file, { output: { type"background" } })

// 黑白遮罩图
removeBackground(file, { output: { type"mask" } })

遮罩图可以做二次处理,比如换底色。

1.9 换底色

拿到透明 PNG 后,用 canvas 合成底色:

function addColorBg(png, color) {
  const img = new Image()
  img.onload = () => {
    const c = document.createElement("canvas")
    c.width = img.width; c.height = img.height
    const ctx = c.getContext("2d")
    ctx.fillStyle = color
    ctx.fillRect(0, 0, c.width, c.height)
    ctx.drawImage(img, 0, 0)
    c.toBlob(blob => URL.createObjectURL(blob))
  }
  img.src = URL.createObjectURL(png)
}

addColorBg(png, "#cc0000")  // 红底证件照

1.10 浏览器缓存

第一次调用下载 80MB 模型文件。

浏览器自动缓存到 disk cache。

第二次打开页面,秒级完成。

清缓存会重新下载。

总结

  • • @imgly/background-removal:纯前端,一行代码

  • • ISNet 模型:ONNX,人像物品通吃

  • • WebGPU:有显卡 3 秒出图

  • • 棋盘格预览:透明一眼见

  • • 换底色:再加 10 行代码

  • • 零后端:隐私不出本机

现在有个问题, 背景复杂的时候, 抠图会多扣, 

所以, 再过2天, 本周我会发布一个带选取的版本, 抠图更丝滑