【總結】OpenCV-Python常用API(四)—— 圖像矩陣處理(2)

1. 圖像矩陣按位操作

1.1 按位取反

1.1.1 函數簡述和原型

該函數用於對圖片矩陣數據中每個元素進行按位取反操作,往往對二值化的圖像進行該操作,使得黑色變成白色,白色變成黑色。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga0002cf8b418479f4cb49a75442baee2f

dst = cv2.bitwise_not(src[, mask])

1.1.2 參數

  • src:要按位取反的圖片數據;
  • mask:掩模,需要是與圖片大小一致的一個ndarray,元素爲uint8類型。一般來說是一個二值化的矩陣,即元素值不是0(黑色)就是255(白色),如果設置了該參數,則掩模中值爲255(白色)的像素纔會進行按位取反的操作,掩模中值爲0(黑色)的像素則直接忽略,該部分的結果也是黑色;

1.1.3 返回值

  • dst:按位取反後的圖像數據;

1.1.4 用法舉例

img = cv2.imread(r'.\image.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('origin', img)

# 先使用自適應均值——高斯法將圖像二值化
th = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 17, 6)
cv2.imshow('binarized', th)

# 創建一個掩模,僅右半部分爲白色,即僅關注圖像的右半部分
mask = np.zeros_like(th)
h, w = mask.shape
mask[:, int(w/2):] = 255
cv2.imshow('mask', mask)

th_inv = cv2.bitwise_not(th, mask=mask)
cv2.imshow('binary inverse', th_inv)

1.1.5 實例展示

按位取反

1.2 按位與

1.2.1 函數簡述和原型

該函數用於對兩個一樣大小的圖片矩陣數據中的每個像素值進行按位與操作。實際應用中往往將某張圖片與自身進行按位與操作,再與mask參數結合,提取出掩模中不爲0的部分在圖像中對應的位置。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga60b4d04b251ba5eb1392c34425497e14

dst = cv2.bitwise_and(src1, src2[, mask])

1.2.2 參數

  • src1:按位與操作的第一張圖片數據;
  • src2:按位與操作的第二張圖片數據,大小需要與第一張圖片一致;
  • mask:掩模,需要是與按位與的兩張圖片大小一致的一個ndarray,元素爲uint8類型。一般來說是一個二值化的矩陣,即元素值不是0(黑色)就是255(白色),如果設置了該參數,則掩模中值爲255(白色)的像素纔會進行按位與操作,掩模中值爲0(黑色)的像素則直接忽略,該部分的結果也是黑色;

1.2.3 返回值

  • dst:按位與操作後的圖像數據;

1.2.4 用法舉例

img = cv2.imread(r'.\image.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Origin', img)

# 創建一個掩模,僅右半部分爲白色,即僅關注圖像的右半部分
mask = np.zeros_like(img)
h, w = img.shape
mask[:, int(w/2):] = 255
cv2.imshow('Mask', mask)

# 將圖像與自身按位與,結合mask參數僅提取圖像的右半部分
bitAnd = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow('BitwiseAnd', bitAnd)

1.2.5 實例展示

按位與

1.3 按位異或

1.3.1 函數簡述和原型

該函數用於對兩個一樣大小的圖片矩陣數據中的每個像素值進行按位異或操作,主要目的即爲尋找出兩個圖像中不同的部分。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga84b2d8188ce506593dcc3f8cd00e8e2c

dst = cv2.bitwise_xor(src1, src2[, mask])

1.3.2 參數

  • src1:按位異或操作的第一張圖片數據;
  • src2:按位異或操作的第二張圖片數據,大小需要與第一張圖片一致;
  • mask:掩模,需要是與按位異或的兩張圖片大小一致的一個ndarray,元素爲uint8類型。一般來說是一個二值化的矩陣,即元素值不是0(黑色)就是255(白色),如果設置了該參數,則掩模中值爲255(白色)的像素纔會進行按位異或操作,掩模中值爲0(黑色)的像素則直接忽略,該部分的結果也是黑色;

