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

0. 前言

圖像在計算機中均是以二維矩陣的方式存儲的,矩陣中的每個元素對應一個像素點,類型爲uint8,因此值在0-255之間。灰度圖像就是一個二維矩陣,0-255對應從黑到白256個級別的灰度。彩色圖像根據不同的色彩空間有不同的存儲方式,最常見的RGB彩色空間,則有三個通道,每個通道也是一個二維矩陣,對應了紅、綠、藍三種基本顏色的分量。

因此,OpenCV讀取的圖片或視頻流中的一幀圖像均爲numpy的ndarray,若爲灰度圖像,即爲一個二維矩陣;若爲三通道BGR彩色圖像,則爲三個二維矩陣。原點默認爲左上角,x軸爲水平方向,向右爲正方向;y軸爲垂直方向,向下爲正方向。也即矩陣的第一個元素M00M_{00}就對應座標爲(0,0)(0,0)的像素,矩陣第ii行第jj列的元素MijM_{ij}對應座標爲(j,i)(j, i)的像素,此處注意座標和矩陣位置的順序!此外,從圖像角度描述圖像大小時往往爲寬*高,而從矩陣角度描述大小時,往往爲行*列。而行對應高,列對應寬,故一張1024×7681024 \times 768的圖像對應的是768×1024768 \times 1024的矩陣。

既然圖像通過矩陣方式存儲,那麼針對圖像的很多操作實際上就是針對矩陣的操作,下面就對OpenCV封裝的對矩陣的一些操作進行小結。

1. 圖像翻轉

1.1 函數簡述和原型

該函數用於對圖片進行翻轉。官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#gaca7be533e3dac7feb70fc60635adf441

dst = cv2.flip(src, flipCode)

1.2 參數

  • src:要翻轉的圖片數據;
  • flipCode:翻轉方向代碼,int類型。有三種模式,0表示按x軸翻轉(垂直翻轉);大於0表示按y軸翻轉(水平翻轉);小於0表示兩個方向均進行翻轉(相當於旋轉180度)

1.3 返回值

  • dst:翻轉後的圖片

1.4 實例展示

圖像翻轉

2. 圖像轉置

2.1 函數簡述和原型

該函數用於對圖像的像素數據矩陣進行轉置,即將圖像沿y=x翻轉,相當於逆時針旋轉90°後再垂直翻轉(或水平翻轉後再逆時針旋轉90°),注意與直接逆時針旋轉90°的區別!官方文檔:https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#ga46630ed6c0ea6254a35f447289bd7404

dst = cv2.transpose(src)

2.2 參數

  • src:要轉置的圖片數據;

2.3 返回值

  • dst:轉置後的圖片

2.4 實例展示

圖片轉置

3. 仿射變換

3.1 函數簡述和原型

從線性代數的知識可知,一個n維方陣可以表示對n維空間的線性變換。那麼既然圖像以二維矩陣的方式存儲在計算機中(多通道彩色圖像可以看做多個二維矩陣的疊加),圖像的二維矩陣左乘一個2*2的矩陣,就可以對該圖像進行線性變換,包括拉伸、旋轉,再加上平移即組成了圖像的仿射變換。因此OpenCV提供了對圖像進行仿射變換的函數,主要作用即爲對圖像數據左乘2維方陣進行線性變換,再加上平移。官方文檔:https://docs.opencv.org/3.4.2/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3

dst = cv2.warpAffine(src, M, dsize[, flags[, borderMode[, borderValue]]])

3.2 參數

  • src:要處理的圖像數據,可以爲多通道彩色圖像;
  • M:ndarray類型,一個2*3的矩陣,元素類型爲float32。其中前兩列構成了對圖像進行線性變換的2*2方陣,第三列表示將圖像分別在x軸和y軸兩個方向上進行平移的距離(以像素爲單位);
  • dsize:輸出圖像的大小,二元元組,分別爲輸出圖像的寬和高;
  • flags:插值方法的flag,默認爲cv2.INTER_LINEAR(線性插值法)。若爲cv2.WARP_INVERSE_MAP,表示使用M的逆矩陣對圖像進行逆向變換;
  • borderMode:邊界外推模式,默認爲cv2.BORDER_CONSTANT,即使用常數填充邊界;
  • borderValue:邊界填充值,當邊界外推模式爲cv2.BORDER_CONSTANT時,填充邊界所用的常數,默認值爲0;

3.3 返回值

  • dst:仿射變換後的圖像;

3.4 用法舉例

img = cv2.imread(r'.\image.jpg', cv2.IMREAD_COLOR)
h, w, channels = img.shape

# 定義平移矩陣,需要是numpy的float32類型
# x軸平移100,y軸平移50的矩陣
M = np.float32([[1, 0, 100],
                [0, 1, 50]])
