Python实现证件照换底色(全网唯一任意底色都可换)(附前端页面)

前言

我翻阅了国内网上没有找到一个可以随意换底色的项目,要不就是要收费的项目,我用相关文章使用opencv来换底色的话会把人物衣服等不属于背景的区域识别为背景,导致换底色的效果不佳,其他文章讲使用Backgroundremover的包也讲的比较的简略。索性自己弄一个,本项目使用的编译器为Pycharm,所需要从外网上下的包为BackgroundRemover,FFmpeg,Flask。

先上效果图:

前端页面:

图片为本人,涉及隐私就不放出来了。

原图是这样的

出的图是这样的:

准备:

项目开始前,我们需要下载BackgroundRemover,就是GitHub上面的开源项目。

链接:GitHub - nadermx/backgroundremover: Background Remover lets you Remove Background from images and video using AI with a simple command line interface that is free and open source.

把他随意放在一个文件夹(我的路径是:F:\Anaconda\myenvs\pytorch\backgroundremover-main)(我后面的代码也是这个路径,如果和我用一样的路径的话后面程序里就不用改路径了)我的Pycharm中的环境是我用anaconda所创建的,不是本地的环境,配置的和其他文章不太一样。

下载完的BackgroundRemover是这样的:

我们还需要在下u2net模型(csdn里有人分享),把他放在backgroundremover文件夹里的models里面。

然后需要下载FFmpeg,把FFmpeg的bin目录添加到本地电脑的环境变量里。

不知道怎么添加环境变量的话可以在CSDN里搜一下。

Conda环境中的Python版本需要大于3.6

可以根据上面BackgroundRemover里的语句执行一下,得在conda环境中执行。

还需要在conda环境中执行安装以下语句:

pip install flask

用于前端的使用。

接下来是主要代码:

import os
from PIL import Image
from flask import Flask, render_template, request, jsonify, send_file
from werkzeug.utils import secure_filename

app = Flask(__name__)


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


@app.route('/upload', methods=['POST'])
def upload_file():
    # 检查是否有文件被上传
    if 'image' not in request.files:
        return jsonify({'message': '没有文件被上传'}), 400
    file = request.files['image']

    # 如果用户没有选择文件,浏览器会提交一个空的文件名
    if file.filename == '':
        return jsonify({'message': '没有选择文件'}), 400
    if file:
        # 保存文件到服务器
        filename = secure_filename(file.filename)  # 安全文件名
        print(filename)
        try:
            os.makedirs('F:/PycharmProjects/Swapbackgroundcolor/photo/', exist_ok=True)
            print("文件夹 创建成功!")
        except OSError as e:
            print(f"创建文件夹时发生错误: {e}")
        file.save(os.path.join('F:/PycharmProjects/Swapbackgroundcolor/photo/', filename))

        # 去背景的图片路径
        temp_path = "cg_output.jpg"
        outName = filename.split('.')[0] + "-out.png"

        # 输出
        out_path = "photo/" + outName
        # 要替换的背景颜色
        color = request.form.get('color')
        # 红:red、蓝:blue、黑:black、白:white
        print(color)
        # 去掉背景颜色h
        current_directory = os.getcwd()
        new_directory = "F:/Anaconda/myenvs/pytorch/backgroundremover-main"
        os.chdir(new_directory)
        input_image_path = current_directory + "\\photo\\" + filename
        print(input_image_path)
        # input_image_path = current_directory + "/\"replace2.jpg\""
        out_image_path = current_directory + "\\photo\\" + filename
        python_path = "F:/Anaconda/myenvs/pytorch/python.exe"
        #这一步为执行去背景的语句,十分重要
        #这一步是用python的os库来执行系统的语句,我们系统里已经有了backgroundremover和FFmpeg
        #所以可以执行来去背景
        command = (python_path + " -m " + 'backgroundremover.cmd.cli -i ' + input_image_path
                   + ' -mk -o F:\PycharmProjects\Swapbackgroundcolor\photo\cg_output.jpg')
        os.system(command)
        os.chdir(current_directory)
        # 加上背景颜色
        temp_path_pwd = "F:\PycharmProjects\Swapbackgroundcolor\photo/cg_output.jpg"
        no_bg_image = Image.open(temp_path_pwd, "r")
        x, y = no_bg_image.size
        new_image = Image.new('RGBA', no_bg_image.size, color=color)
        new_image.paste(no_bg_image, (0, 0, x, y), no_bg_image)
        new_image.save(out_path)
        return jsonify({'img': 'get/' + outName}), 200