1.3.3 返回值

  • dst:按位異或操作後的圖像數據,兩張圖像相同的部分爲0(黑色),不同的部分爲255(白色);

1.3.4 用法舉例

img1 = cv2.imread(r'.\image1.jpg', cv2.IMREAD_COLOR)
img2 = cv2.imread(r'.\image2.jpg', cv2.IMREAD_COLOR)
cv2.imshow('image1', img1)
cv2.imshow('image2', img2)

bitXor = cv2.bitwise_xor(img1, img2)
cv2.imshow('bitXOR', bitXor)

1.3.5 實例展示

按位異或

1.4 按位或

1.4.1 函數簡述和原型

該函數用於對兩個一樣大小的圖片矩陣數據中的每個像素值進行按位或操作。實際應用中往往針對二值化圖像進行該操作,目的在於取兩個二值化圖像中的白色部分的並集。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#gab85523db362a4e26ff0c703793a719b4

dst = cv2.bitwise_or(src1, src2[, mask])

1.4.2 參數

  • src1:按位或操作的第一張圖片數據;
  • src2:按位或操作的第二張圖片數據,大小需要與第一張圖片一致;
  • mask:掩模,需要是與按位或的兩張圖片大小一致的一個ndarray,元素爲uint8類型。一般來說是一個二值化的矩陣,即元素值不是0(黑色)就是255(白色),如果設置了該參數,則掩模中值爲255(白色)的像素纔會進行按位或操作,掩模中值爲0(黑色)的像素則直接忽略,該部分的結果也是黑色;

1.4.3 返回值

  • dst:按位或操作後的圖像數據;

1.4.4 用法舉例

# 創建兩個黑色畫布
canvas1 = np.zeros((300, 300), dtype=np.uint8)
canvas2 = np.zeros((300, 300), dtype=np.uint8)

# 在兩個畫布的不同位置分別繪製白色的實心矩形
cv2.rectangle(canvas1, (50, 50), (150, 150), color=255, thickness=cv2.FILLED)
cv2.rectangle(canvas2, (80, 80), (250, 250), color=255, thickness=cv2.FILLED)
cv2.imshow('image1', canvas1)
cv2.imshow('image2', canvas2)

# 按位或操作,合併兩個白色矩形
bitOr = cv2.bitwise_or(canvas1, canvas2)
cv2.imshow('bitwiseOr', bitOr)

1.4.5 實例展示

按位或

2. 圖像矩陣絕對差值

2.1 函數簡述和原型

該函數用於計算兩個一樣大小的圖片矩陣數據中每個像素值之間差值的絕對值,類似按位異或操作,該函數主要目的也爲尋找出兩個圖像中不同的部分。然而,兩張圖像中某個像素的值只要有不同,按位異或在該位置計算出的值均爲255,因此按位異或操作的輸出值是一個二值化矩陣(不是0就是255)。而該函數的輸出則有大有小,值越大表示該位置兩張輸入圖像的像素差異越大。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga6fef31bc8c4071cbc114a758a2b79c14

dst = cv2.absdiff(src1, src2)

2.2 參數

  • src1:計算差異的第一張圖像數據;
  • src1:計算差異的第二張圖像數據,大小需要與第一張圖像一致;

2.3 返回值

  • dst:計算出的兩張圖像在每個像素點處差值的絕對值;

2.4 用法舉例

img1 = cv2.imread(r'.\image1.jpg', cv2.IMREAD_COLOR)
img2 = cv2.imread(r'.\image2.jpg', cv2.IMREAD_COLOR)
cv2.imshow('image1', img1)
cv2.imshow('image2', img2)

# 計算兩張圖片的差異絕對值
diff = cv2.absdiff(img1, img2)
cv2.imshow('difference', diff)

2.5 實例展示