# 使用仿射變換實現平移,並使用白色填充邊界
imgShift = cv2.warpAffine(img, M, (w, h), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
cv2.imshow('shift', imgShift)

# 定義一個繞圖片中心逆時針旋轉90°的仿射變換矩陣
M = np.float32([[0, 1, 0],
                [1, 0, 0]])
imgRotate = cv2.warpAffine(img, M, (h, w))
cv2.imshow('rotate', imgRotate)

# 定義一個斜右下角剪切(shear)的仿射變換矩陣
M = np.float32([[1, 1, 0],
                [0, 1, 0]])
imgShear = cv2.warpAffine(img, M, (2*w, h), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
cv2.imshow('shear', imgShear)

3.5 實例展示

仿射變換

4. 仿射變換矩陣生成

4.1 函數簡述和原型

如上所述,仿射變換可以完成很多針對圖像的操作,如平移、旋轉、拉伸等。但往往計算仿射變換對應的矩陣需要具備線性代數的相關知識,並且計算量也較大。因此OpenCV提供了兩個函數來生成仿射變換矩陣,極爲方便。其中getRotationMatrix2D函數是專用於生成旋轉對應的仿射變換的矩陣,getAffineTransform則更爲通用,通過變換前後三個非共線點的座標來生成對應的仿射變換矩陣。官方文檔:https://docs.opencv.org/3.4.2/da/d54/group__imgproc__transform.html

# 生成旋轉對應的仿射變換矩陣
M = cv2.getRotationMatrix2D(center, angle, scale)
# 根據仿射變換前後三個點的位置變化生成對應的矩陣
M = cv2.getAffineTransform(src, dst)

4.2 參數

  • center:旋轉中心的點座標,一個二元組;
  • angle:旋轉角度,double類型,正數表示逆時針旋轉,負數表示順時針旋轉;
  • scale:double類型,各向同性的縮放比例;
  • src:仿射變換前三個點的座標;
  • dst:仿射變換後對應的三個點的座標;

4.3 返回值

  • M:參數決定的仿射變換所對應的矩陣,一個2*3的ndarray,元素爲float32類型,可以直接用於warpAffine函數;

4.4 用法舉例

img = cv2.imread(r'\image.jpg', cv2.IMREAD_COLOR)
h, w, channels = img.shape

# 繞圖片中心逆時針旋轉45°,並縮小一半
M = cv2.getRotationMatrix2D((w / 2, h / 2), 45, 0.5)
imgRot = cv2.warpAffine(img, M, (w, h))
cv2.imshow('rotation', imgRot)

# 通過變換前後三個點的座標獲取對應的仿射變換矩陣
# 變換前的三個點
pts1 = np.float32([[0, 0], [1, 0], [0, 1]])
# 變換後的三個點,逆時針旋轉90°,並均下移寬度位置
pts2 = np.float32([[0, w], [0, -1+w], [1, w]])

# 生成變換矩陣
M = cv2.getAffineTransform(pts1, pts2)
imgRot = cv2.warpAffine(img, M, (h, w))
cv2.imshow('image Rotation', imgRot)

5. 透視變換

5.1 函數簡述和原型

圖像的幾何變換中,除了仿射變換,還有透視變換,也就是將圖片重新投影到一個新的視平面。實際應用中往往通過這種方式矯正圖片。類似仿射變換,配套透視變換函數warpPerspective的還有生成透視變換矩陣的函數getPerspectiveTransform,通過四個非共線點來生成對應的透視變換矩陣。官方文檔:https://docs.opencv.org/3.4.2/da/d54/group__imgproc__transform.html

# 根據透視變換前後非共線的四個點的位置變化生成對應的透視變換矩陣
M = cv2.getPerspectiveTransform(src, dst)
# 根據透視變換矩陣將圖像進行透視變換
ret = cv2.warpPerspective(img, M, dsize[, flags[, borderMode[, borderValue]]])

5.2 參數

  • src:透視變換前四個非共線的點的座標;
  • dst:透視變換後對應的四個點的座標;
  • img:要進行透視變換的圖像,可以是多通道彩色圖像;
  • M:透視變換的矩陣,一個3*3的ndarray;
  • dsize:輸出圖像的大小,二元元組,分別爲輸出圖像的寬和高;
  • flags:插值方法的flag,默認爲cv2.INTER_LINEAR(線性插值法)。若爲cv2.WARP_INVERSE_MAP,表示使用M的逆矩陣對圖像進行逆向變換;
  • borderMode:邊界外推模式,默認爲cv2.BORDER_CONSTANT,即使用常數填充邊界;
  • borderValue:邊界填充值,當邊界外推模式爲cv2.BORDER_CONSTANT時,填充邊界所用的常數,默認值爲0;

5.3 返回值

  • M:參數決定的透視變換所對應的矩陣,一個3*3的ndarray,元素爲float32類型,可以直接用於warpPerspective函數;
  • ret:透視變換後的圖像數據;

5.4 用法舉例

img = cv2.imread(r'.\image.jpg', cv2.IMREAD_COLOR)
h, w, channels = img.shape

# 卡片的四個角點,非共線的四個點才能唯一確定透視變換
pts1 = np.float32([[148, 80], [437, 114], [94, 247], [423, 288]])
# 變換後分別在左上、右上、左下、右下四個點
pts2 = np.float32([[0, 0], [320, 0], [0, 178], [320, 178]])

# 根據變換前後點的位置生成透視變換矩陣
M = cv2.getPerspectiveTransform(pts1, pts2)
# 進行透視變換
imgPersp = cv2.warpPerspective(img, M, (320, 178))
cv2.imshow('Perspective transform', imgPersp)

5.5 實例展示

透視變換

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