付費限定

[OpenCV應用][Python]利用SIFT得取圖片物件旋轉角度,並旋轉回正常角度

閱讀時間約 39 分鐘

利用OPENCV,實現SIFT應用,尋找圖片中物件的旋轉角度

前言

SIFT的介紹,維基百科寫的就會比我清楚很多,就不在贅述
維基百科連結

本文介紹主要提出SIFT提取關鍵角點的座標,由此算出物件的旋轉角度

程式功能介紹 : 導入待檢測圖及樣本圖,則會依照樣本圖中的物件為基準,算出待檢圖實際旋轉的角度

實驗方法:找兩張一模一樣的圖,待檢測圖先旋轉90度,樣本圖為此原狀,利用此程式算出旋轉角度並轉正存圖

實驗結果:算出旋轉角度:90.01496444740344 度

raw-image

結果圖

org_img : 待檢測圖,故意旋轉90度

temp_img : 樣本圖,使待檢測圖有個檢測的基準result_img : 算出旋轉角度後,在將待檢測圖旋轉存入

raw-image

程式碼及圖片連結


程式碼範例解說

import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.pyplot as plt

#這是一個 FeatureMatching 類別的初始化方法,用來進行特徵匹配的準備工作。
class FeatureMatching:
def __init__(self, query_image='data/query.jpg'):
self.sift = cv2.SIFT_create()
self.img_query = cv2.imread(query_image, 0)
#讀取temp
if self.img_query is None:
print("Could not find train image " + query_image)
raise SystemExit
self.shape_query = self.img_query.shape[:2] # 對應的是y x
# detectAndCompute 返回關鍵點,跟描述符,供後續特徵匹配做使用
self.key_query, self.desc_query = self.sift.detectAndCompute(self.img_query, None)
FLANN_INDEX_KDTREE = 0
#FLANN 特徵匹配器
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) #使用K-D Tree算法進行最近鄰搜索,trees=5 表示構建K-D Tree時使用的樹的數量。
search_params = dict(checks=50) #checks=50 表示進行搜索時,每次搜索最近鄰時檢查的節點數量。
self.flann = cv2.FlannBasedMatcher(index_params, search_params)

