OpenCV圖像旋轉(zhuǎn)(單點(diǎn)旋轉(zhuǎn)與圖片旋轉(zhuǎn))的實(shí)現(xiàn)
1. 引言
圖像旋轉(zhuǎn)是計(jì)算機(jī)視覺中最基礎(chǔ)也是最重要的幾何變換之一,在圖像處理、計(jì)算機(jī)視覺、醫(yī)學(xué)影像分析等領(lǐng)域有著廣泛應(yīng)用。OpenCV作為最流行的計(jì)算機(jī)視覺庫,提供了強(qiáng)大的圖像旋轉(zhuǎn)功能。本文將深入探討OpenCV中的兩種旋轉(zhuǎn)方式:基于單點(diǎn)的仿射變換旋轉(zhuǎn)和直接圖片旋轉(zhuǎn),并通過代碼示例展示如何實(shí)現(xiàn)這些功能。
2. 圖像旋轉(zhuǎn)的基本概念
圖像旋轉(zhuǎn)是指將圖像圍繞某個(gè)點(diǎn)(通常是中心點(diǎn))旋轉(zhuǎn)一定角度的幾何變換。在數(shù)學(xué)上,旋轉(zhuǎn)屬于剛體變換,可以保持圖像中物體的形狀和大小不變。
旋轉(zhuǎn)的主要參數(shù)包括:
- 旋轉(zhuǎn)中心點(diǎn)
- 旋轉(zhuǎn)角度(順時(shí)針或逆時(shí)針)
- 旋轉(zhuǎn)后的縮放比例
- 旋轉(zhuǎn)后圖像的邊界處理
3. 單點(diǎn)旋轉(zhuǎn)與仿射變換矩陣
3.1 仿射變換基礎(chǔ)
仿射變換是一種二維線性變換,可以表示為:
其中(x,y)是原坐標(biāo),(x',y')是變換后坐標(biāo)。
在OpenCV中,我們使用2×3的矩陣來表示仿射變換:
3.2 獲取旋轉(zhuǎn)的仿射變換矩陣
OpenCV提供了cv2.getRotationMatrix2D
函數(shù)來計(jì)算旋轉(zhuǎn)矩陣:
import cv2 import numpy as np # 定義旋轉(zhuǎn)中心和角度 center = (width/2, height/2) # 通常以圖像中心為旋轉(zhuǎn)點(diǎn) angle = 45 # 旋轉(zhuǎn)角度 scale = 1.0 # 縮放比例 # 獲取旋轉(zhuǎn)矩陣 rotation_matrix = cv2.getRotationMatrix2D(center, angle, scale)
3.3 應(yīng)用仿射變換進(jìn)行旋轉(zhuǎn)
得到旋轉(zhuǎn)矩陣后,可以使用cv2.warpAffine
函數(shù)應(yīng)用變換:
# 讀取圖像 image = cv2.imread('input.jpg') # 獲取圖像尺寸 height, width = image.shape[:2] # 應(yīng)用旋轉(zhuǎn) rotated_image = cv2.warpAffine(image, rotation_matrix, (width, height)) # 顯示結(jié)果 cv2.imshow('Rotated Image', rotated_image) cv2.waitKey(0) cv2.destroyAllWindows()
4. 直接圖片旋轉(zhuǎn)
除了使用仿射變換,OpenCV還提供了更直接的旋轉(zhuǎn)方式:
4.1 使用transpose和flip實(shí)現(xiàn)90度倍數(shù)的旋轉(zhuǎn)
對于90°、180°、270°的旋轉(zhuǎn),可以使用更高效的操作:
# 順時(shí)針旋轉(zhuǎn)90度 rotated_90 = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE) # 逆時(shí)針旋轉(zhuǎn)90度 rotated_90_counter = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE) # 旋轉(zhuǎn)180度 rotated_180 = cv2.rotate(image, cv2.ROTATE_180)
4.2 任意角度旋轉(zhuǎn)的完整實(shí)現(xiàn)
對于任意角度的旋轉(zhuǎn),我們需要考慮旋轉(zhuǎn)后圖像可能超出原圖邊界的問題:
def rotate_image(image, angle): # 獲取圖像尺寸 (h, w) = image.shape[:2] # 計(jì)算旋轉(zhuǎn)中心 center = (w // 2, h // 2) # 獲取旋轉(zhuǎn)矩陣 M = cv2.getRotationMatrix2D(center, angle, 1.0) # 計(jì)算旋轉(zhuǎn)后圖像的邊界 cos = np.abs(M[0, 0]) sin = np.abs(M[0, 1]) new_w = int((h * sin) + (w * cos)) new_h = int((h * cos) + (w * sin)) # 調(diào)整旋轉(zhuǎn)矩陣以考慮平移 M[0, 2] += (new_w / 2) - center[0] M[1, 2] += (new_h / 2) - center[1] # 執(zhí)行旋轉(zhuǎn) rotated = cv2.warpAffine(image, M, (new_w, new_h), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255)) return rotated
5. 旋轉(zhuǎn)中的邊界處理
旋轉(zhuǎn)圖像時(shí),邊角的處理非常重要。OpenCV提供了多種邊界處理方式:
# 不同邊界填充方式 rotated_replicate = cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REPLICATE) rotated_reflect = cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_REFLECT) rotated_wrap = cv2.warpAffine(image, M, (w, h), borderMode=cv2.BORDER_WRAP)
6. 基于兩點(diǎn)的旋轉(zhuǎn)(擴(kuò)展內(nèi)容)
有時(shí)我們需要根據(jù)圖像中的兩個(gè)特征點(diǎn)來旋轉(zhuǎn)圖像,使兩點(diǎn)連線達(dá)到特定角度:
def rotate_by_two_points(image, pt1, pt2, desired_angle=0): # 計(jì)算兩點(diǎn)之間的角度 dx = pt2[0] - pt1[0] dy = pt2[1] - pt1[1] current_angle = np.degrees(np.arctan2(dy, dx)) # 計(jì)算需要旋轉(zhuǎn)的角度 rotation_angle = desired_angle - current_angle # 計(jì)算旋轉(zhuǎn)中心(兩點(diǎn)中點(diǎn)) center = ((pt1[0] + pt2[0]) / 2, (pt1[1] + pt2[1]) / 2) # 獲取旋轉(zhuǎn)矩陣 M = cv2.getRotationMatrix2D(center, rotation_angle, 1.0) # 執(zhí)行旋轉(zhuǎn) rotated = cv2.warpAffine(image, M, (image.shape[1], image.shape[0])) return rotated
7. 性能優(yōu)化與注意事項(xiàng)
- 批量旋轉(zhuǎn)優(yōu)化:如果需要旋轉(zhuǎn)多張圖片,可以預(yù)先計(jì)算旋轉(zhuǎn)矩陣并復(fù)用
- 插值方法選擇:
warpAffine
中的flags
參數(shù)可以指定插值方法,影響旋轉(zhuǎn)質(zhì)量cv2.INTER_NEAREST
:最近鄰插值,速度快但質(zhì)量低cv2.INTER_LINEAR
:雙線性插值(默認(rèn))cv2.INTER_CUBIC
:雙三次插值,質(zhì)量更好但速度慢
- 內(nèi)存考慮:大角度旋轉(zhuǎn)會(huì)產(chǎn)生更大的圖像,注意內(nèi)存消耗
8. 實(shí)際應(yīng)用案例
8.1 文檔校正
def correct_document_skew(image): # 轉(zhuǎn)換為灰度圖 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 邊緣檢測 edges = cv2.Canny(gray, 50, 150, apertureSize=3) # 霍夫線變換檢測直線 lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10) # 計(jì)算平均角度 angles = [] for line in lines: x1, y1, x2, y2 = line[0] angle = np.degrees(np.arctan2(y2-y1, x2-x1)) angles.append(angle) median_angle = np.median(angles) # 旋轉(zhuǎn)圖像校正 (h, w) = image.shape[:2] center = (w // 2, h // 2) M = cv2.getRotationMatrix2D(center, median_angle, 1.0) corrected = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) return corrected
8.2 圖像數(shù)據(jù)增強(qiáng)
在深度學(xué)習(xí)中,圖像旋轉(zhuǎn)是常用的數(shù)據(jù)增強(qiáng)手段:
def augment_data(image): # 隨機(jī)旋轉(zhuǎn)角度 (-15到15度之間) angle = np.random.uniform(-15, 15) # 隨機(jī)縮放 (0.8到1.2之間) scale = np.random.uniform(0.8, 1.2) # 獲取旋轉(zhuǎn)矩陣 h, w = image.shape[:2] center = (w/2, h/2) M = cv2.getRotationMatrix2D(center, angle, scale) # 應(yīng)用變換 augmented = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT) return augmented
9. 總結(jié)
本文詳細(xì)介紹了OpenCV中實(shí)現(xiàn)圖像旋轉(zhuǎn)的兩種主要方法:基于單點(diǎn)的仿射變換旋轉(zhuǎn)和直接圖片旋轉(zhuǎn)。關(guān)鍵點(diǎn)包括:
- 使用
cv2.getRotationMatrix2D
獲取旋轉(zhuǎn)矩陣 - 使用
cv2.warpAffine
應(yīng)用仿射變換 - 處理旋轉(zhuǎn)后的邊界問題
- 基于兩點(diǎn)旋轉(zhuǎn)的特殊情況處理
- 實(shí)際應(yīng)用中的性能優(yōu)化技巧
掌握這些技術(shù)后,讀者可以靈活地在各種計(jì)算機(jī)視覺應(yīng)用中實(shí)現(xiàn)圖像旋轉(zhuǎn)功能。根據(jù)具體需求選擇合適的方法,并注意旋轉(zhuǎn)對圖像質(zhì)量的影響,就能獲得最佳的旋轉(zhuǎn)效果。
10. 參考文獻(xiàn)
- OpenCV官方文檔
- 《學(xué)習(xí)OpenCV》計(jì)算機(jī)視覺編程經(jīng)典書籍
- 《數(shù)字圖像處理》岡薩雷斯著
到此這篇關(guān)于OpenCV圖像旋轉(zhuǎn)(單點(diǎn)旋轉(zhuǎn)與圖片旋轉(zhuǎn))的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)OpenCV圖像旋轉(zhuǎn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python同義詞替換的實(shí)現(xiàn)(jieba分詞)
這篇文章主要介紹了python同義詞替換的實(shí)現(xiàn)(jieba分詞),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01django中的數(shù)據(jù)庫遷移的實(shí)現(xiàn)
這篇文章主要介紹了django中的數(shù)據(jù)庫遷移的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03在Pandas中導(dǎo)入CSV數(shù)據(jù)時(shí)去除默認(rèn)索引的方法匯總
在Pandas中讀取CSV數(shù)據(jù)時(shí),會(huì)默認(rèn)將第一列設(shè)為索引列index,但有時(shí)候我們并不需要索引,或者希望指定自己的索引列,本文將介紹幾種在Pandas中導(dǎo)入CSV數(shù)據(jù)時(shí)去除默認(rèn)索引的方法,需要的朋友可以參考下2023-05-05在服務(wù)器上運(yùn)行python文件詳細(xì)步驟
很多小伙伴想知道如何在服務(wù)器上跑python程序的方法,那么這篇文章主要給大家介紹了關(guān)于在服務(wù)器上運(yùn)行python文件的詳細(xì)步驟,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02python編程PyQt5創(chuàng)建按鈕及觸發(fā)點(diǎn)擊事件示例解析
這篇文章主要為大家介紹了python編程使用PyQt5如何創(chuàng)建按鈕及觸發(fā)點(diǎn)擊事件的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10詳解Python 實(shí)現(xiàn) ZeroMQ 的三種基本工作模式
ZMQ是一個(gè)簡單好用的傳輸層,像框架一樣的一個(gè) socket library,他使得 Socket 編程更加簡單、簡潔和性能更高。 ,這篇文章主要介紹了Python 實(shí)現(xiàn) ZeroMQ 的三種基本工作模式,需要的朋友可以參考下2020-03-03