一、背景
生活中,有的时候我们需要不同颜色的背景图片,电子档或者打印出的图片。当我们手上正好有某一种背景颜色的图片,却又不想花钱去打印店拍摄照片时,我们就会通过ps等工具进行颜色背景的替换,然而对于手残党的我们却始终无法很好的抠图。此时,我们就会希望有一个好的工具替我们来完成背景替换操作,于是乎,小妖就来教大家一个怎么完成颜色背景和前景融合的方法。
二、说明
2.1. 接口调用说明
我们引入的是removebg的api接口,所以每月会有次数限制(remove.bg官网上写的是一个月50次,基本够我们使用),嫌麻烦的话可以直接去removebg的官网进行抠图替换背景,这里只是帮助大家一起了解一下如何通过python+opencv的程序来实现。
2.2 API key获取位置
三、实现代码
import os
import numpy as np
import cv2
from typing import List
from removebg import RemoveBg as RmBg
"""
移除图片背景,并替换成纯色背景
"""
class RemoveImgBg:
# 换成自己的api key,每月有50次调用机会
API_KEY = "xxxxx"
def __init__(self, file_name, error_log_file="error.log"):
# 传入的图片名
self.src_img = file_name
# 生成的图片名
self.des_img = ""
# 移除背景时,调用api报错
self.error_log_file = error_log_file
def rm_bg(self):
"""
移除图片的背景
:return:
"""
rmbg = RmBg(self.API_KEY, self.error_log_file)
rmbg.remove_background_from_img_file(self.src_img)
def rename_no_bg_img(self):
"""
重命名接口返回的图片名
:return:
"""
src_img_name = f"{self.src_img}_no_bg.png"
dest_img_name = f"{self.src_img.split('.')[0]}_no_bg.png"
if os.path.exists(src_img_name):
os.rename(src_img_name, dest_img_name)
self.des_img = dest_img_name
else:
if os.path.exists(dest_img_name):
self.des_img = dest_img_name
def change_bg_color(self, color: List[int], file_name: str):
"""
给图片的添加上纯色
:param color:
:param file_name:
:return:
"""
# 读取png图片, -1代表获取alpha通道
fore_image = cv2.imread(self.des_img, -1)
# 拆分png的4个通道
b, g, r, a = cv2.split(fore_image)
# 图片的高, 宽
rows = fore_image.shape[0]
cols = fore_image.shape[1]
# 得到PNG图像前景部分,在这个图片中就是除去 Alpha通道的部分
foreground = cv2.merge((b, g, r))
# 得到PNG图像的alpha通道,即alpha掩模
alpha = cv2.merge((a, a, a))
img = np.ones((rows, cols), dtype=np.uint8)
# 新建一个图层,默认为单通道图层
background = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 将单通道转化成3通道Mat
# 设置背景图层的颜色
background[:, :, 0] = color[0]
background[:, :, 1] = color[1]
background[:, :, 2] = color[2]
# 因为下面要进行乘法运算故将数据类型设为float,防止溢出
foreground = foreground.astype(float)
background = background.astype(float)
# 将alpha的值归一化在0-1之间,作为加权系数
alpha = alpha.astype(float) / 255
# 将前景和背景进行加权,每个像素的加权系数即为alpha掩模对应位置像素的值,前景部分为1,背景部分为0
# 采用了正片叠底的方法 即 任何像素与黑色相乘为黑色,与白色相乘不变
# 公式: 混合色 * 基色 / 255
foreground = cv2.multiply(alpha, foreground) # 此时即相当于原图的png,黑色背景,混合色为(0~1)
background = cv2.multiply(1 - alpha, background) # 背景图去除前景的部分为黑色,其它部分为背景色偏暗
out_image = foreground + background
# """测试时, opencv的imshow函数在显示double,对其认为是0~1,而大于1的地方都为白色,所以需要除以255"""
# cv2.imshow("outImage", out_image / 255)
# cv2.waitKey(0)
cv2.imwrite(file_name, out_image)
def run(self):
# self.rm_bg()
self.rename_no_bg_img()
# [255, 255, 255]为替换的纯色(rgb,每一个颜色值为0-255)
# xxxx.jpg 为生成的图片名
self.change_bg_color([0, 124, 255], "xxxx.jpg")
if __name__ == '__main__':
# 需要移除背景的图片
remove_bg = RemoveImgBg("xxx.jpg")
remove_bg.run()
四、生成的结果(动漫)
4.1 原图:
4.2 移除背景图
4.3 填充纯色图片
四、生成的结果(人像)
4.1 原图
4.2 移除背景图
4.3 填充纯色图片
五、补充说明
纯色填充的值为rgb,具体想要替换颜色值小伙伴们可以自行搜索,或者通过颜色提取工具提取