天天看点

使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】

先上代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
# 图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601
# OpenCV的版本为4.1

import cv2 as cv
import sys
import numpy as np
import matplotlib.pyplot as plt


if __name__ == '__main__':
    # 读取图像并判断是否读取成功
    img = cv.imread('../images/food-01.jpg')
    if img is None:
        print('Failed to read food-01.jpg.')
        sys.exit()
    else:
        # 使用cv.merge()函数添加alpha通道
        zeros = np.ones(img.shape[:2], dtype=img.dtype) * 100
        result_BGR_alpha = cv.merge([img, zeros])
        print('原图的通道数为:{}'.format(img.shape[2]))
        print('处理后的通道数为:{}'.format(result_BGR_alpha.shape[2]))

        # 图像保存到硬盘
        cv.imwrite('../results/food-01.png', result_BGR_alpha)

        # 以下代码为图像展示
        # 因为opencv的颜色通道顺序为[B,G,R],而matplotlib的颜色通道顺序为[R,G,B],
        # 所以作图前要先进行通道顺序的调整。
        result_RGB_alpha = result_BGR_alpha[:, :, (2, 1, 0, 3)]
        img_RGB = img[:, :, (2, 1, 0)]

        # 以下开始绘制图形并显示
        plt.figure()
        plt.subplot(1, 2, 1)  # 将画板分为一行两列,接下来要绘的图位于第一个位置
        plt.title('Original image')
        plt.imshow(img_RGB)
        plt.subplot(1, 2, 2)  # 将画板分为一行两列,接下来要绘的图位于第二个位置
        plt.title('Add alpha channel image')
        plt.imshow(result_RGB_alpha)
        plt.show()

           

运行结果如下图所示:

使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】
使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】

下面对程序进行说明。

1 图像的alpha通道有什么用?

答:一个图像的每个像素都有 BGR 三个通道,后来有个名叫Alvy Ray Smith 提出每个像素再增加一个 Alpha 通道,取值为0到1(当然,在咱们程序中是从0到255),用来储存这个像素是否对图片有「贡献」,0代表透明、1或255代表不透明。也就是说,「Alpha 通道」储存一个值,这个值与原图像中的值作了运算后,其外在表现是「透明度」。 当然,简单的理解就是Alpha 通道可以控制图像的透明度。

2 opencv中的merge()函数用于合并若干个相同尺寸(size)和深度(depth)的矩阵。

merge()函数的原型有两种,分别介绍如下:

第一种原型:

C++

Python:

参数意义如下:

mv—input array of matrices to be merged; all the matrices in mv must have the same size and the same depth.(翻译:将要被合并的矩阵数组,矩阵数组中的每个矩阵都要相同的尺寸和深度,什么叫矩阵数组?下面代码中的“channels”就是一个矩阵数组,它由3个矩阵元素组成,这3个矩阵元素分别为m1、m2、m3)

Mat m1 = (Mat_<uchar>(2,2) << 1,4,7,10);
 Mat m2 = (Mat_<uchar>(2,2) << 2,5,8,11);
 Mat m3 = (Mat_<uchar>(2,2) << 3,6,9,12);
 Mat channels[3] = {m1, m2, m3};
           

count—number of input matrices when mv is a plain C array; it must be greater than zero.(翻译:需要合并的矩阵数目,它必须是大于0的数)

dst—output array of the same size and the same depth as mv[0]; The number of channels will be equal to the parameter count.(翻译:合并之后的矩阵,它的尺寸和深度与mv[0]矩阵的尺寸和深度一致,它的通道数就是参数count)

第二种原型:

C++

Python:

参数mv和dst的意义和第一个原型基本相同,这里就不多赘述了。只是要注意这里的mv的类型为InputArrayOfArrays,直译为用于输入的矩阵数组的数组,即它是一个二维数组。

我们这里的程序是用Python写成的,两种原型对于Python编程来说都没有区别,所以不用去区分到底是第一种原型还是第二种原型。

3 为什么不用opencv的imshow()函数显示图像?

答:因为opencv的imshow()函数并不能把带图片的alpha通道的效果显示出来。

文末再附一个利用merge()函数和图像alpha通道的例子:

该例子利用图像的轮廓图生成alpha通道,然后利用merge()函数将alpha通道融合到原BGR图像中,最终得到带透明度信息的png图像。在效果上体现为将手绘的图形从纸上抠出(即手绘图的抠图实现)

原BGR图像如下(名字“jing_ling_300_400.jpg”):

使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】

其带填充效果的轮廓如下(名字“JL_Contours_01.bmp”):

使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】

可用下面的代码生成名字为JL_image_BGR_alpha.png的图像,该图像把原图中的背景部分全部置为透明状态了。

# 博主微信/QQ 2487872782
# 有问题可以联系博主交流
# 有图像处理需求也请联系博主
# 图像处理技术交流QQ群 271891601

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# OpenCV的版本为4.1

import numpy as np
import cv2 as cv
import sys

image_contours1 = cv.imread('F:/material/images/2022/2022-06/JL_Contours_01.bmp', 0)
image_src = cv.imread('F:/material/images/2022/2022-06/jing_ling_300_400.jpg')

if image_contours1 is None:
    print('Error: Could not load image')
    sys.exit()

if image_src is None:
    print('Error: Could not load image')
    sys.exit()

alpha_channel = np.zeros(image_src.shape[0:2], image_src.dtype)

img_row = image_contours1.shape[0]
img_col = image_contours1.shape[1]

for i in range(img_row):
    for j in range(img_col):
        temp1 = image_contours1[i, j]
        if temp1 > 200:
            alpha_channel[i, j] = 255

image_BGR_alpha = cv.merge([image_src, alpha_channel])

# cv.imshow(' alpha_channel', alpha_channel)
cv.imwrite('F:/material/images/2022/2022-06/JL_image_BGR_alpha.png', image_BGR_alpha)

           

运行生成的JL_image_BGR_alpha.png图像如下图所示:

使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】
使用opencv中的merge()函数为BGR图像添加alpha通道【额外再附一个手绘图抠图的例子】

可见,输出的png图像把原图中的背景部分全部置为透明状态了,这是一次比较成功的抠图。