高精度・高解像度・境界を綺麗 に背景を透過できるBiRefNet

2026年4月29日

BiRefNetとは

BiRefNet(Bilateral Reference Network) は、
高解像度の二値画像セグメンテーション(前景/背景の切り分け)に特化した最新モデル です。

用途は主に:

  • 背景除去(人物・物体の切り抜き)
  • 顕著物体検出(SOD)
  • 高解像度画像のマスク生成
  • マッティング(髪の毛などの細かい境界)
  • カモフラージュ物体検出(COD)
  • 医療画像などの二値セグメンテーション

とにかく 高精度・高解像度・境界が綺麗 というのが特徴。

インストール方法(公式推奨)

BiRefNet のコードを取得

git clone https://github.com/ZhengPeng7/BiRefNet
cd BiRefNet

必要ライブラリをインストール

(GitHub の requirements.txt を使用)

pip install -r requirements.txt

4. モデル(weights)をダウンロード

GitHub Releases(v1)または Google Drive から取得
https://github.com/ZhengPeng7/BiRefNet/releases

BiRefNet のモデル種類と用途(重要)

BiRefNet は用途別に 複数のモデル が公開されています。

1. BiRefNet-general(General 用)

用途:人物・物体の背景除去、一般的な切り抜き

  • 最も汎用的
  • 人物・動物・物体など幅広く対応
  • 実用アプリ(背景除去サービスなど)でよく使われる

人物切り抜きならまずこれ

2. BiRefNet_HR(高解像度用)

用途:高解像度写真(2048×2048 以上)で高品質なマスク

  • 髪の毛・細かい境界が綺麗
  • 写真・商品画像の切り抜きに最適

高画質写真の人物切り抜きに最適

3. BiRefNet_HR-matting(マッティング用)

用途:髪の毛・透明物・細かい境界のマッティング

  • トリマップ不要
  • 透明感のある境界が必要な場合に最強

髪の毛の自然な切り抜きが必要ならこれ

4. BiRefNet_dynamic(解像度可変モデル)

用途:解像度がバラバラの大量画像を処理したい場合

  • 256?2304px の幅広い解像度に対応
  • 実務向けの安定モデル

大量バッチ処理に向く

5. BiRefNet-lite / SwinT バージョン

用途:軽量・高速推論

  • モバイル・低スペックGPU向け
  • 精度はやや下がるが高速

速度重視ならこれ

6. BiRefNet-HRSOD / DIS / COD(研究用)

用途:特定データセット向け(研究・比較用)

  • HRSOD:高解像度顕著物体検出
  • DIS:高精細境界のセグメンテーション
  • COD:カモフラージュ物体検出

一般ユーザーは不要

人物切り抜きに最適なモデルは?

あなたの用途(人物切り抜き)なら:

1位:BiRefNet-general(General)

  • 最も汎用的で人物に強い
  • ONNX 版もあり高速

2位:BiRefNet_HR

  • 高解像度写真ならこちらが最強

3位:BiRefNet_HR-matting

  • 髪の毛の自然さを重視するならこれ

ONNX推論コード

1つ上の場所に移す

"D:\WinPython\content\BiRefNet\birefnet.py"

モデルのダウンロードと設置

  • “D:\WinPython\content\BiRefNet\models\BiRefNet-general-epoch_244.onnx"
import os
import cv2
import argparse
import numpy as np
import onnxruntime
from PIL import Image


# ---------------------------------------------------------
# 1. デフォルトパス(指定が無い場合に使用)
# ---------------------------------------------------------
DEFAULT_MODEL_PATH = r"D:\WinPython\content\BiRefNet\models\BiRefNet-general-epoch_244.onnx"
DEFAULT_INPUT_DIR = r"D:\WinPython\content\BiRefNet\input_images"
DEFAULT_OUTPUT_DIR = r"D:\WinPython\content\BiRefNet\output_images"


# ---------------------------------------------------------
# 2. Sigmoid
# ---------------------------------------------------------
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


