目录
- boy.png:最终结果保存的图片
(1)input.jpg图片:
(2)执行代码,
完整代码:
- # -*-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)可以看到背景透明化处理之后的结果是,
(4)完整代码:
- 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,说明我们经过透明化处理的图片是包含透明通道。