先上代碼:
#!/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()
運作結果如下圖所示:
下面對程式進行說明。
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”):
其帶填充效果的輪廓如下(名字“JL_Contours_01.bmp”):
可用下面的代碼生成名字為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圖像如下圖所示:
可見,輸出的png圖像把原圖中的背景部分全部置為透明狀态了,這是一次比較成功的摳圖。