1、引言
在《OpenCV-Python圖像的加法運算cv2.add函數詳解》及《OpenCV-Python圖像的減法運算cv2.subtract函數詳解以及和矩陣減法的差別對比》詳細介紹了圖像的加法運算和減法運算,有加減法就有乘除法,本文介紹圖像的乘法運算。html
圖像的乘法有三種,具體參考《對OpenCV中3種乘法操做的理解掌握》,咱們在此只關注最後一種,也即cv2.multiply函數提供的乘法。對於兩個圖像矩陣A、B來講:
該種方式的乘法計算方法以下:
python
2、圖像乘法cv2.multiply的語法
調用語法:
multiply(src1, src2, dst=None, scale=None, dtype=None)
算法
參數說明:
OpenCV手冊介紹的乘法相關語法內容解讀以下:windows
- src1:做爲被乘數的圖像數組
- src2:做爲乘數的圖像數組,大小和類型與src1相同
- dst:可選參數,輸出結果保存的變量,默認值爲None,若是爲非None,輸出圖像保存到dst對應實參中,其大小和通道數與輸入圖像相同,圖像的深度(即圖像像素的位數)由dtype參數或輸入圖像肯定
- scale:可選的結果圖像縮放因子,即在src1*src2的基礎上再乘scale
- mask:圖像掩膜,可選參數,爲8位單通道的灰度圖像,用於指定要更改的輸出圖像數組的元素,即輸出圖像像素只有mask對應位置元素不爲0的部分才輸出,不然該位置像素的全部通道份量都設置爲0
- dtype:可選參數,輸出圖像數組的深度,即圖像單個像素值的位數(如RGB用三個字節表示,則爲24位)。
- 返回值:相乘的結果圖像
3、圖像乘法cv2.multiply的使用場景
關於src1和src2這兩個輸入數據上,OpenCV幫助文檔中乘法和加法、減法的說明不同,加法和減法中可使用標量,而在乘法中說明是兩者必須大小和類型相同,沒有說可使用標量。咱們參考加減法的模式來進行驗證說明。數組
本部分處理案例的源圖像使用圖片imgs.jpg是一張多個OpenCV處理經典圖像的合集,圖像以下:
因爲圖像比較大很差截圖,所以後面讀取圖像時將其強制調整爲1000*750.app
3.一、src2爲標量的狀況
以一副圖像和一個標量相乘來觀察,代碼以下:函數
import numpy as np import cv2 def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) imgMultiply = cv2.multiply(img,1.2) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
咱們經過程序調試來觀察相乘的結果,在顯示圖片前設置斷點,觀看相關變量數據,如圖:
從上述標黃色部分的矩陣通道值能夠看出,直接用一個常數標量相乘後,原圖像矩陣的像素後2個通道值在結果圖像中所有爲0。繼續運行顯示圖像以下:
能夠看到圖像爲藍色,與上面三通道只留了第一個通道藍色通道的數據的一致。ui
3.二、src2爲一個四元組
在前面介紹加減法時說明了OpenCV在對標量運算時轉爲了四元組進行運算,所以在此咱們將上面案例的標量改成四元組再驗證。代碼以下:spa
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) imgMultiply = cv2.multiply(img,(1.5,1.5,1.5,1.5)) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
經跟蹤觀察,全部像素通道份量都乘以了1.5,超過255的按飽和運算模式置爲255.顯示圖像以下:.net
上圖跟原圖對比,亮度明顯加強。實際上當src2設置爲一個元素值相等的四元組時,其效果等同於設置爲四個元素爲1的四元組和圖像設置縮放因子爲該元素值的狀況。咱們將上述代碼調整爲以下:
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) imgMultiply = cv2.multiply(img,(1,1,1,1),scale=0.5) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
注意:縮放因子以前還有個可選參數dst,所以須要用關鍵字參數形式。
對應結果圖像以下:
能夠看到圖像亮度明顯變暗,但對比度沒有變化。
綜合3.1和3.2驗證的狀況(老猿的驗證環境爲OpenCV-Python4.3.0.36,windows版本),src2能夠是一個四元組,當咱們想使用multiply調整圖像亮度時,可使用src2爲一個四元組,該四元組的全部元素值即爲要調整的亮度因子,也可使用元素全爲1的四元組疊加scale調整因子的狀況來實現。但這2種形式在OpenCV幫助文檔中沒有說明,所以雖然如今可行但老猿不建議使用。若是要直接調整圖像的亮度,建議直接進行矩陣和標量的算術乘法便可,只是須要注意要採用飽和運算模式。
3.三、彩色圖像數組和掩膜圖像數組相乘
使用以下代碼進行彩色圖像和掩膜圖像的乘法運算:
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) mask = np.ones(img.shape[:2],np.uint8) mask[100:200,100:200] = 0 imgMultiply = cv2.multiply(img,mask,scale=0.5) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
執行時報錯:
"C:\Program Files\Python38\python.exe" F:/study/python/project/cvtest/cvtest.py Traceback (most recent call last): File "F:/study/python/project/cvtest/cvtest.py", line 100, in <module> main() File "F:/study/python/project/cvtest/cvtest.py", line 94, in main imgMultiply = cv2.multiply(img,mask,scale=0.5) cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp:669: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'cv::arithm_op'可見不能這樣操做。
3.四、彩色圖像數組和彩色圖像數組相乘
咱們使用以下代碼構建兩個彩色圖像數組的乘法運算,其中的第二個圖像是基於原圖像一樣大小和通道數的矩陣圖像,其元素取值只有0和1:
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) mask = np.ones(img.shape,np.uint8) mask[500:650,10:300] = 0 imgMultiply = cv2.multiply(img,mask,scale=0.8) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
執行後結果圖像截圖:
能夠看到左下角圖片部分被黑色替代,若是想使用白色替代,將mask設置爲0的通道調整爲一個比較大的值使得相乘時飽和運算後值爲255便可。如:
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) mask = np.ones(img.shape,np.uint8) mask[500:650,10:300] = 100 imgMultiply = cv2.multiply(img,mask,scale=0.8) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
執行結果截圖:
能夠看到,經過這樣的兩個圖像相乘,能夠決定結果圖像哪些部分保留哪些部分清除。
3.五、彩色圖像飽和運算乘
若是兩副圖像相乘甚至是一副圖像自乘,因爲圖像自身像素通道值通常大於爲0或大於1的數,而圖像運算是飽和運算,就會致使兩副圖像任意一副爲黑色的部分在結果圖像中都爲黑色,而其餘部分通道值大部分都會大幅增加甚至達到飽和。
上面原圖自乘的代碼以下:
def main(): img = cv2.resize(cv2.imread(r'F:\pic\imgs.jpg'),(1000,750)) imgMultiply = cv2.multiply(img,img) cv2.imshow('img', img) cv2.imshow('imgMultiply', imgMultiply) cv2.waitKey(0) main()
自乘以後的結果圖像以下:
因此這種真正的兩副圖像相乘在低級圖像處理來講基本沒有意義,中高級圖像處理方面老猿沒有研究不清楚是否有特殊用途。
3.六、彩色圖像乘積的溢出處理
3.6.一、溢出的解決方式
圖像的單個通道值用一個無符號字節(numpy.uint8)表示,其值範圍在0-255以內,若是圖像像素通道值超出範圍時,OpenCV的飽和運算機制會將小於0的通道值置爲0,大於255的置爲255。但這種機制在某些狀況下會致使圖像像素通道值大範圍的被置爲255或0。例如從上面3.4能夠看到真正兩個圖像的乘積因爲飽和元素致使圖像大範圍白化。
爲了解決這個問題,能夠採用以下方法處理:
- 乘法時,將圖像乘積結果保存到通道值uint16或float32的矩陣中(因爲float32能夠保存小數,所以老猿建議爲float32),這可能有2種方式,一種是將原輸入圖像矩陣在執行乘運算前將其轉爲float32矩陣,二是原輸入圖像矩陣保持不變,將乘積保存到float32圖像矩陣,但老猿目前沒有在OpenCV-Python中找到第二種方式的實現,只驗證經過了先將輸入圖像轉爲float32的方式;
- 執行乘法的乘積矩陣進行歸一化處理。關於歸一化處理請參考《opencv中歸一化函數normalize()的原理講解》。
3.6.二、歸一化處理的算法考慮
使用OpenCV-Python的normalize函數的NORM_MINMAX模式將矩陣元素值歸到[0,255]區間範圍內時,OpenCV採用的算法是:
這個算法的思想是將原矩陣中最大元素值映射爲區間的上限如255,將原矩陣中最小元素值映射爲區間的下限如0,其餘中間值映射爲該值與矩陣中最小元素值的差與原矩陣中最大最小元素值差的比例乘以映射區間的乘積再加上映射區間下限值,即映射過程的線性變換是以原元素值與原矩陣最小值的差別值做爲線性變換的,而不是直接以元素值做爲線性變換的。
從算法上來講,這種方式比較科學,但老猿認爲圖像處理的狀況比較特殊,若是一副圖像所有是由深色圖像構成,全部像素的每一個通道值都比較大,就會致使圖像的乘積歸一化到[0-255]之間時差別會很小,而且圖像單通道都在[0-255]之間,所以兩個圖像的乘積特別是自乘的乘積理論上以0做爲下限來考慮進行歸一化處理可能在特定場景下更合理,固然在其餘歸一化場景下(如圖像加法)可能OpenCV採用的NORM_MINMAX模式更合理。
3.6.三、圖像自乘及歸一化處理案例
針對OpenCV-Python的歸一化和老猿考慮的歸一化兩種算法咱們來實現圖片imgs.jpg的圖像自乘以後的歸一化效果對比。對應代碼以下:
def main(): img = cv2.imread(r'F:\pic\imgs.jpg') img32 = img.astype(np.float32) imgMultiply = cv2.multiply(img32, img32) imgNormalizeOpenCV = cv2.normalize(imgMultiply,None,0,255,cv2.NORM_MINMAX) #opencv歸一化處理 #老猿的歸一化處理 maxv = np.max(imgMultiply) imgNormalizeLaoyuan = (imgMultiply / maxv) * 255 cv2.imshow('imgNormalizeOpenCV', imgNormalizeOpenCV.astype(np.uint8)) cv2.imshow('imgNormalizeLaoyuan', imgNormalizeLaoyuan.astype(np.uint8)) cv2.waitKey(0) main()
咱們將原圖、兩種歸一化處理的圖豎直疊加在一塊兒對比一下看看圖像自乘再歸一化處理的效果。下面圖片中第一行圖片是原圖的,第二行是OpenCV歸一化處理的,第三行是老猿的歸一化方式處理。
從上面圖片對照能夠看出,自乘歸一化處理後圖像的對比度增大,這是由於自乘後放大了差別,歸一化處理不會改變這種變化趨勢。同時能夠看到兩種歸一化處理圖像效果差很少,老猿沒有仔細分析數據,想來也差很少,這是由於imgs.jpg這幅圖像黑色和白色都存在,致使這兩種算法處理時實際結果應該基本相同。
4、小結:
本文詳細介紹了OpenCV-Python圖像乘法運算cv2.multiply函數的調用語法,並分析了OpenCV乘法的幾種使用場景以及圖像溢出的歸一化處理,經過這些分析能夠知道OpenCV圖像的乘法運算主要有三種做用:
- 圖像和標量的乘法能夠調節圖像的明暗度;
- 圖像和掩膜的乘法能夠控制輸出圖像的範圍;
- 圖像自乘能夠調節圖像的對比度。
更多OpenCV-Python的介紹請參考專欄《OpenCV-Python圖形圖像處理 》
博文地址:https://blog.csdn.net/laoyuanpython/category_9979286.html