200字
python+html自动化抠图
2026-01-11
2026-01-16

运用AI技术,实现智能识别,一键抠图,满足您在日常生活中的抠图需求,无需下载PS,也可快速实现图片背景切换。基于深度学习模型,通过对大量图像数据的学习与优化,深度学习模型能够识别图片中的主体与背景,实现精准抠图。这种方法相较传统手工抠图,不仅效率高,而且能处理复杂场景下的抠图需求,显著提高抠图质量与用户体验。通过持续学习与优化,提升AI模型的精确度与泛化能力,持续优化抠图的效果。

遇到bug或者使用上的问题,记得评论区留言!

此工具需要电脑有一定的配置,可在局域网下运行,电脑运行python文件,此局域网下所有设备均可打开网页。显存至少6个G!

可前往:https://huggingface.co/spaces/SJY-HIM/my-rembg-tool 进行在线体验。(huggingface为国外网站,需要挂梯子才能访问,建议本地部署!

首先安装所需库

pip install rembg flask flask-cors pillow
pip install onnxruntime

🤔请确保python文件和index.html在同一文件夹。首次运行需要下载一个约200MB的模型文件,耐心等待!

from rembg import remove, new_session 
from flask import Flask, request, send_file
from flask_cors import CORS
from PIL import Image
import io

app = Flask(__name__)
CORS(app)

# 预加载高精度模型
print("正在加载 AI 模型...")
model_name = "isnet-general-use"
session = new_session(model_name)
print("模型加载完成!")

@app.route('/')
def index():
    return send_file('index.html')

@app.route('/remove-bg', methods=['POST']) 
def remove_background():
    if 'image' not in request.files:
        return '没有上传图片', 400
    file = request.files['image']
    if file.filename == '':
        return '文件名为空', 400

    # 获取前端传来的模式参数,默认为 'general'
    mode = request.form.get('mode', 'general')
    print(f"收到请求 -> 模式: {mode} | 文件: {file.filename}")

    try:
        input_image = Image.open(file.stream)
        input_image = input_image.convert('RGB') # 强制转RGB防止报错
        
        #根据模式动态调整参数
        if mode == 'hair':
            # 模式2:精细发丝 (开启 Alpha Matting)
            output_image = remove(
                input_image, 
                session=session,
                alpha_matting=True,
                alpha_matting_foreground_threshold=240,
                alpha_matting_background_threshold=10,
                alpha_matting_erode_size=10
            )
        elif mode == 'aggressive':
             # 模式3:强力去底 (更大的腐蚀力度,适合难搞的背景)
            output_image = remove(
                input_image, 
                session=session,
                alpha_matting=True,
                alpha_matting_foreground_threshold=250, 
                alpha_matting_background_threshold=10,
                alpha_matting_erode_size=15  # 腐蚀更多边缘
            )
        else:
            output_image = remove(input_image, session=session)
        
        img_io = io.BytesIO()
        output_image.save(img_io, 'PNG')
        img_io.seek(0)
        return send_file(img_io, mimetype='image/png')

    except Exception as e:
        print(f"Error occurred: {e}") 
        return str(e), 500

if __name__ == '__main__':
    app.run(debug=True, port=5000, host='0.0.0.0')