# ---------------------------------------------------------
# 3. GPU があれば使うセッション生成
# ---------------------------------------------------------
def create_session(model_path):
    available = onnxruntime.get_available_providers()
    print("Available providers:", available)

    providers = []
    if "CUDAExecutionProvider" in available:
        providers.append("CUDAExecutionProvider")
    if "CPUExecutionProvider" in available:
        providers.append("CPUExecutionProvider")

    print("Using providers:", providers)
    return onnxruntime.InferenceSession(model_path, providers=providers)


# ---------------------------------------------------------
# 4. ONNX 推論(色補正済み)
# ---------------------------------------------------------
def run_inference(onnx_session, bgr_image):
    input_size = onnx_session.get_inputs()[0].shape
    input_width = input_size[3]
    input_height = input_size[2]

    # ---- 前処理 ----
    img = cv2.resize(bgr_image, (input_width, input_height))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # ★ RGB に変換(青み対策)
    img = img.astype(np.float32) / 255.0        # ★ 正規化なし(ResNet-general)

    img = img.transpose(2, 0, 1)
    img = np.expand_dims(img, axis=0)

    # ---- 推論 ----
    input_name = onnx_session.get_inputs()[0].name
    result = onnx_session.run(None, {input_name: img})

    # ---- 後処理 ----
    mask = np.squeeze(result[-1])
    mask = sigmoid(mask)
    mask = (mask * 255).astype(np.uint8)

    return mask


# ---------------------------------------------------------
# 5. メイン処理
# ---------------------------------------------------------
def main():
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-i", "--input",
        type=str,
        default=DEFAULT_INPUT_DIR,
        help="入力フォルダー(省略時はデフォルト)"
    )

    parser.add_argument(
        "-o", "--output",
        type=str,
        default=DEFAULT_OUTPUT_DIR,
        help="出力フォルダー(省略時はデフォルト)"
    )

    parser.add_argument(
        "-m", "--model",
        type=str,
        default=DEFAULT_MODEL_PATH,
        help="ONNX モデルパス(省略時はデフォルト)"
    )

    args = parser.parse_args()

    input_dir = args.input
    output_dir = args.output
    model_path = args.model

    os.makedirs(output_dir, exist_ok=True)

    print("Input folder :", input_dir)
    print("Output folder:", output_dir)
    print("Model path   :", model_path)

    print("\nLoading ONNX model...")
    onnx_session = create_session(model_path)
    print("Model loaded.\n")

    valid_ext = [".jpg", ".jpeg", ".png", ".bmp", ".webp"]

    print("Start processing images...\n")

    for filename in os.listdir(input_dir):
        if not any(filename.lower().endswith(ext) for ext in valid_ext):
            continue

        input_path = os.path.join(input_dir, filename)
        output_path = os.path.join(
            output_dir, os.path.splitext(filename)[0] + ".png"
        )

        print("Processing:", filename)

        bgr = cv2.imread(input_path)
        if bgr is None:
            print("Failed to read:", input_path)
            continue

        mask = run_inference(onnx_session, bgr)

        mask = cv2.resize(mask, (bgr.shape[1], bgr.shape[0]))

        rgb = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
        rgba = np.dstack([rgb, mask])

        Image.fromarray(rgba).save(output_path)

    print("\nAll images processed successfully.")


if __name__ == "__main__":
    main()

インストールと実行用バッチファイル

インストールが終わったら"D:\WinPython\content\BiRefNet\process_images_onnx.py"作ってください

@echo off
call %~dp0\scripts\env_for_icons.bat  %*
SET PATH=%PATH%;%WINPYDIRBASE%\PortableGit;%WINPYDIRBASE%\PortableGit\bin
SET PATH=%PATH%;%WINPYDIRBASE%\ffmpeg\bin

If not exist %WINPYDIRBASE%\content mkdir  %WINPYDIRBASE%\content 