下圖比較了一下按位異或與絕對差值,可見由於按位異或無法區分出差異大小,導致差異較小的地方輸出也較大,因此噪點較多:
按位異或與絕對差值

3. 圖像疊加

3.1 簡單疊加

3.1.1 函數簡述和原型

該函數用於加和兩個一樣大小的圖片矩陣數據中的每個像素值,加和結果溢出時則取最大值,如對於單字節類型(uint8)即爲255。實際應用中對該函數的應用較少。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga0002cf8b418479f4cb49a75442baee2f

dst = cv2.add(src1, src2[, mask[, dtype]])

3.1.2 參數

  • src1:要疊加的第一幅圖像數據;
  • src2:要疊加的第二幅圖像數據,大小需要與第一幅圖像一致;
  • mask:掩模,需要是與圖片大小一致的一個ndarray,元素爲uint8類型。一般來說是一個二值化的矩陣,即元素值不是0(黑色)就是255(白色),如果設置了該參數,則掩模中值爲255(白色)的像素纔會進行疊加操作,掩模中值爲0(黑色)的像素則直接忽略,該部分的結果也是黑色;
  • dtype:輸出的數據類型,默認值爲-1,表示與第一幅圖像一致。實際應用中圖像的數據類型往往都是單字節類型(uint8),故不對該參數進行設置;

3.1.3 返回值

  • dst:疊加後的圖像;

3.1.4 用法舉例

img1 = cv2.imread(r".\image1.jpeg", cv2.IMREAD_COLOR)
img2 = cv2.imread(r".\image2.jpg", cv2.IMREAD_COLOR)
cv2.imshow('image1', img1)
cv2.imshow('image2', img2)

# 簡單疊加兩張圖片,僅疊加右半部分
h, w, c = img1.shape
mask = np.zeros((h, w), dtype=np.uint8)
mask[:,int(w/2):] = 255
imgAdd = cv2.add(img1, img2, mask=mask)
cv2.imshow('Simple Add', imgAdd)

3.2 加權疊加

3.2.1 函數簡述和原型

該函數用於對兩個一樣大小的圖片矩陣數據中的每個像素值進行加權加和,加和結果溢出時則取最大值,如對於單字節類型(uint8)即爲255。相比於簡單疊加,該函數更爲靈活,且如果參數設置合理,加和結果也不那麼容易溢出(輸出即爲白色)。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19

dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dtype])

3.2.2 參數

  • src1:要疊加的第一幅圖像數據;
  • alpha:double類型,第一幅圖像的數據的權重值;
  • src2:要疊加的第二幅圖像數據,大小需要與第一幅圖像一致;
  • beta:double類型,第二幅圖像的數據的權重值;
  • gamma:double類型,最後加權結果的偏移量;
  • dtype:輸出的數據類型,默認值爲-1,表示與第一幅圖像一致。實際應用中圖像的數據類型往往都是單字節類型(uint8),故不對該參數進行設置;

3.2.3 返回值

  • dst:加權疊加後的圖像,每個像素的值爲$dst[i]=alpha*src1[i]+beta*src2[i]+gamma$

3.2.4 用法舉例

img1 = cv2.imread(r".\image1.jpeg", cv2.IMREAD_COLOR)
img2 = cv2.imread(r".\image2.jpg", cv2.IMREAD_COLOR)
cv2.imshow('image1', img1)
cv2.imshow('image2', img2)

# 加權疊加兩張圖片,兩張圖片各佔一半,最後輸出值再減去40
imgAddW = cv2.addWeighted(img1, 0.5, img2, 0.5, -40)

3.2.5 實例展示

下圖對比了一下簡單疊加和加權疊加,很明顯簡單疊加很容易溢出,而加權疊加則可以自由地控制輸出:
圖片疊加

4. 圖像拼接

4.1 水平拼接

4.1.1 函數簡述和原型

該函數用於在水平方向上拼接多個高度一致(即行數一致)的圖像。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#gaf9771c991763233866bf76b5b5d1776f

