目录
OpenCV-Python实现绿幕图像抠图
python利用蒙版批量抠图并实现透明化
jpeg格式图片进行批量背景透明化处理
PIL检测图片是否包含透明通道
- boy.png:最终结果保存的图片
(1)input.jpg图片:
完整代码:
# -*-coding:utf-8-*-
import cv2 as cv
import numpy as np
"""
OpenCV-Python实现绿幕图像抠图
"""
def image_matting(image_path: str):
# todo 读取并转换图片格式
img = cv.imread(image_path, cv.IMREAD_COLOR)
cv.imshow('input', img) # 将图像在特定的窗口进行显示
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) # Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像,参数CV_RGB2GRAY是RGB到gray
# cv.imshow('hsv', hsv)
# todo 确定绿色范围
"""
cv.inRange(src, lowerb, upperb):根据像素的范围进行过滤,把符合像素范围的保留,赋值0,黑色;不符合的赋值255,白色。
src:需要处理的图像
lowerb:最小像数值
upperb:最大像素值
"""
mask = cv.inRange(hsv, (35, 43, 46), (77, 255, 255))
# cv.imshow('cc', mask)
# todo 确定非绿色范围
mask = cv.bitwise_not(mask) # 非:cv.bitwise_not(img),将图像按位取反操作。
# todo 通过掩码控制的按位与运算锁定绿色区域
result = cv.bitwise_and(img, img, mask=mask) # 只在mask区域做与运算 与:cv.bitwise_and(img1,img2),两幅图像按位进行与操作;
# cv.imshow('mask', mask)
# todo 显示图片验证结果
cv.imshow('result', result)
# 保存带有透明通道的png图片, 有了这种素材之后,就可以给这张图片替换任意背景了
cv.imwrite('boy.png', result)
cv.waitKey(0)
cv.destroyAllWindows()
# canny边缘检测 和轮廓提提取方法
if __name__ == '__main__':
path = 'img.jpg'
image_matting(path)
(3)可以看到执行结果,
而且,最终结果保存的图片boy.png为:
步骤:
- 如果input图片为jpeg格式图片,那么就需要进行第一步操作 :将tt文件夹里的jpeg格式图片“imput.jpeg”先转化为png格式。
- 利用蒙版批量抠图并实现透明化
(1)将tt文件夹里的jpeg格式图片“imput.jpeg”先转化为png格式,
代码为:
def change_png():
'''将批量的jpeg图片转为png格式'''
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
if file.endswith('jpeg'):
# 要指明重命名之后的路径
src = os.path.join(file_path, file)
r_name = file.split('.')[0] + '.png'
dct = os.path.join(file_path, r_name)
os.rename(src, dct)
count = count + 1
print('count:', count)
if __name__ == "__main__":
change_png()
可以看到转换结果是,
(2)得到图片的蒙版mask,利用蒙版批量抠图并实现透明化,
import cv2, os
from PIL import Image
import numpy as np
def change_png():
'''将批量的jpeg图片转为png格式'''
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
if file.endswith('jpeg'):
# 要指明重命名之后的路径
src = os.path.join(file_path, file)
r_name = file.split('.')[0] + '.png'
dct = os.path.join(file_path, r_name)
os.rename(src, dct)
count = count + 1
print('count:', count)
def get_mask():
'''得到图片的蒙版mask'''
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
image_path = file_path + '/' + file
print(image_path)
# todo 读取并转换图片格式
img = cv2.imread(image_path, cv2.IMREAD_COLOR)
# cv2.imshow('input', img) # 将图像在特定的窗口进行显示
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像,参数CV_RGB2GRAY是RGB到gray
# cv.imshow('hsv', hsv)
# todo 确定绿色范围
"""
cv.inRange(src, lowerb, upperb):根据像素的范围进行过滤,把符合像素范围的保留,赋值0,黑色;不符合的赋值255,白色。
src:需要处理的图像
lowerb:最小像数值
upperb:最大像素值
"""
mask = cv2.inRange(hsv, (35, 43, 46), (77, 255, 255))
# cv.imshow('cc', mask)
# todo 确定非绿色范围
mask = cv2.bitwise_not(mask) # 非:cv.bitwise_not(img),将图像按位取反操作。
# todo 通过掩码控制的按位与运算锁定绿色区域
result = cv2.bitwise_and(img, img, mask=mask) # 只在mask区域做与运算 与:cv.bitwise_and(img1,img2),两幅图像按位进行与操作;
# cv2.imshow('mask22', mask)
cv2.imwrite('mask/' + file.split('.')[0] +'_mask.jpg' , mask)
count += 1
print('count:', count)
class UnsupportedFormat(Exception):
def __init__(self, input_type):
self.t = input_type
def __str__(self):
return "不支持'{}'模式的转换,请使用为图片地址(path)、PIL.Image(pil)或OpenCV(cv2)模式".format(self.t)
class MatteMatting():
def __init__(self, original_graph, mask_graph, input_type='path'):
"""
将输入的图片经过蒙版转化为透明图构造函数
:param original_graph:输入的图片地址、PIL格式、CV2格式
:param mask_graph:蒙版的图片地址、PIL格式、CV2格式
:param input_type:输入的类型,有path:图片地址、pil:pil类型、cv2类型
"""
if input_type == 'path':
self.img1 = cv2.imread(original_graph)
self.img2 = cv2.imread(mask_graph)
elif input_type == 'pil':
self.img1 = self.__image_to_opencv(original_graph)
self.img2 = self.__image_to_opencv(mask_graph)
elif input_type == 'cv2':
self.img1 = original_graph
self.img2 = mask_graph
else:
raise UnsupportedFormat(input_type)
@staticmethod
def __transparent_back(img):
"""
:param img: 传入图片地址
:return: 返回替换白色后的透明图
"""
img = img.convert('RGBA')
L, H = img.size
color_0 = (255, 255, 255, 255) # 要替换的颜色
for h in range(H):
for l in range(L):
dot = (l, h)
color_1 = img.getpixel(dot)
if color_1 == color_0:
color_1 = color_1[:-1] + (0,)
img.putpixel(dot, color_1)
return img
def save_image(self, path, mask_flip=False):
"""
用于保存透明图
:param path: 保存位置
:param mask_flip: 蒙版翻转,将蒙版的黑白颜色翻转;True翻转;False不使用翻转
"""
if mask_flip:
img2 = cv2.bitwise_not(self.img2) # 黑白翻转
image = cv2.add(self.img1, img2)
image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) # OpenCV转换成PIL.Image格式
img = self.__transparent_back(image)
img.save(path)
@staticmethod
def __image_to_opencv(image):
"""
PIL.Image转换成OpenCV格式
"""
img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
return img
@staticmethod
def __image_to_opencv(image):
"""
PIL.Image转换成OpenCV格式
"""
img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
return img
if __name__ == '__main__':
# change_png()
get_mask()
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
image_path = file_path + '/' + file
mask_path = 'mask/'+ file.split('.')[0] +'_mask.jpg'
output_path = 'output/'+ file.split('.')[0] +'_output.png'
mm = MatteMatting(image_path, mask_path)
mm.save_image(output_path, mask_flip=True) # mask_flip是指蒙版翻转,即把白色的变成黑色的,黑色的变成白色的
count += 1
print('count:', count)
执行截图:
(3)可以看到执行的结果,
步骤:
- 如果input图片为jpeg格式图片,那么就需要进行第一步操作 :将tt文件夹里的jpeg格式图片“imput.jpeg”先转化为png格式。
- 批量背景透明化处理
(1)将tt文件里的jpeg格式图片“imput.jpeg”先转化为png格式,
代码为:
def change_png():
'''将批量的jpeg图片转为png格式'''
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
if file.endswith('jpeg'):
# 要指明重命名之后的路径
src = os.path.join(file_path, file)
r_name = file.split('.')[0] + '.png'
dct = os.path.join(file_path, r_name)
os.rename(src, dct)
count = count + 1
print('count:', count)
if __name__ == "__main__":
change_png()
可以看到转换结果是,
(2)绿色背景png格式图片背景透明化处理
补充:可以用这个网页RGB(255,0,255),#FF00FF 颜色查询,颜色梯度,色彩搭配,色盲模拟 - RGB颜色查询 - 在线工具 - 字客网来将颜色转换为rgb值
代码:
import os
from PIL import Image
'''绿色背景png格式图片背景透明化处理'''
class Transcolor():
def __init__(self):
# 最后一位表示透明度
self.color_map = {
'white': (255, 255, 255, 0),
'black': (0, 0, 0, 0),
'green': (87, 211, 57, 0)
}
def process(self, image_file, old_bk, new_bk, text_color):
'''将图像特定颜色改为新颜色,前文改为设定颜色或者原始颜色'''
img = Image.open(image_file).convert("RGBA")
datas = img.getdata()
newData = []
for item in datas:
if self.is_around(item, old_bk):
newData.append(new_bk)
else:
newData.append(text_color if text_color else item)
img.putdata(newData)
return img
def transparent(self, image_file, bk_color='green', text_color=None):
# 透明化
bk = self.formulate(bk_color)
text_color = self.formulate(text_color) if text_color else None
return self.process(image_file, bk, (0, 0, 0, 0), text_color)
def is_around(self, color1, color2):
for i in range(3):
if abs(color1[i] - color2[i]) > 30:
return False
return True
def formulate(self, var): # 格式检查
if var in self.color_map.keys():
return self.color_map[var]
for n, i in enumerate(var):
if i < 0 or i > 255 or n >= 4:
print('Error:请输入white|black|phote_w|(220,220,220,0)RGBA形式')
exit(1)
return var
if __name__ == "__main__":
t = Transcolor()
photo_dir = 'tt'
for i in os.listdir(photo_dir):
if os.path.splitext(i)[1].lower() in ['.jpg', '.png', '.jpeg', '.bmp']:
path = os.path.join(photo_dir, i)
t.transparent(path).save(path)
(3)可以看到背景透明化处理之后的结果是,
import os
from PIL import Image
'''绿色背景jpeg格式图片进行批量背景透明化处理'''
def change_png():
'''将批量的jpeg图片转为png格式'''
file_path = "tt"
count = 0
files = os.listdir(file_path)
for file in files:
if file.endswith('jpeg'):
# 要指明重命名之后的路径
src = os.path.join(file_path, file)
r_name = file.split('.')[0] + '.png'
dct = os.path.join(file_path, r_name)
os.rename(src, dct)
count = count + 1
print('count:', count)
class Transcolor():
def __init__(self):
# 最后一位表示透明度
self.color_map = {
'white': (255, 255, 255, 0),
'black': (0, 0, 0, 0),
'green': (35, 43, 46, 0)
}
def process(self, image_file, old_bk, new_bk, text_color):
'''将图像特定颜色改为新颜色,前文改为设定颜色或者原始颜色'''
img = Image.open(image_file).convert("RGBA")
datas = img.getdata()
newData = []
for item in datas:
if self.is_around(item, old_bk):
newData.append(new_bk)
else:
newData.append(text_color if text_color else item)
img.putdata(newData)
return img
def transparent(self, image_file, bk_color='green', text_color=None):
'''透明化'''
bk = self.formulate(bk_color)
text_color = self.formulate(text_color) if text_color else None
return self.process(image_file, bk, (0, 0, 0, 0), text_color)
def is_around(self, color1, color2):
for i in range(3):
if abs(color1[i] - color2[i]) > 30:
return False
return True
def formulate(self, var): # 格式检查
if var in self.color_map.keys():
return self.color_map[var]
for n, i in enumerate(var):
if i < 0 or i > 255 or n >= 4:
print('Error:请输入white|black|phote_w|(220,220,220,0)RGBA形式')
exit(1)
return var
if __name__ == "__main__":
# change_png()
t = Transcolor()
photo_dir = 'imgs'
for i in os.listdir(photo_dir):
if os.path.splitext(i)[1].lower() in ['.jpg', '.png', '.jpeg', '.bmp']:
path = os.path.join(photo_dir, i)
t.transparent(path).save(path)
print("完成")
- 执行的结果为True,说明我们经过透明化处理的图片是包含透明通道。
from PIL import Image
'''PIL检测图片是否包含透明通道'''
def has_transparency(img):
if img.mode == "P":
transparent = img.info.get("transparency", -1)
for _, index in img.getcolors():
if index == transparent:
return True
elif img.mode == "RGBA":
extrema = img.getextrema()
if extrema[3][0] < 255:
return True
return False
if __name__ == "__main__":
# extract_alpha("./13.png")
image = Image.open("output/input_output.png")
print(has_transparency(image))
可以看到执行的结果为True,说明我们经过透明化处理的图片是包含透明通道。