@app.route('/get/<filename>', methods=['Get'])
def get(filename):
    return send_file(os.path.join('F:\PycharmProjects\Swapbackgroundcolor\photo', filename), as_attachment=False)


if __name__ == '__main__':
    app.run(debug=True)

本程序的思路是把前端传来的照片放入文件夹中,文件夹会生成一个去掉人物背景的照片,然后再通过Image包的工具来填色。输出会输出到前端页面里,也会在后端生成文件(名为输入文件名+-out格式)

得注意的是,输出格式得为JPG格式的,PNG文件好像不能用'RGBA'模式来编码(不太懂,这方面只是套用了别的程序,没有具体研究)

附前端页面代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片换色工具</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            padding: 20px;
        }

        #app {
            background-color: #fff;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 20px;
        }

        input[type="file"] {
            display: block;
            margin: 0 auto;
            margin-bottom: 10px;
            padding: 10px;
            font-size: 16px;
        }

        .color-buttons {
            text-align: center;
            margin-bottom: 20px;
        }

        .color-button {
            display: inline-block;
            padding: 10px 20px;
            margin: 0 5px;
            border-radius: 4px;
            color: #fff;
            cursor: pointer;
        }

        #redButton {
            background-color: #f44336;
        }

        #blueButton {
            background-color: #2196f3;
        }

        #whiteButton {
            background-color: #fff;
            color: #333;
            border: 1px solid #ccc;
        }

        #generateButton {
            display: block;
            margin: 0 auto;
            padding: 15px 30px;
            font-size: 18px;
            background-color: #4caf50;
            color: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }

        #preview {
            margin: 0 auto;
            max-width: 100%;
            max-height: 400px;
            border-radius: 5px;
            overflow: hidden;
            background-size: cover;
            background-position: center;
        }
        .img-show{
            position:center;
            width: 50%;
            height: auto
        }
    </style>
</head>
<body>

<div id="app">
    <h1>图片换色工具</h1>
    <input type="file" id="imageUpload" accept="image/*">
    <div class="color-buttons">
        <button class="color-button" id="redButton">红色</button>
        <button class="color-button" id="blueButton">蓝色</button>
        <button class="color-button" id="whiteButton">白色</button>
    </div>
    <button id="generateButton">生成新图片</button>
    <!-- 用于显示图片的img标签 -->
     <img id="image" src="" class="img-show">
    <div id="preview"></div>
</div>

<script>
    var file
    var color
    document.querySelector('#redButton').addEventListener('click', function () {
        color = 'red'
    })
    document.querySelector('#blueButton').addEventListener('click', function () {
        color = 'blue'
    })
    document.querySelector('#whiteButton').addEventListener('click', function () {
        color = 'white'
    })
    document.querySelector('#generateButton').addEventListener('click', function () {

        // 检查是否有文件被选中
        if (file) {
            if (!color) {
                window.alert("未选择颜色")
                return
            }
            // 获取文件的基本信息
            const fileName = file.name;
            const fileSize = file.size;
            const fileType = file.type;

            // 打印文件信息到控制台
            console.log('File Name:', fileName);
            console.log('File Size:', fileSize, 'bytes');
            console.log('File Type:', fileType);
            // 创建一个FormData实例
            const formData = new FormData();

            // 检查是否有文件被选中

            // 将文件添加到FormData实例中
            formData.append('image', file);
            formData.append('color', color);
            // 创建一个包含上传URL的对象
            const uploadURL = '/upload'; // 替换为你的上传URL

            // 使用Fetch API发送POST请求
            fetch(uploadURL, {
                method: 'POST', // 使用POST方法上传文件
                body: formData, // 将FormData实例作为请求体发送
            })
                .then(response => {
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json()
                })
                .then(data => {
                    console.log(data)
                    document.getElementById('image').src = data.img;
                    console.log('上传成功:', data); // 处理上传成功后的响应数据
                })
                .catch(error => {
                    console.error('上传失败:', error); // 处理上传过程中的错误
                });
        } else {
            window.alert('未选择图片')
        }
    });

    document.querySelector('#imageUpload').addEventListener('change', function () {
        // 文件选择后的处理逻辑
        file = this.files[0];
    });
</script>

</body>
</html>

相关知识掌握不全,可能有些地方写的有问题。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值