旋轉圖片的方法
若是單純只是要把圖片做角度的旋轉,可以直接使用OpenCV 的 cv2.rotate()
函数。可按指定的方向旋轉圖像。如下:
import cv2
# 讀取圖像
image = cv2.imread('your_image.jpg')
# 將圖像旋轉90度
rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
# 顯示旋轉後的圖像
cv2.imshow('Rotated Image', rotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
翻轉圖片的方法
cv2.flip()
是 OpenCV 中用於圖像翻轉的函數。它可以在水平、垂直或兩個方向上翻轉圖像。該函數接受三個參數:輸入圖像、翻轉的模式和輸出圖像的可選參數。
dst = cv2.flip(src, flipCode[, dst])
flipCode
:翻轉的模式。可以是以下值之一:
- 0:水平翻轉(沿著垂直軸翻轉)。
- 1:垂直翻轉(沿著水平軸翻轉)。
- -1:同時在水平和垂直方向上翻轉。
cv2.flip()
函數和 cv2.rotate()
函數都可以用於實現圖像的旋轉和翻轉,但它們的效果是不同的。
cv2.flip() 函數可以在水平和垂直方向上翻轉圖像,包括水平翻轉、垂直翻轉和同時在水平和垂直方向上翻轉。例如,使用 cv2.flip(image, -1) 可以同時在水平和垂直方向上翻轉圖像。
cv2.rotate() 函數用於對圖像進行旋轉。通過指定旋轉的角度和旋轉中心點,可以實現不同角度的旋轉。例如,使用 cv2.rotate(image, cv2.ROTATE_180_CLOCKWISE) 可以將圖像順時針旋轉180度。
雖然cv2.flip(image, -1)
和 cv2.rotate(image, cv2.ROTATE_180_CLOCKWISE)
可以實現類似的效果,將圖像翻轉或旋轉180度,但它們的內部操作是不同的。 cv2.flip() 是基於軸對稱翻轉實現的,而 cv2.rotate() 是基於旋轉變換實現的。
針對形狀做角度校正
在許多圖像偵測的狀況,我們仍然會需要針對物件去做旋轉,首先我們一定是先用cv2.findContours
取得輪廓,然後取得該物件輪廓的角度。這邊很重要的,就是要取得物件輪廓的角度,要取得角度,首先就要先去做輪廓擬合(請參考: OpenCV裡面形狀擬合的幾種方法)。
這邊我大推使用橢圓去做輪廓擬合並且取得軸心的角度,為什麼呢? 雖然cv2.minAreaRect()
可計算最小擬合矩形,但是這個矩形會非常容易受到輪廓的些微影響而改變擬合的方式,例如以下圖為例,就有可能有黑框、紅色框兩種的最小擬合矩形(會視當下輪廓取得的細微變化而改變)。也因此所取得的角度會非常多變,後續的辨識也會更困難
但是使用最小擬合橢圓,對於像上面這種左右、上下為對稱,但是長寬不同的形狀來說,非常適合使用最小擬合橢圓cv2.fitEllipse()
,使用範例如下
import cv2
image = cv2.imread('./333_2023-06-08_19-57-30.jpg')
canny = cv2.Canny(image , 50, 250)
cnts, hier = cv2.findContours(canny , cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 執行最小橢圓擬合
ellipse = cv2.fitEllipse(cnts[0])
(center, axes, angle) = ellipse
cv2.ellipse(image, ellipse, (0, 255, 0), 2)
# 顯示結果
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
上面可以看到(center, axes, angle) = ellipse
這邊的angle就是所偵測到的輪廓的角度,接著可以用cv2.warpAffine
方法將圖像轉正
def rotatedDice(image, cnt):
# 取得最小擬合橢圓並對圖像做翻轉
ellipse = cv2.fitEllipse(cnt)
(center, axes, angle) = ellipse
angle = angle + 90
rotation_matrix = cv2.getRotationMatrix2D(tuple(center), angle, 1)
image = cv2.warpAffine(image, rotation_matrix,(image.shape[1], image.shape[0]))
# 計算裁切位置
mark = np.zeros_like(image)
cv2.drawContours(mark, [cnt], 0, (255, 255, 255), -1)
mark = cv2.warpAffine(mark, rotation_matrix,(mark.shape[1], mark.shape[0]))
mark = cv2.cvtColor(mark, cv2.COLOR_RGB2GRAY)
cnts, hier = cv2.findContours(mark, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(cnts[0])
matting_result = image[y:y+h,x:x+w,:]
return matting_result
從上面,我們使用cv2.warpAffine來做圖片角度的校正,warpAffine裡面有要輸入一個旋轉的矩陣的參數,在上面的範例,我們使用cv2.getRotationMatrix2D
,這個參數是單純做形狀旋轉,但是在真實的世界當中,大部分3D的角度轉換也會帶有著深度的轉換,如下圖
這時候就會需要使用cv2.getAffineTransform
來取得這個旋轉矩陣
import cv2
import numpy as np
# 定義三個點的坐標
point1 = (106, 92)
point2 = (28, 91)
point3 = (154, 33)
# 定義旋轉角度
rotation_angle = -45
# 創建一個空白圖像
image = np.zeros((500, 500), dtype=np.uint8)
# 在圖像上繪製三角形
cv2.drawContours(image, [np.array([point1, point2, point3])], 0, (255), thickness=2)
# 計算旋轉中心
center = np.mean([point1, point2, point3], axis=0)
# 構建旋轉矩陣
rotation_matrix = cv2.getRotationMatrix2D(tuple(center), rotation_angle, 1)
# 對整個圖像進行旋轉
rotated_image = cv2.warpAffine(image, rotation_matrix, (image.shape[1], image.shape[0]))
# 顯示旋轉後的圖像
cv2.imshow("Rotated Image", rotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()