opencv入門系列教學(五)影像的基本操作(像素值、屬性、ROI和邊框)

0.序言

每個影像是由一個個點組成的,而這些點可以表示為像素值的形式。

這篇部落格里我們將學會:

  • 訪問像素值並修改它們 。
  • 訪問影像屬性 。
  • 設置感興趣區域(ROI) 。
  • 分割和合併影像。

對於影像的基本操作我們需要對numpy知識的了解,不需要很多,只知道基本用法即可。這裡暫不贅述,讀者可查閱其餘資料進行學習。

1.訪問和修改像素值

讓我們先載入彩色影像:

import numpy as np
import cv2 as cv

img = cv.imread('cat.jpg')

我們可以通過行和列坐標來訪問像素值。對於 BGR 影像,它返回一個由藍色、綠色和紅色值組成的數組。而如果是灰度影像的話,它只返回相應的灰度。我們也可以用相同的方式來對像素值進行修改。

# 通過行和列坐標來訪問像素值
>>> px = img[100,100]
>>> print( px )
[157 166 200]

# 修改像素值
>>> img[100,100] = [255,255,255]
>>> print( img[100,100] )
[255 255 255]

 

Numpy是用於快速數組計算的優化庫。因此,簡單地訪問每個像素值並對其進行修改將非常慢,因此不建議使用。對於單個像素訪問,Numpy數組方法array.item()和array.itemset())被認為更好,但是它們始終返回標量。如果要訪問所有B,G,R值,則需要分別調用所有的array.item()。

比如我們可以用下面的方法來進行像素的訪問和編輯:

# 訪問 RED 值
>>> img.item(10,10,2)
59

# 修改 RED 值
>>> img.itemset((10,10,2),100)
>>> img.item(10,10,2)
100

2.訪問影像屬性

影像屬性包括行數,列數,通道數,影像數據類型,像素數等等。

影像的形狀可通過 img.shape 訪問。它返回行,列和通道數的元組(如果影像是彩色的)

注意:如果影像是灰度的,則返回的元組僅包含行數和列數,因此這是檢查載入的影像是灰度還是彩色的好方法。

>>> print( img.shape )
(342, 548, 3)

像素總數可通過訪問 img.size :

>>> print( img.size )
562248

影像數據類型通過 img.dtype 獲得:

>>> print( img.dtype )
uint8

注意:img.dtype在調試時非常重要,因為OpenCV-Python程式碼中的大量錯誤是由無效的數據類型引起的。

3.影像感興趣區域ROI

有時候,我們不得不處理一些特定區域的影像。比如對於影像中的眼睛檢測,首先對整個影像進行人臉檢測。在獲取人臉影像時,我們只選擇人臉區域,搜索其中的眼睛,而不是搜索整個影像。它提高了準確性和性能。

這裡我們直接使用numpy的切片即可,比如:

>>> ROI = img[280:340, 330:390]

不規則形狀的ROI區域的設置,我們將在以後的文章里再詳細闡述。 

4.拆分和合併影像通道

有時我們需要分別處理影像的B,G,R通道。在這種情況下,我們需要將BGR影像拆分為單個通道。我們可以這樣做:

>>> b,g,r = cv.split(img) >>> img = cv.merge((b,g,r))

但是cv.split() 是一項耗時的操作(就時間而言)。因此,僅在必要時才這樣做。我們一般採用Numpy索引的方法。比如我們要將所有的紅色像素都設置為0:

>>> img [:, :, 2] = 0

5.為影像設置邊框

如果我們要在影像周圍創建邊框(如相框),那可以使用 cv.copyMakeBorder() 。它在以後對影像進行高級處理的時候,比如卷積運算,零填充等方面將有更多應用。此函數採用以下參數:

  • src – 輸入影像
  • top,bottom,left,right 邊界寬度(以相應方向上的像素數為單位)
  • borderType – 定義要添加哪種邊框的標誌。它可以是以下類型:
  • cv.BORDER_CONSTANT – 添加恆定的彩色邊框。該值應作為下一個參數給出。
  • cv.BORDER_REFLECT – 邊框將是邊框元素的鏡像,如下所示: fedcba | abcdefgh hgfedcb
  • **cv.BORDER_REFLECT_101**或 **cv.BORDER_DEFAULT**與上述相同,但略有變化,例如: gfedcb | abcdefgh | gfedcba
  • **cv.BORDER_REPLICATE**最後一個元素被複制,像這樣: aaaaaa | abcdefgh | hhhhhhh
  • **cv.BORDER_WRAP**看起來像這樣: cdefgh | abcdefgh | abcdefg
  • value -邊框的顏色,如果邊框類型為**cv.BORDER_CONSTANT**

下面我們來看一下各個邊框類型在圖片顯示上的結果。注意因為影像是基於matplotlib一起顯示的。所以紅色和藍色通道將會互換。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('opencv-logo.png')
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()

結果如下: