6.2.3 圖像的仿射變換
圖像的仿射變換涉及到圖像的形狀位置角度的變化,是深度學習預處理中常到的功能,在此簡單回顧一下。仿射變換具體到圖像中的應用,主要是對圖像的縮放,旋轉,剪切,翻轉和平移的組合。在OpenCV中,仿射變換的矩陣是一個2×3的矩陣,其中左邊的2×2子矩陣是線性變換矩陣,右邊的2×1的兩項是平移項:
對于圖像上的任一位置(x,y),仿射變換執行的是如下的操作:
需要注意的是,對于圖像而言,寬度方向是x,高度方向是y,坐標的順序和圖像像素對應下標一致。所以原點的位置不是左下角而是右上角,y的方向也不是向上,而是向下。在OpenCV中實現仿射變換是通過仿射變換矩陣和cv2.warpAffine()這個函數,還是通過代碼來理解一下,例子中圖片的分辨率為600×400:
import cv2
import numpy as np
# 讀取一張斯里蘭卡拍攝的大象照片
img = cv2.imread('lanka_safari.jpg')
# 沿著橫縱軸放大1.6倍,然后平移(-150,-240),最后沿原圖大小截取,等效于裁剪并放大
M_crop_elephant = np.array([
[1.6, 0, -150],
[0, 1.6, -240]
], dtype=np.float32)
img_elephant = cv2.warpAffine(img, M_crop_elephant, (400, 600))
cv2.imwrite('lanka_elephant.jpg', img_elephant)
# x軸的剪切變換,角度15°
theta = 15 * np.pi / 180
M_shear = np.array([
[1, np.tan(theta), 0],
[0, 1, 0]
], dtype=np.float32)
img_sheared = cv2.warpAffine(img, M_shear, (400, 600))
cv2.imwrite('lanka_safari_sheared.jpg', img_sheared)
# 順時針旋轉,角度15°
M_rotate = np.array([
[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0]
], dtype=np.float32)
img_rotated = cv2.warpAffine(img, M_rotate, (400, 600))
cv2.imwrite('lanka_safari_rotated.jpg', img_rotated)
# 某種變換,具體旋轉+縮放+旋轉組合可以通過SVD分解理解
M = np.array([
[1, 1.5, -400],
[0.5, 2, -100]
], dtype=np.float32)
img_transformed = cv2.warpAffine(img, M, (400, 600))
cv2.imwrite('lanka_safari_transformed.jpg', img_transformed)
代碼實現的操作示意在下圖中:
6.2.4 基本繪圖
OpenCV提供了各種繪圖的函數,可以在畫面上繪制線段,圓,矩形和多邊形等,還可以在圖像上指定位置打印文字,比如下面例子:
import numpy as np
import cv2
# 定義一塊寬600,高400的畫布,初始化為白色
canvas = np.zeros((400, 600, 3), dtype=np.uint8) + 255
# 畫一條縱向的正中央的黑色分界線
cv2.line(canvas, (300, 0), (300, 399), (0, 0, 0), 2)
# 畫一條右半部份畫面以150為界的橫向分界線
cv2.line(canvas, (300, 149), (599, 149), (0, 0, 0), 2)
# 左半部分的右下角畫個紅色的圓
cv2.circle(canvas, (200, 300), 75, (0, 0, 255), 5)
# 左半部分的左下角畫個藍色的矩形
cv2.rectangle(canvas, (20, 240), (100, 360), (255, 0, 0), thickness=3)
# 定義兩個三角形,并執行內部綠色填充
triangles = np.array([
[(200, 240), (145, 333), (255, 333)],
[(60, 180), (20, 237), (100, 237)]])
cv2.fillPoly(canvas, triangles, (0, 255, 0))
# 畫一個黃色五角星
# 第一步通過旋轉角度的辦法求出五個頂點
phi = 4 * np.pi / 5
rotations = [[[np.cos(i * phi), -np.sin(i * phi)], [i * np.sin(phi), np.cos(i * phi)]] for i in range(1, 5)]
pentagram = np.array([[[[0, -1]] + [np.dot(m, (0, -1)) for m in rotations]]], dtype=np.float)
# 定義縮放倍數和平移向量把五角星畫在左半部分畫面的上方
pentagram = np.round(pentagram * 80 + np.array([160, 120])).astype(np.int)
# 將5個頂點作為多邊形頂點連線,得到五角星
cv2.polylines(canvas, pentagram, True, (0, 255, 255), 9)
# 按像素為間隔從左至右在畫面右半部份的上方畫出HSV空間的色調連續變化
for x in range(302, 600):
color_pixel = np.array([[[round(180*float(x-302)/298), 255, 255]]], dtype=np.uint8)
line_color = [int(c) for c in cv2.cvtColor(color_pixel, cv2.COLOR_HSV2BGR)[0][0]]
cv2.line(canvas, (x, 0), (x, 147), line_color)
# 如果定義圓的線寬大于半斤,則等效于畫圓點,隨機在畫面右下角的框內生成坐標
np.random.seed(42)
n_pts = 30
pts_x = np.random.randint(310, 590, n_pts)
pts_y = np.random.randint(160, 390, n_pts)
pts = zip(pts_x, pts_y)
# 畫出每個點,顏色隨機
for pt in pts:
pt_color = [int(c) for c in np.random.randint(0, 255, 3)]
cv2.circle(canvas, pt, 3, pt_color, 5)
# 在左半部分最上方打印文字
cv2.putText(canvas,
'Python-OpenCV Drawing Example',
(5, 15),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0, 0),
1)
cv2.imshow('Example of basic drawing functions', canvas)
cv2.waitKey()
執行這段代碼得到如下的圖像:
評論
查看更多