BirefNet 大模型扣图 效果扛扛的
·
import cv2
import numpy as np
import onnxruntime as ort
from pathlib import Path
import os
import time
class BiRefNetMatting:
def __init__(self, model_path=None, input_size=(1024, 1024)):
"""
初始化BiRefNet模型
"""
# 如果未指定模型路径,尝试自动查找
if model_path is None:
model_path = self.find_model_file()
self.model_path = model_path
self.input_size = input_size
if not os.path.exists(model_path):
raise FileNotFoundError(f"模型文件不存在: {model_path}")
# 获取可用的执行提供程序
available_providers = ort.get_available_providers()
print(f"可用的执行提供程序: {available_providers}")
# 创建ONNX Runtime会话(使用可用的提供程序)
self.session = ort.InferenceSession(
model_path,
providers=available_providers # 自动使用可用的提供程序
)
# 获取输入输出信息
self.input_info = self.session.get_inputs()[0]
self.output_info = self.session.get_outputs()[0]
self.input_name = self.input_info.name
self.output_name = self.output_info.name
# 获取模型期望的输入数据类型
self.input_type = self.input_info.type
print(f"模型期望的输入类型: {self.input_type}")
print(f"模型加载成功: {model_path}")
print(f"输入名称: {self.input_name}, 输出名称: {self.output_name}")
print(f"输入尺寸: {self.input_size}")
def find_model_file(self):
"""尝试自动查找模型文件"""
possible_names = [
'birefnet_1024x1024.onnx',
'mvanet_1024x1024.onnx',
'birefnet.onnx',
'BiRefNet.onnx',
'birefnet_512x512.onnx',
'*.onnx' # 任何onnx文件
]
for name in possible_names:
if name == '*.onnx':
# 查找所有onnx文件
onnx_files = list(Path('.').glob('*.onnx'))
if onnx_files:
return str(onnx_files[0])
elif Path(name).exists():
return name
# 如果都没找到,返回默认名称
return 'birefnet_1024x1024.onnx'
def preprocess(self, image):
"""
图像预处理 - 确保使用float32类型
"""
# 保存原始尺寸
self.original_size = image.shape[:2]
# 调整图像尺寸
resized_image = cv2.resize(image, self.input_size, interpolation=cv2.INTER_LINEAR)
# 确保图像是float32类型
if resized_image.dtype != np.float32:
resized_image = resized_image.astype(np.float32)
# 归一化 (假设模型使用ImageNet归一化)
# 使用float32常数确保结果保持float32
mean = np.array([0.485, 0.456, 0.406], dtype=np.float32)
std = np.array([0.229, 0.224, 0.225], dtype=np.float32)
# 除以255.0并转换为float32
normalized_image = resized_image / 255.0
normalized_image = (normalized_image - mean) / std
# 调整通道顺序 HWC -> CHW
input_tensor = normalized_image.transpose(2, 0, 1)
# 添加batch维度
input_tensor = np.expand_dims(input_tensor, axis=0)
# 确保最终类型是float32
if input_tensor.dtype != np.float32:
input_tensor = input_tensor.astype(np.float32)
print(f"输入张量形状: {input_tensor.shape}, 类型: {input_tensor.dtype}")
return input_tensor
def postprocess(self, output, apply_threshold=True):
"""
后处理输出
"""
# 移除batch维度
mask = output[0, 0]
# 调整回原始尺寸
mask = cv2.resize(mask, (self.original_size[1], self.original_size[0]),
interpolation=cv2.INTER_LINEAR)
# 应用阈值(可选)
if apply_threshold:
# 使用自适应阈值或固定阈值
mask = (mask * 255).astype(np.uint8)
# 使用OTSU阈值或固定阈值
if np.max(mask) > np.min(mask): # 确保有变化
_, binary_mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
else:
_, binary_mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
return binary_mask
else:
# 返回软掩码(0-1范围)
return np.clip(mask, 0, 1)
def predict(self, image, apply_threshold=True):
"""
预测图像
"""
# 预处理
input_tensor = self.preprocess(image)
# 推理
start_time = time.time()
outputs = self.session.run([self.output_name], {self.input_name: input_tensor})
inference_time = time.time() - start_time
print(f"推理时间: {inference_time:.3f}秒")
# 后处理
mask = self.postprocess(outputs[0], apply_threshold)
return mask
def create_composite_result(image, mask, background_color=(255, 255, 255)):
"""
创建合成结果
"""
# 创建带透明通道的图像
b, g, r = cv2.split(image)
if mask.dtype == np.float32 or mask.dtype == np.float64:
alpha = mask
else:
alpha = mask.astype(np.float32) / 255.0
# 应用alpha通道
b = (b * alpha + background_color[0] * (1 - alpha)).astype(np.uint8)
g = (g * alpha + background_color[1] * (1 - alpha)).astype(np.uint8)
r = (r * alpha + background_color[2] * (1 - alpha)).astype(np.uint8)
# 创建RGBA图像
rgba = cv2.merge([b, g, r, (alpha * 255).astype(np.uint8)])
# 创建白色背景的合成图像
white_bg = np.ones_like(image) * 255
white_bg = (image * alpha[..., None] + white_bg * (1 - alpha[..., None])).astype(np.uint8)
return rgba, white_bg
def save_results(output_dir, base_name, image, mask, rgba, white_bg):
"""
保存所有结果
"""
# 保存掩码
cv2.imwrite(str(output_dir / f"{base_name}_mask.png"), mask)
# 保存透明背景图像
cv2.imwrite(str(output_dir / f"{base_name}_transparent.png"), rgba)
# 保存白色背景图像
cv2.imwrite(str(output_dir / f"{base_name}_white_bg.png"), white_bg)
# 保存掩码可视化(增强对比度以便观察)
mask_visual = cv2.normalize(mask, None, 0, 255, cv2.NORM_MINMAX)
cv2.imwrite(str(output_dir / f"{base_name}_mask_visual.png"), mask_visual)
print(f"结果已保存到: {output_dir}/{base_name}_*")
def main():
# 配置参数
image_path = "888.jpg"
output_dir = Path("mvanet_results")
output_dir.mkdir(exist_ok=True)
try:
# 首先检查模型文件
print("正在查找模型文件...")
model_files = list(Path('.').glob('*.onnx'))
if not model_files:
print("未找到任何.onnx模型文件!")
print("请将模型文件放在当前目录")
return
model_path = str(model_files[0])
print(f"使用模型: {model_path}")
# 初始化模型
print("正在加载模型...")
matting_model = BiRefNetMatting(model_path, input_size=(1024, 1024))
# 加载图像
print(f"正在加载图像: {image_path}")
image = cv2.imread(image_path)
if image is None:
raise FileNotFoundError(f"无法读取图像: {image_path}")
print(f"图像尺寸: {image.shape}")
# 尝试不同参数进行预测
print("正在进行图像分割...")
# 方法1: 使用软掩码(不二值化)
try:
mask_soft = matting_model.predict(image, apply_threshold=False)
# 保存软掩码结果
rgba_soft, white_bg_soft = create_composite_result(image, mask_soft)
save_results(output_dir, "soft", image,
(mask_soft * 255).astype(np.uint8), rgba_soft, white_bg_soft)
print("软掩码处理完成")
except Exception as e:
print(f"软掩码处理失败: {e}")
# 方法2: 使用硬掩码(二值化)
try:
mask_hard = matting_model.predict(image, apply_threshold=True)
# 保存硬掩码结果
rgba_hard, white_bg_hard = create_composite_result(image,
mask_hard.astype(np.float32) / 255.0)
save_results(output_dir, "hard", image, mask_hard, rgba_hard, white_bg_hard)
print("硬掩码处理完成")
except Exception as e:
print(f"硬掩码处理失败: {e}")
print("\n所有处理完成!")
print(f"结果已保存到: {output_dir}/")
print("\n生成的文件:")
print(" soft_*: 软掩码(有透明度渐变)")
print(" hard_*: 硬掩码(二值化)")
except FileNotFoundError as e:
print(f"文件错误: {e}")
print("请确保:")
print("1. 模型文件(.onnx)在当前目录")
print("2. 888.jpg 文件存在")
except Exception as e:
print(f"处理过程中出现错误: {e}")
import traceback
traceback.print_exc()
def test_with_different_input_sizes():
"""测试不同输入尺寸的预处理"""
image = cv2.imread("888.jpg")
# 测试不同尺寸
test_sizes = [(512, 512), (1024, 1024), (640, 480)]
for size in test_sizes:
print(f"\n测试尺寸: {size}")
# 调整尺寸
resized = cv2.resize(image, size, interpolation=cv2.INTER_LINEAR)
# 转换为float32
resized = resized.astype(np.float32)
# 归一化
normalized = resized / 255.0
normalized = (normalized - np.array([0.485, 0.456, 0.406], dtype=np.float32)) / \
np.array([0.229, 0.224, 0.225], dtype=np.float32)
# 调整通道顺序
tensor = normalized.transpose(2, 0, 1)
tensor = np.expand_dims(tensor, axis=0)
print(f" 最终形状: {tensor.shape}, 类型: {tensor.dtype}, 范围: [{tensor.min():.3f}, {tensor.max():.3f}]")
if __name__ == "__main__":
# 如果需要测试不同尺寸的预处理,取消下面的注释
# test_with_different_input_sizes()
# 运行主程序
main()
需要安装环境
pip install opencv-python onnxruntime numpy
pip install torch torchvision
pip install rembg
其实不用装那么多,反正我觉得都要测大模型了,当然装的越多越好了
onnxruntime 要是安装不了得用国内境像了
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple onnxruntime
效果如下

更多推荐
所有评论(0)