付費限定

[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]學習心得筆記你目前無法檢視以下內容,可能因為尚未登入,或沒有該房間的查看權限。
avatar-img
131會員
218內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
螃蟹_crab的沙龍 的其他內容
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
使用 LBP(Local Binary Patterns) 進行紋理分析和瑕疵檢測 Local Binary Patterns(LBP) 是一種用來描述圖像紋理的特徵提取技術。LBP 對於檢測表面紋理的異常具有很好的效果,尤其在檢測紋理一致的材料表面(例如紡織品、紙張、金屬)時,LBP 非常有用。
Thumbnail
Python資料視覺化在數據分析中扮演關鍵角色,透過視覺化捕捉數據模式、趨勢和異常,透過Matplotlib等工具創建專業圖表變相對簡單和高效。
Thumbnail
接續上一邊,分割了螺絲與螺母的圖像,但分割後的結果,因為螺絲過於接近的關係,沒有切割乾淨,會有其他螺絲的頭或者身體,這樣會影響到後續量測。 [OpenCV應用][Python]擷取出螺絲或螺母的影像 本文主要是,如何去除掉不要的背景雜物。 下層為原先分割的圖,上層為去除背景雜物的圖。
Thumbnail
先上成果圖,如果是螺母的話就標註 is circle來區分。 簡單的用圖表加文字說明AOI辨識 在此文章的範例中: 影像前處理:色彩空間轉換(灰階) -> 二值化閥值處理 演算法:尋找輪廓 數值判斷:長,寬,面積,周長 圖片來源 程式碼 import cv2 import nu
Thumbnail
import openai import os from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) openai.api_key = os.getenv('OPENAI_API_KEY')
Thumbnail
寬景Wide view 鳥瞰Bird view 前景Foreground 背景Background 正面Front View 側面Side View 俯視Top View 景深Depth of field 微距鏡頭Macro Shot 超特寫Extreme Close up
Thumbnail
很多AI只要輸入相關的鏡頭的關鍵字,視覺畫面會隨著鏡頭移動。 鏡頭與視角的關鍵字: 微觀|Microscopic view 焦點,對焦|Focus 第一人稱|First person perspective 第三人稱|Third person perspective 特寫|Close
Thumbnail
找出區間[1, n] 內的軸心點位置。通過介紹直覺法、改良直覺法和二分搜尋等算法,最終給出了解析解(推導軸心點的公式解),提供了對應的程式碼和參考資料。該問題的最優解是使用解析解,能夠在O(1)的時間複雜度內找到答案。
Thumbnail
大部分在求物件的寬度及高度,都會想到用OpenCV的findContours函式來做,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度 [OpenCV應用][Python]利用findContours找出物件邊界框求出寬度及高度 本文將用不同的方法,利用Numpy
Thumbnail
本文將利用OpenCV的findContours函式,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度。 一般來說,我們在進行輪廓檢測時,會先進行圖像二值化,將對象轉換為白色,背景為黑色。這樣,在找到輪廓後,輪廓的點就會以白色表示,背景為黑色。 結果圖 從圖中綠色框
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
使用 LBP(Local Binary Patterns) 進行紋理分析和瑕疵檢測 Local Binary Patterns(LBP) 是一種用來描述圖像紋理的特徵提取技術。LBP 對於檢測表面紋理的異常具有很好的效果,尤其在檢測紋理一致的材料表面(例如紡織品、紙張、金屬)時,LBP 非常有用。
Thumbnail
Python資料視覺化在數據分析中扮演關鍵角色,透過視覺化捕捉數據模式、趨勢和異常,透過Matplotlib等工具創建專業圖表變相對簡單和高效。
Thumbnail
接續上一邊,分割了螺絲與螺母的圖像,但分割後的結果,因為螺絲過於接近的關係,沒有切割乾淨,會有其他螺絲的頭或者身體,這樣會影響到後續量測。 [OpenCV應用][Python]擷取出螺絲或螺母的影像 本文主要是,如何去除掉不要的背景雜物。 下層為原先分割的圖,上層為去除背景雜物的圖。
Thumbnail
先上成果圖,如果是螺母的話就標註 is circle來區分。 簡單的用圖表加文字說明AOI辨識 在此文章的範例中: 影像前處理:色彩空間轉換(灰階) -> 二值化閥值處理 演算法:尋找輪廓 數值判斷:長,寬,面積,周長 圖片來源 程式碼 import cv2 import nu
Thumbnail
import openai import os from dotenv import load_dotenv, find_dotenv _ = load_dotenv(find_dotenv()) openai.api_key = os.getenv('OPENAI_API_KEY')
Thumbnail
寬景Wide view 鳥瞰Bird view 前景Foreground 背景Background 正面Front View 側面Side View 俯視Top View 景深Depth of field 微距鏡頭Macro Shot 超特寫Extreme Close up
Thumbnail
很多AI只要輸入相關的鏡頭的關鍵字,視覺畫面會隨著鏡頭移動。 鏡頭與視角的關鍵字: 微觀|Microscopic view 焦點,對焦|Focus 第一人稱|First person perspective 第三人稱|Third person perspective 特寫|Close
Thumbnail
找出區間[1, n] 內的軸心點位置。通過介紹直覺法、改良直覺法和二分搜尋等算法,最終給出了解析解(推導軸心點的公式解),提供了對應的程式碼和參考資料。該問題的最優解是使用解析解,能夠在O(1)的時間複雜度內找到答案。
Thumbnail
大部分在求物件的寬度及高度,都會想到用OpenCV的findContours函式來做,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度 [OpenCV應用][Python]利用findContours找出物件邊界框求出寬度及高度 本文將用不同的方法,利用Numpy
Thumbnail
本文將利用OpenCV的findContours函式,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度。 一般來說,我們在進行輪廓檢測時,會先進行圖像二值化,將對象轉換為白色,背景為黑色。這樣,在找到輪廓後,輪廓的點就會以白色表示,背景為黑色。 結果圖 從圖中綠色框