Python 進行目標檢測

来源:https://www.cnblogs.com/zhj-Szu/archive/2020/02/15/12311082.html
-Advertisement-
Play Games

一、前言 從學單片機開始鼓搗C語言,到現在為了學CV鼓搗Python,期間在CSDN、簡書、博客園和github這些地方得到了很多幫助,所以也想把自己做的一些小東西分享給大家,希望能幫助到別人。記錄人生的第一篇博客,mark。 二、圖像檢測步驟 1. 讀取兩張圖片 第一張是需要檢測的小物體,第二章圖 ...


一、前言

  從學單片機開始鼓搗C語言,到現在為了學CV鼓搗Python,期間在CSDN、簡書、博客園和github這些地方得到了很多幫助,所以也想把自己做的一些小東西分享給大家,希望能幫助到別人。記錄人生的第一篇博客,mark。

二、圖像檢測步驟

1. 讀取兩張圖片

  第一張是需要檢測的小物體,第二章圖片是小物體放置在大場景中。代碼與輸出結果如下所示:

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

def my_show(img):
    plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
    return 

# 讀取圖片
img_small=cv2.imread('small.jpg',1)
img_big=cv2.imread('big.jpg',1)

# 顯示圖片
plt.figure(figsize=(10,10))
plt.subplot(121)
my_show(img_small)
plt.subplot(122)
my_show(img_big)

 

2. 提取圖片中的特征點

  這一步就像我們在區分不同的人的時候,一眼看到外貌就知道此人是誰,而外貌就是這個人的特征。我們希望提取該物體的特征點,以便在不同的場景中識別出來。圖片是由像素點構成,但是像素點包含的信息太零散了,一般是識別物體的邊緣或者角點作為特征信息。常用的特征描述演算法如下:

  SIFThttps://blog.csdn.net/zddblog/article/details/7521424

  harris corner detection: https://www.jianshu.com/p/efc81fdb8afb

  Hog: https://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf

  SURF: https://www.vision.ee.ethz.ch/~surf/eccv06.pdf

  BRISK: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.371.1343&rep=rep1&type=pdf

  Orb: http://www.willowgarage.com/sites/default/files/orb_final.pdf

  我們項目中用到的是SIFT演算法,SIFT精確度高,對尺度、亮度以及旋轉的魯棒性強,不過計算時間長,所需的計算資源較多。SURF是SIFT的加速版本,有興趣的小伙伴可以瞭解一下。SIFT演算法運行後,可以得到的特征點的位置以及特征向量。(PS:SIFT演算法申請了專利,所以在opencv3.4.2版本後不能使用了,需要用SIFT的請安裝3.4.2的opencv)

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

def my_show(img):
    plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
    return 

# 讀取圖片
img_small=cv2.imread('small.jpg',1)
img_big=cv2.imread('big.jpg',1)

# 提取特征點
sift=cv2.xfeatures2d.SIFT_create()
kp1,des1=sift.detectAndCompute(img_small,None)
kp2,des2=sift.detectAndCompute(img_big,None)