#抽取特徵
def _extract_features(self, frame):
sift = cv2.SIFT_create()
key_train, desc_train = sift.detectAndCompute(frame, None)
return key_train, desc_train
#匹配特徵
def _match_features(self, desc_frame):
matches = self.flann.knnMatch(self.desc_query, desc_frame, k=2)
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
return good_matches
def _detect_corner_points(self, key_frame, good_matches):
src_points = np.float32([self.key_query[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2) #是 query 圖像中好的匹配點對應的特徵點坐標
dst_points = np.float32([key_frame[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2) #是 frame 圖像中好的匹配點對應的特徵點坐標
H, mask = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5.0) #計算兩組對應點之間的單應變換,這裡用於計算 query 到 frame 的變換
matchesMask = mask.ravel().tolist()
h, w = self.img_query.shape[:2]
src_corners = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2) #是 query 圖像的四個角點的坐標,這裡是左上、左下、右下和右上。這些點用於形成一個矩形,後面會被變換到 frame 圖像上
dst_corners = cv2.perspectiveTransform(src_corners, H) #得到在 frame 圖像上的角點坐標
return dst_corners, H, matchesMask

def _frontal_keypoints(self, frame, H):
Hinv = np.linalg.inv(H) #計算單應性矩陣 H 的逆矩陣,得到透視變換的反變換矩陣。
# 從單應性矩陣 H 中提取旋轉部分
print(f'Hinv"{Hinv}')
rotation_matrix = Hinv[:2, :2] # 從逆變換矩陣中提取旋轉部分,這是一個 2x2 的矩陣。
# 計算旋轉角度(以度為單位)
rotation_angle = np.arctan2(rotation_matrix[1, 0], rotation_matrix[0, 0]) * (180 / np.pi) #使用反正切函數 arctan2 計算旋轉角度
print(f"旋轉角度:{rotation_angle} 度")
dst_size = frame.shape[:2]
img_front = cv2.warpPerspective(frame, Hinv, dst_size, flags=cv2.INTER_LINEAR) #應用反變換,對輸入圖像進行逆透視變換,獲得正面視角的圖像。
return img_front , rotation_angle

def match(self, frame):
img_train = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
shape_train = img_train.shape[:2]
key_train, desc_train = self._extract_features(img_train)
good_matches = self._match_features(desc_train)
if len(good_matches) < 4:
self.num_frames_no_success += 1
return False, frame
# drawMatchesKnn 函數在兩張圖像之間繪製特徵匹配的結果, self.img_query:即模板圖像 img_train即待匹配的圖像
img_match = cv2.drawMatchesKnn(self.img_query, self.key_query, img_train, key_train, [good_matches], None,
flags=2)
plt.imshow(img_match) #繪製匹配的結果
plt.show()
#算出變換後的角點座標,單映矩陣,matchesMask被用來只繪製模型的內點
dst_corners, Hinv, _ = self._detect_corner_points(key_train, good_matches)
dst_ravel = dst_corners.ravel()
#檢查角點座標是否超出範圍
dst_ravel_Spec = 1500 #可允許範圍
if (dst_ravel > shape_train[0] + dst_ravel_Spec).any() and (dst_ravel > -dst_ravel_Spec).any() \
and (dst_ravel > shape_train[1] + dst_ravel_Spec).any():
self.num_frames_no_success += 1
print('角點離圖片太遠')
return False, frame
#轉換成正面視角
img_front, img_angle = self._frontal_keypoints(frame, Hinv)
return True, img_front , img_angle

def rotate_image(image, angle):
# 取得影像中心點坐標
center = tuple(np.array(image.shape[1::-1]) / 2)
# 設定旋轉矩陣
rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
# 進行影像旋轉
rotated_image = cv2.warpAffine(image, rotation_matrix, image.shape[1::-1], flags=cv2.INTER_LINEAR)
# 將旋轉後的影像存儲
output_path = "F:/python/opencv/Result.jpg"
cv2.imwrite(output_path, rotated_image)
return rotated_image

#載入原圖
img_train = cv2.imread('rotation.jpg')
#載入樣本圖
temp_img = cv2.imread('temp_org.jpg')
matching = FeatureMatching(query_image='temp_org.jpg')

flag , img_front, img_angle = matching.match(img_train)
#算出的角度需要 換方向 加負號
Result_img = rotate_image(img_train , -img_angle)

# 將結果轉換回彩色圖
img_train = cv2.cvtColor(img_train, cv2.COLOR_BGR2RGB)
temp_img = cv2.cvtColor(temp_img, cv2.COLOR_BGR2RGB)
Result_img = cv2.cvtColor(Result_img, cv2.COLOR_BGR2RGB)
# 顯示原始圖片和結果
plt.subplot(1, 3, 1), plt.imshow(img_train), plt.title('org_img'), plt.axis('off')
plt.subplot(1, 3, 2), plt.imshow(temp_img), plt.title('temp_img'), plt.axis('off')
plt.subplot(1, 3, 3), plt.imshow(Result_img), plt.title('result_img'), plt.axis('off')
plt.show()

函式功能解說

FeatureMatching :特徵匹配的類別,初始化方法__init__用來進行特徵匹配的準備工作,包括使用SIFT算法檢測並計算特徵點,使用FLANN特徵匹配器進行特徵匹配等。

_extract_features 方法:抽取圖片的特徵,這裡使用SIFT算法。

_match_features 方法:進行特徵匹配,這裡使用FLANN特徵匹配器。

_detect_corner_points 方法:檢測匹配到的角點,計算透視變換矩陣。

_frontal_keypoints 方法:根據透視變換矩陣,將圖片轉換成正面視角。

match 方法:實際進行特徵匹配,並根據透視變換將圖片轉換成正面視角。

在主程式中,載入原圖、樣本圖,並使用 FeatureMatching 進行特徵匹配。接著,使用 _frontal_keypoints 將匹配的圖片轉換成正面視角,然後使用 rotate_image 方法進行影像旋轉,最後顯示原始圖片、樣本圖片和結果圖片。

rotate_image 方法:這是一個影像旋轉的函式,使用 OpenCV 的 cv2.getRotationMatrix2D cv2.warpAffine 函數進行旋轉。

FeatureMatching 類別初始化 (__init__ 方法)

def __init__(self, query_image='data/query.jpg'):
# 初始化 SIFT 物件
self.sift = cv2.SIFT_create()
# 讀取模板圖片(query_image)
self.img_query = cv2.imread(query_image, 0)
if self.img_query is None:
print("Could not find train image " + query_image)
raise SystemExit
# 取得模板圖片的形狀(高度和寬度)
self.shape_query = self.img_query.shape[:2]
# 用 SIFT 算法提取模板圖片的關鍵點和描述符
self.key_query, self.desc_query = self.sift.detectAndCompute(self.img_query, None)
# 使用 FLANN 特徵匹配器
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
self.flann = cv2.FlannBasedMatcher(index_params, search_params)

在 __init__ 方法中,這是 FeatureMatching 類別的初始化部分。以下是詳細說明:

  1. self.sift = cv2.SIFT_create(): 創建了一個 SIFT 物件,用於後續的特徵提取。
  2. self.img_query = cv2.imread(query_image, 0): 讀取指定路徑的模板圖片(query_image),並以灰度模式(0 表示灰度)讀入。
  3. if self.img_query is None: ...: 檢查是否成功讀取模板圖片,如果未成功,則輸出錯誤信息並退出程式。
  4. self.shape_query = self.img_query.shape[:2]: 取得模板圖片的形狀,即高度和寬度,存儲在 self.shape_query 中。
  5. self.key_query, self.desc_query = self.sift.detectAndCompute(self.img_query, None): 使用 SIFT 算法檢測並計算模板圖片的關鍵點和描述符。

self.key_query:存儲關鍵點

以行動支持創作者!付費即可解鎖
本篇內容共 15753 字、3 則留言,僅發佈於[Python][OpenCV]學習心得筆記你目前無法檢視以下內容,可能因為尚未登入,或沒有該房間的查看權限。
119會員
201內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。
留言0
查看全部
發表第一個留言支持創作者!
螃蟹_crab的沙龍 的其他內容
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
在樹莓派安裝OpenCV的紀錄。板子是樹莓派3B(沒有+),系統raspbian bullseye 32bit灌到USB隨身碟。
Thumbnail
#安裝 OpenCV 相關套件 pip install opencv-python pip install opencv-contrib-python pip install matplotlib
Haar Cascade classifier OpenCV 官方 Github:https://github.com/opencv/opencv/tree/4.x/data 人臉特徵模型:haarcascade_frontalface_default.xml 資料來源: https://steam
Thumbnail
OpenCV 讀取圖片 原碼:https://reurl.cc/3354ZL 成果: OpenCV 本身有提供讀取圖檔的函數可用,讀取圖檔,只要呼叫 cv2.imread 即可將圖片讀取進來,以 cv2.imread 讀進來的資料,會儲存成一個 NumPy 的陣列。 將圖片讀取進來之後,可使用 c
opencv is use BGR color matplotlib is use RGB color 顯示圖片 opencv matplotlib
Thumbnail
初稿 作者: Stan Ht. Wu (stanwu 吳信典) 想像一下,如果整台電腦裝瀏覽器就好了?這樣多輕鬆啊!人生就是要斷捨離,什麼都不裝,就用瀏覽器就好了,您看連寫方格子的文章也是直接用瀏覽器耶!! 用瀏覽器基本上是最符合懶人原則,為什麼呢?因為從頭到尾根本不需要切換應用程式,存檔案放在雲端
Thumbnail
OpenCart 官方的 3.0.3.7 版於上周釋出,除了修正許多 3.0.x 版累積的小問題,也更新了 twig 套件解決了 PHP 7.4 的相容問題,所以 OpenCart 台灣電商技術團隊,也以 OpenCart 3.0.3.7 版為基礎,加上了在地優化及實用模組,推出台灣優化版。
Thumbnail
綠界科技雖然為 OpenCart 電商系統推出了可直接安裝使用的金流擴充模組,但其設計的模組架構,並不算完全符合 OpenCart 金流模組的架構規則,包含後臺編輯不同付款方式時的設定,無法獨立分開設定,前台的金流選擇,更是被設計成兩段式的模式,非常不符合台灣消費者慣用的習性。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
在樹莓派安裝OpenCV的紀錄。板子是樹莓派3B(沒有+),系統raspbian bullseye 32bit灌到USB隨身碟。
Thumbnail
#安裝 OpenCV 相關套件 pip install opencv-python pip install opencv-contrib-python pip install matplotlib
Haar Cascade classifier OpenCV 官方 Github:https://github.com/opencv/opencv/tree/4.x/data 人臉特徵模型:haarcascade_frontalface_default.xml 資料來源: https://steam
Thumbnail
OpenCV 讀取圖片 原碼:https://reurl.cc/3354ZL 成果: OpenCV 本身有提供讀取圖檔的函數可用,讀取圖檔,只要呼叫 cv2.imread 即可將圖片讀取進來,以 cv2.imread 讀進來的資料,會儲存成一個 NumPy 的陣列。 將圖片讀取進來之後,可使用 c
opencv is use BGR color matplotlib is use RGB color 顯示圖片 opencv matplotlib
Thumbnail
初稿 作者: Stan Ht. Wu (stanwu 吳信典) 想像一下,如果整台電腦裝瀏覽器就好了?這樣多輕鬆啊!人生就是要斷捨離,什麼都不裝,就用瀏覽器就好了,您看連寫方格子的文章也是直接用瀏覽器耶!! 用瀏覽器基本上是最符合懶人原則,為什麼呢?因為從頭到尾根本不需要切換應用程式,存檔案放在雲端
Thumbnail
OpenCart 官方的 3.0.3.7 版於上周釋出,除了修正許多 3.0.x 版累積的小問題,也更新了 twig 套件解決了 PHP 7.4 的相容問題,所以 OpenCart 台灣電商技術團隊,也以 OpenCart 3.0.3.7 版為基礎,加上了在地優化及實用模組,推出台灣優化版。
Thumbnail
綠界科技雖然為 OpenCart 電商系統推出了可直接安裝使用的金流擴充模組,但其設計的模組架構,並不算完全符合 OpenCart 金流模組的架構規則,包含後臺編輯不同付款方式時的設定,無法獨立分開設定,前台的金流選擇,更是被設計成兩段式的模式,非常不符合台灣消費者慣用的習性。