dst = cv2.hconcat(src)

4.1.2 參數

  • src:一個包含圖像矩陣的列表,其中每個元素爲想要拼接的圖像數據,這些圖像矩陣的行數必須一致,即圖像高度一致;

4.1.3 返回值

  • dst:水平拼接後的圖像;

4.1.4 用法舉例

img1 = cv2.imread(r".\image1.jpeg", cv2.IMREAD_COLOR)
img2 = cv2.imread(r".\image2.jpg", cv2.IMREAD_COLOR)
# 水平方向上拼接圖像後展示
cv2.imshow('image', cv2.hconcat([img1,img2]))

4.2 垂直拼接

4.2.1 函數簡述和原型

該函數用於在垂直方向上拼接多個寬度一致(即列數一致)的圖像。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga744f53b69f6e4f12156cdde4e76aed27

dst = cv2.vconcat(src)

4.2.2 參數

  • src:一個包含圖像矩陣的列表,其中每個元素爲想要拼接的圖像數據,這些圖像矩陣的列數必須一致,即圖像寬度一致;

4.2.3 返回值

  • dst:垂直拼接後的圖像;

4.2.4 用法舉例

img1 = cv2.imread(r".\image1.jpeg", cv2.IMREAD_COLOR)
img2 = cv2.imread(r".\image2.jpg", cv2.IMREAD_COLOR)
# 垂直方向上拼接圖像後展示
cv2.imshow('image', cv2.vconcat([img1,img2]))

5. 綜合實例

此處演示一個綜合應用上述幾種API的例子。

5.1 目的

目前有一張路飛的圖片和一張葉伊布的圖片,現在希望將葉伊布放在路飛的掌心。主要思路如下:首先將關心的區域(ROI)取出,本例中即爲路飛的手掌部分;將伊布的圖片縮放至合適的大小;之後將伊布的圖像轉爲灰度圖像,再進行二值化,可以獲得一個掩模,該掩模中圖像的白色背景部分爲0(黑色)。利用該掩模將伊布的圖像中白色的背景除去,也就僅將有顏色的部分取出,即只提取出了伊布;之後再將該掩模按位取反,則掩模中白色背景爲255(白色),利用該掩模可以將路飛手掌中伊布的部分抹黑,從而將伊布的位置騰出來;最後把除去背景的伊布與伊布位置爲黑色的路飛手掌疊加,再將疊加後的區域替換路飛的原始圖像,則就實現了把伊布放在路飛的手掌中的效果。

5.2 代碼實現

luffy = cv2.imread(r".\resources\Luffy1.jpeg", cv2.IMREAD_COLOR)
eevee = cv2.imread(r".\resources\cartoon1.jpg", cv2.IMREAD_COLOR)

# 先取出關心區域(ROI),即路飛的手掌部分
luffy_hand = luffy[366:494, 792:972]

# 將伊布的圖像縮小至適合路飛手掌的大小
eevee_shrink = cv2.resize(eevee, None, fx=1/6, fy=1/6, interpolation=cv2.INTER_CUBIC)

# 製作掩模,將伊布圖像中白色背景除去
eevee_gray = cv2.cvtColor(eevee_shrink, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(eevee_gray, 250, 255, cv2.THRESH_BINARY_INV)
eevee_extract = cv2.bitwise_and(eevee_shrink, eevee_shrink, mask=mask)

# 掩模取反,將路飛手掌中伊布的位置抹黑
mask_inv = cv2.bitwise_not(mask)
luffy_hand = cv2.bitwise_and(luffy_hand, luffy_hand, mask=mask_inv)

# 融合路飛手掌和伊布
luffy_hand = cv2.add(luffy_hand, eevee_extract)
# 將融合後的ROI放回原圖對應位置
luffy[366:494, 792:972] = luffy_hand
cv2.imshow('Eevee in Luffy\'s Hand', luffy)

5.3 結果展示

路飛掌心中的伊布

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章