前言
我翻阅了国内网上没有找到一个可以随意换底色的项目,要不就是要收费的项目,我用相关文章使用opencv来换底色的话会把人物衣服等不属于背景的区域识别为背景,导致换底色的效果不佳,其他文章讲使用Backgroundremover的包也讲的比较的简略。索性自己弄一个,本项目使用的编译器为Pycharm,所需要从外网上下的包为BackgroundRemover,FFmpeg,Flask。
先上效果图:
前端页面:
图片为本人,涉及隐私就不放出来了。
原图是这样的
出的图是这样的:
准备:
项目开始前,我们需要下载BackgroundRemover,就是GitHub上面的开源项目。
把他随意放在一个文件夹(我的路径是: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>
相关知识掌握不全,可能有些地方写的有问题。