set APP_NAME=BiRefNet
set APP_DIR=%WINPYDIRBASE%\content\%APP_NAME%
cd %WINPYDIRBASE%\content\

If not exist  %APP_DIR% git clone https://github.com/ZhengPeng7/BiRefNet

echo %APP_DIR%
cd %APP_DIR%


if not defined VENV_DIR (set "VENV_DIR=%APP_DIR%\venv")
if EXIST %VENV_DIR% goto :activate_venv


::python.exe -m venv "%VENV_DIR%" 
python.exe -m venv "%VENV_DIR%" --system-site-packages 
if %ERRORLEVEL% == 0 goto :activate_venv
echo Unable to create venv 
goto :skip_venv

:activate_venv
call "%VENV_DIR%\Scripts\activate"
If  exist  %APP_DIR%\process_images_onnx.py goto :skip_cmd

::
pip install -r requirements.txt
::pip uninstall -y onnxruntime
pip install onnxruntime-gpu
cmd.exe /k
goto :skip_venv
:skip_cmd
If not exist Y:\input mkdir  Y:\input
python process_images_onnx.py -i Y:\input -o Y:\output
::python process_images_onnx.py -t 80 -i Y:\input -o Y:\output

:skip_venv
timeout /t 55
::
cmd.exe /k

モデル切り替え

"--close マスクの穴埋め(closing)ピクセル数
"--model-type 使用するモデルタイプ(general / portrait)
"--threshold マスクしきい値(0〜255)
"--dilate マスク膨張ピクセル数(甘めにしたい場合)

  • 汎用(general)そのまま python script.py --model-type general
  • 人物特化 portrait + 少し甘め python script.py --model-type portrait -t 110 -d 4
  • HR-matting で欠け対策強め python script.py --model-type hrmatting --close 6 -d 3 -t 120
import os
import cv2
import argparse
import numpy as np
import onnxruntime
from PIL import Image


# ---------------------------------------------------------
# 1. デフォルトパス
# ---------------------------------------------------------
DEFAULT_MODEL_GENERAL   = r"D:\WinPython\content\BiRefNet\models\BiRefNet-general-epoch_244.onnx"
DEFAULT_MODEL_PORTRAIT  = r"D:\WinPython\content\BiRefNet\models\BiRefNet-portrait-epoch_150.onnx"
DEFAULT_MODEL_HRMATTING = r"D:\WinPython\content\BiRefNet\models\BiRefNet_HR-matting-epoch_135.onnx"

DEFAULT_INPUT_DIR = r"D:\WinPython\content\BiRefNet\input_images"
DEFAULT_OUTPUT_DIR = r"D:\WinPython\content\BiRefNet\output_images"
DEFAULT_THRESHOLD = 128


# ---------------------------------------------------------
# 2. Sigmoid
# ---------------------------------------------------------
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


# ---------------------------------------------------------
# 3. GPU があれば使うセッション生成
# ---------------------------------------------------------
def create_session(model_path):
    available = onnxruntime.get_available_providers()
    print("Available providers:", available)

    providers = []
    if "CUDAExecutionProvider" in available:
        providers.append("CUDAExecutionProvider")
    if "CPUExecutionProvider" in available:
        providers.append("CPUExecutionProvider")

    print("Using providers:", providers)
    return onnxruntime.InferenceSession(model_path, providers=providers)


# ---------------------------------------------------------
# 4. ONNX 推論
# ---------------------------------------------------------
def run_inference(onnx_session, bgr_image):
    input_size = onnx_session.get_inputs()[0].shape
    # (N, C, H, W)
    input_height = input_size[2]
    input_width  = input_size[3]

    img = cv2.resize(bgr_image, (input_width, input_height))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = img.astype(np.float32) / 255.0

    img = img.transpose(2, 0, 1)  # (H, W, C) -> (C, H, W)
    img = np.expand_dims(img, axis=0)  # (1, C, H, W)

    input_name = onnx_session.get_inputs()[0].name
    result = onnx_session.run(None, {input_name: img})

    # BiRefNet 系は最後の出力がマスク
    mask = np.squeeze(result[-1])
    mask = sigmoid(mask)
    mask = (mask * 255).astype(np.uint8)

    return mask


