天天看點

使用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圖像把原圖中的背景部分全部置為透明狀态了,這是一次比較成功的摳圖。