python之 ffmpeg+opencv绿幕抠图,蒙版绿幕抠图,透明化处理,PIL检测图片是否包含透明通道

目录

OpenCV-Python实现绿幕图像抠图

python利用蒙版批量抠图并实现透明化

jpeg格式图片进行批量背景透明化处理

PIL检测图片是否包含透明通道


OpenCV-Python实现绿幕图像抠图

  • 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为:

  

python利用蒙版批量抠图并实现透明化

步骤:

  • 如果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)可以看到执行的结果,

 

jpeg格式图片进行批量背景透明化处理

步骤:

  • 如果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("完成")

PIL检测图片是否包含透明通道

  • 执行的结果为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,说明我们经过透明化处理的图片是包含透明通道。

猜你喜欢

转载自blog.csdn.net/qq_45956730/article/details/125596129