# 在圖中顯示特征點
img_small_sift=cv2.drawKeypoints(img_small,kp1,outImage=np.array([]),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
img_big_sift=cv2.drawKeypoints(img_big,kp2,outImage=np.array([]),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

plt.figure(figsize=(15,15))
plt.subplot(121)
my_show(img_small_sift)
plt.subplot(122)
my_show(img_big_sift)

 

3.特征點匹配

  在分別提取了兩張圖的特征點後,就需要進行特征點匹配啦。這裡需要註意的是,兩張圖的特征點數量一般情況下是不一樣的,opencv演算法里預設用第一張圖的特征點來匹配,所以匹配矩陣的行數與第一張圖特征點的行數一致。常用的匹配方法:

  Brute-Force: 暴力搜索,用圖1的特征點逐一與圖二的特征點比較,找到歐式距離最小的點作為匹配點。不過這樣匹配的錯誤點就會很多,所以常用交叉匹配法消除錯誤匹配。交叉匹配法指的是,反過來匹配一次,用匹配到圖2的點反過來匹配圖1的點,如果匹配結果與原來相同,則認為是正確匹配。

  KNN: K近鄰匹配,在匹配的時候選擇K個和特征點最相似的點,如果這K個點之間的區別足夠大,則選擇最相似的那個點作為匹配點,通常選擇K = 2。KNN匹配也會出現一些誤匹配,這時候需要對比第一鄰近與第二鄰近之間的距離大小,假如 distance_1< (0.5~0.7)*distance_2, 則認為是正確匹配。

  FLANN: FLANN是快速最近鄰搜索包(Fast Library for Approximate Nearest Neighbors)的簡稱,是最近鄰搜索的演算法的集合。

  一般我們會選擇調用cv2.Brute-Force或者cv2.FlannBasedMatcher來進行特征點匹配,FLANN裡邊就包含的KNN、KD樹還有其他的最近鄰演算法。

 

4.計算單應性矩陣

  這裡我們需要在大場景中用矩形框出匹配的小物體,所以就要計算單應性矩陣,然後做投影變換。RANSAC(Random Sample Consensus隨機抽樣一致性演算法是計算單應性矩陣的有效方法,並且在尋找單應性矩陣的過程中可以進一步剔除錯誤匹配點。RANSAC演算法的步驟如下:

  •  隨機抽取四個匹配點對計算投影矩陣,需要檢驗四個點是否共線
  •  圖片1特征點坐標齊次變換後(3,1)乘上投影矩陣(3,3),然後計算變換後的特征點坐標與圖片2特征點坐標的歐氏距離,小於設定的閾值則記錄為內點,反之則為內點
  •  判斷此次內點的數量是否比以往記錄的內點最大值多,如果是,則更新投影矩陣,如果不是,則不更新
  •  判定迴圈次數是夠達到設定次數或內點數占全部匹配點的比例達到設定比例,則跳出迴圈,否則跳到步驟1繼續迴圈

  尋找到最優的單應性矩陣後,將框住物體一的矩陣經投影變換後在圖片二上畫出來,完成目標檢測框選。以下代碼摘自Brook@CV的博客並修改,如有侵權,請通知刪除

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

MIN_MATCH_COUNT = 10

img1 = cv2.imread('small.jpg',1)
img2 = cv2.imread('big.jpg',1)

# 使用SIFT檢測角點
sift = cv2.xfeatures2d.SIFT_create()
# 獲取關鍵點和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# 定義FLANN匹配器
index_params = dict(algorithm = 1, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 使用KNN演算法匹配
matches = flann.knnMatch(des1,des2,k=2)

# 去除錯誤匹配
good = []
for m,n in matches:
    if m.distance <= 0.7*n.distance:
        good.append(m)

# 單應性
if len(good)>MIN_MATCH_COUNT:
    # 改變數組的表現形式,不改變數據內容,數據內容是每個關鍵點的坐標位置
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
    # findHomography 函數是計算變換矩陣
    # 參數cv2.RANSAC是使用RANSAC演算法尋找一個最佳單應性矩陣H,即返回值M
    # 返回值:M 為變換矩陣,mask是掩模
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    # ravel方法將數據降維處理,最後並轉換成列表格式
    matchesMask = mask.ravel().tolist()
    # 獲取img1的圖像尺寸
    h,w,dim = img1.shape
    # pts是圖像img1的四個頂點
    pts = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
    # 計算變換後的四個頂點坐標位置
    dst = cv2.perspectiveTransform(pts,M)

    # 根據四個頂點坐標位置在img2圖像畫出變換後的邊框
    img2 = cv2.polylines(img2,[np.int32(dst)],True,(0,0,255),3, cv2.LINE_AA)

else:
    print("Not enough matches are found - %d/%d") % (len(good),MIN_MATCH_COUNT)
    matchesMask = None

# 顯示匹配結果
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
                   singlePointColor = None,
                   matchesMask = matchesMask, # draw only inliers
                   flags = 2)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.figure(figsize=(20,20))
plt.imshow(cv2.cvtColor(img3,cv2.COLOR_BGR2RGB))
plt.show()

最後給大家放上原圖可以跑一下程式!

 

 

 

 

 

 

 

      

 

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • javaSE學習筆記(15) 緩衝流、轉換流、序列化流 緩衝流 昨天複習了基本的一些流,作為IO流的入門,今天我們要見識一些更強大的流。比如能夠高效讀寫的緩衝流,能夠轉換編碼的轉換流,能夠持久化存儲對象的序列化流等等。這些功能更為強大的流,都是在基本的流對象基礎之上創建而來的,相當於是對基本流對象的 ...
  • 楔子 假如我現在有一個列表l=['a','b','c','d','e'],我想取列表中的內容,有幾種方式? 首先,我可以通過索引取值l[0],其次我們是不是還可以用for迴圈來取值呀? 你有沒有仔細思考過,用索引取值和for迴圈取值是有著微妙區別的。 如果用索引取值,你可以取到任意位置的值,前提是你 ...
  • 楔子 作為一個會寫函數的python開發,我們從今天開始要去公司上班了。寫了一個函數,就交給其他開發用了。 def func1(): print('in func1') 季度末,公司的領導要給大家發績效獎金了,就提議對這段日子所有人開發的成果進行審核,審核的標準是什麼呢?就是統計每個函數的執行時間。 ...
  • 楔子 假如有一個函數,實現返回兩個數中的較大值: def my_max(x,y): m = x if x>y else y return mbigger = my_max(10,20)print(bigger) 之前是不是我告訴你們要把結果return回來你們就照做了?可是你們有沒有想過,我們為什麼 ...
  • 好久時間沒有做Django的項目了,今天創建項目竟然報Non-zero exit code(1)錯誤 查明原因是因為pip不是最新版本,需要執行以下命令:python -m pip install --upgrade pip 但還是沒有成功,提示超時,估計源有問題 使用豆瓣源進行安裝,問題解決了 命 ...
  • 前言最近由於疫情被困在家,於是準備每天看點專業知識,準備寫成博客,不定期發佈。博客大概會寫5~7篇,主要是“解剖”一些深度學習的底層技術。關於深度學習,電腦專業的人多少都會瞭解,知道Conv\Pool的過程,也看過論文,做過實驗或是解決方案。在寫的各種捲積網路 時候,有沒有問問自己:這些網路到底是... ...
  • 為什麼要用函數 現在python屆發生了一個大事件,len方法突然不能直接用了。。。 然後現在有一個需求,讓你計算'hello world'的長度,你怎麼計算? 這個需求對於現在的你其實不難,我們一起來寫一下。 s1 = "hello world" length = 0 for i in s1: l ...
  • 慕課網-悟空-玩轉Java併發工具,精通JUC,成為併發多面手-筆記 微雲:https://share.weiyun.com/81aa12bb98016e200add31fb8e191cdf百度網盤:鏈接:https://pan.baidu.com/s/1IiClTkQwFJgBL2NqlptKbA ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...