以下为html文件。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI 多模式智能抠图</title>
    <link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
    <style>
        :root {
            --glass-bg: rgba(255, 255, 255, 0.15);
            --glass-border: 1px solid rgba(255, 255, 255, 0.3);
            --glass-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
            --text-color: #ffffff;
        }

        * { margin: 0; padding: 0; box-sizing: border-box; }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(45deg, #2575fc 0%, #6a11cb 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            color: var(--text-color);
            position: relative;
            overflow-x: hidden;
        }

        /* 动态背景 */
        .blob {
            position: absolute;
            border-radius: 50%;
            filter: blur(80px);
            z-index: -1;
            opacity: 0.8;
            animation: move 10s infinite alternate;
        }
        .blob:nth-child(1) { top: -10%; left: -10%; width: 500px; height: 500px; background: #ff416c; }
        .blob:nth-child(2) { bottom: -10%; right: -10%; width: 400px; height: 400px; background: #2575fc; }
        @keyframes move { from { transform: translate(0, 0); } to { transform: translate(30px, -30px); } }

        .main-card {
            background: var(--glass-bg);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: var(--glass-border);
            box-shadow: var(--glass-shadow);
            border-radius: 24px;
            padding: 40px;
            width: 90%;
            max-width: 900px;
            display: flex;
            flex-direction: column;
            align-items: center; 
            text-align: center;
        }

        h1 { font-size: 2.2rem; margin-bottom: 10px; font-weight: 700; }
        p.subtitle { margin-bottom: 25px; opacity: 0.9; font-size: 1rem; }

        .upload-area {
            display: flex; 
            flex-direction: column;
            align-items: center;
            justify-content: center;
            width: 100%; 
            max-width: 600px;
            height: 160px;
            background: rgba(255, 255, 255, 0.1);
            border: 2px dashed rgba(255, 255, 255, 0.5);
            border-radius: 16px;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-bottom: 20px;
        }
        .upload-area:hover { background: rgba(255, 255, 255, 0.2); border-color: #fff; }
        .upload-area i { font-size: 2.5rem; margin-bottom: 10px; color: rgba(255,255,255,0.9); }
        #uploadInput { display: none; }


        .mode-select-container {
            margin-bottom: 20px;
            position: relative;
            width: 100%;
            max-width: 300px;
        }
        
        select {
            width: 100%;
            padding: 12px 20px;
            font-size: 1rem;
            border-radius: 50px;
            border: 1px solid rgba(255, 255, 255, 0.4);
            background: rgba(0, 0, 0, 0.2); /* 半透明黑底,保证白色文字可见 */
            color: white;
            outline: none;
            appearance: none; /* 去掉默认箭头 */
            cursor: pointer;
            text-align: center;
            font-family: inherit;
        }
        
        select:hover { background: rgba(0, 0, 0, 0.3); }
        
        /* 自定义下拉箭头图标 */
        .mode-select-container::after {
            content: '▼';
            font-size: 0.8rem;
            position: absolute;
            right: 20px;
            top: 50%;
            transform: translateY(-50%);
            pointer-events: none;
            color: rgba(255,255,255,0.7);
        }


        option { background-color: #333; color: white; }

        .action-btn {
            padding: 12px 50px;
            background: linear-gradient(90deg, #ff416c, #ff4b2b);
            color: white;
            border: none;
            border-radius: 50px;
            font-size: 1.1rem;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 4px 15px rgba(255, 75, 43, 0.4);
            transition: transform 0.2s;
        }
        .action-btn:hover { transform: translateY(-2px); }
        .action-btn:disabled { background: #ccc; cursor: not-allowed; box-shadow: none; }

        .preview-container {
            display: none; 
            width: 100%;
            margin-top: 40px;
            display: grid; 
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            display: none; 
        }

        .image-card {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 16px;
            padding: 15px;
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        .image-card h3 { margin-bottom: 15px; font-size: 1rem; opacity: 0.9; }

        .checkerboard {
            background-image: linear-gradient(45deg, #ccc 25%, transparent 25%), 
                              linear-gradient(-45deg, #ccc 25%, transparent 25%), 
                              linear-gradient(45deg, transparent 75%, #ccc 75%), 
                              linear-gradient(-45deg, transparent 75%, #ccc 75%);
            background-size: 20px 20px;
            background-color: #fff;
            border-radius: 12px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 200px;
        }

        img { max-width: 100%; max-height: 400px; display: block; image-rendering: -webkit-optimize-contrast; object-fit: contain;}

        .loader-wrapper { display: none; margin: 20px 0; text-align: center; }
        .spinner {
            width: 40px; height: 40px;
            border: 4px solid rgba(255,255,255,0.3); border-top: 4px solid #fff;
            border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 10px auto;
        }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }

        .download-link {
            display: inline-flex; align-items: center; gap: 5px; margin-top: 15px;
            color: #fff; text-decoration: none; font-size: 0.9rem;
            background: rgba(0,0,0,0.2); padding: 8px 20px; border-radius: 20px;
        }
        
        @media (max-width: 768px) {
            .preview-container { grid-template-columns: 1fr; }
            .main-card { padding: 20px; width: 95%; }
        }
    </style>
</head>
<body>

    <div class="blob"></div>
    <div class="blob"></div>

    <div class="main-card">
        <h1><i class="ri-magic-line"></i> AI 智能抠图</h1>
        <p class="subtitle">选择模式,精准去除背景</p>

        <label for="uploadInput" class="upload-area" id="dropZone">
            <i class="ri-upload-cloud-2-line"></i>
            <span id="fileName">点击或拖拽图片到这里上传</span>
        </label>
        <input type="file" id="uploadInput" accept="image/*">

        <div class="mode-select-container">
            <select id="modeSelect">
                <option value="general">🚀 通用模式 (Logo/商品/硬边)</option>
                <option value="hair">🦁 精细模式 (头发/毛绒/婚纱)</option>
                <option value="aggressive">🛡️ 强力去底 (复杂杂乱背景)</option>
            </select>
        </div>

        <button onclick="processImage()" id="btnProcess" class="action-btn">开始抠图</button>

        <div class="loader-wrapper" id="loader">
            <div class="spinner"></div>
            <p>正在进行 AI 推理...</p>
        </div>

        <div class="preview-container" id="previewContainer">
            <div class="image-card">
                <h3>原始图片</h3>
                <div class="checkerboard">
                    <img id="originalImg" alt="原始图片">
                </div>
            </div>

            <div class="image-card">
                <h3>处理结果</h3>
                <div class="checkerboard">
                    <img id="resultImg" alt="抠图结果">
                </div>
                <div id="downloadArea"></div>
            </div>
        </div>
    </div>

    <script>
        const input = document.getElementById('uploadInput');
        const fileNameDisplay = document.getElementById('fileName');
        const originalImg = document.getElementById('originalImg');
        const resultImg = document.getElementById('resultImg');
        const previewContainer = document.getElementById('previewContainer');
        const loader = document.getElementById('loader');
        const btn = document.getElementById('btnProcess');
        const downloadArea = document.getElementById('downloadArea');
        const modeSelect = document.getElementById('modeSelect');

        input.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                fileNameDisplay.innerText = "已选择: " + file.name;
                const reader = new FileReader();
                reader.onload = function(e) {
                    originalImg.src = e.target.result;
                    previewContainer.style.display = 'grid'; 
                    resultImg.style.display = 'none';
                    downloadArea.innerHTML = ''; 
                }
                reader.readAsDataURL(file);
            }
        });

        async function processImage() {
            if (!input.files[0]) {
                alert("请先选择一张图片!");
                return;
            }

            loader.style.display = 'block';
            btn.disabled = true;
            btn.innerText = "处理中...";
            resultImg.style.display = 'none';

            const formData = new FormData();
            formData.append('image', input.files[0]);
            
            //把用户选择的模式传给后端
            formData.append('mode', modeSelect.value); 
            // ===================================

            try {
                // 使用相对路径,自动适配手机/电脑
                const response = await fetch('/remove-bg', {  
                    method: 'POST',
                    body: formData
                });

                if (!response.ok) {
                    throw new Error("HTTP 状态码异常: " + response.status);
                }

                const blob = await response.blob();
                const imgUrl = URL.createObjectURL(blob);
                
                resultImg.src = imgUrl;
                resultImg.style.display = 'block';

                downloadArea.innerHTML = `
                    <a href="${imgUrl}" download="rembg_result.png" class="download-link">
                        <i class="ri-download-line"></i> 下载透明背景图
                    </a>
                `;

            } catch (error) {
                console.error(error);
                alert("错误详情: " + error.message);
            } finally {
                loader.style.display = 'none';
                btn.disabled = false;
                btn.innerText = "开始抠图";
            }
        }
    </script>
</body>
</html>

操作步骤:运行python文件,打开返回的网址信息,需要先开电脑防火墙端口。抠图速度与电脑配置有关。

python+html自动化抠图
作者
站长
发表于
2026-01-11

评论