# ---------------------------------------------------------
# 5. メイン処理
# ---------------------------------------------------------
def main():
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-i", "--input",
        type=str,
        default=DEFAULT_INPUT_DIR,
        help="入力フォルダー"
    )
    parser.add_argument(
        "-o", "--output",
        type=str,
        default=DEFAULT_OUTPUT_DIR,
        help="出力フォルダー"
    )

    parser.add_argument(
        "--model-type",
        type=str,
        default="general",
        choices=["general", "portrait", "hrmatting"],
        help="使用するモデルタイプ(general / portrait / hrmatting)"
    )

    parser.add_argument(
        "-t", "--threshold",
        type=int,
        default=DEFAULT_THRESHOLD,
        help="マスクしきい値(0?255、低いほど甘め)"
    )

    parser.add_argument(
        "-d", "--dilate",
        type=int,
        default=0,
        help="マスク膨張ピクセル数(甘めにしたい場合)"
    )

    parser.add_argument(
        "--close",
        type=int,
        default=0,
        help="マスク穴埋め(closing)ピクセル数(欠け対策など)"
    )

    args = parser.parse_args()

    # モデルパス切り替え
    if args.model_type == "general":
        model_path = DEFAULT_MODEL_GENERAL
    elif args.model_type == "portrait":
        model_path = DEFAULT_MODEL_PORTRAIT
    elif args.model_type == "hrmatting":
        model_path = DEFAULT_MODEL_HRMATTING
    else:
        model_path = DEFAULT_MODEL_GENERAL
    input_dir = args.input
    output_dir = args.output
    threshold = args.threshold

    os.makedirs(output_dir, exist_ok=True)

    print("Input folder :", input_dir)
    print("Output folder:", output_dir)
    print("Model type   :", args.model_type)
    print("Model path   :", model_path)
    print("Threshold    :", threshold)
    print("Dilate       :", args.dilate)
    print("Closing      :", args.close)

    print("\nLoading ONNX model...")
    onnx_session = create_session(model_path)
    print("Model loaded.\n")

    valid_ext = [".jpg", ".jpeg", ".png", ".bmp", ".webp"]

    print("Start processing images...\n")

    for filename in os.listdir(input_dir):
        if not any(filename.lower().endswith(ext) for ext in valid_ext):
            continue

        input_path = os.path.join(input_dir, filename)
        output_path = os.path.join(
            output_dir, os.path.splitext(filename)[0] + ".png"
        )

        print("Processing:", filename)

        bgr = cv2.imread(input_path)
        if bgr is None:
            print("Failed to read:", input_path)
            continue

        mask = run_inference(onnx_session, bgr)

        # 元画像サイズにリサイズ
        mask = cv2.resize(mask, (bgr.shape[1], bgr.shape[0]))

        # しきい値処理
        mask = np.where(mask >= threshold, 255, 0).astype(np.uint8)

        # 穴埋め(closing)
        if args.close > 0:
            kernel_close = np.ones((args.close, args.close), np.uint8)
            mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel_close)

        # 膨張(甘め)
        if args.dilate > 0:
            kernel_dilate = np.ones((args.dilate, args.dilate), np.uint8)
            mask = cv2.dilate(mask, kernel_dilate, iterations=1)

        rgb = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
        rgba = np.dstack([rgb, mask])

        Image.fromarray(rgba).save(output_path)

    print("\nAll images processed successfully.")


if __name__ == "__main__":
    main()

うまくいかない時

https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/windows-x86_64

自分の環境にあったのをダウンロードして次のホルダーに入れる

"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\bin\x64"
↓
"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\bin"

確認

where cudnn*.dll

バージョン

pip install onnxruntime-gpu==1.20.0

Python

Posted by eightban