python進階—OpenCV之圖像特徵檢測與描述


這是官方教程的第四篇,OpenCV之圖像特徵檢測,繼續學習opencv。
原教程花了很大篇幅介紹圖像的特徵是什麼含義,如何描述他們,並用“拼圖”遊戲來解釋它們。簡單說圖像的特徵就是一些邊邊角角、變化非常明顯的區域,能在圖片中明顯定位的元素,然後用一些數據去描述這些特徵。

Harris角點檢測

Harris角點檢測是Chris Harris和Mike Stephens在1988年提出的。主要用於運動圖像的追蹤。當時的普遍想法是利用邊緣進行追蹤,但是當相機或物體運動時你不知道朝哪個方向,相機的幾何變換也是未知的,所以邊緣匹配很難達到預期的效果。即使是當時最優秀的邊緣檢測算子Canny算子,它的邊緣檢測也依賴於閾值的選取。所以Harris等人放棄了匹配邊緣,轉而尋找一些特殊的點來匹配,這些點是邊緣線段的連接點,它們表徵了圖像的結構,代表了圖像局部的特徵。

Harris角點檢測

  • 函數原型:dst = cv.cornerHarris( src, blockSize, ksize, k[, dst[, borderType]] )
  • src:輸入圖像,單通道8bit灰度圖像或者float32型的圖像
  • dst:角點檢測後圖像,圖像類型爲CV_32FC1,尺寸與原圖一致
  • blockSize:鄰域尺寸大小
  • ksize:sobel邊緣檢測窗口大小
  • k:係數值,通常取值範圍爲0.04 ~ 0.06之間
  • borderType:邊沿像素推斷方法,即邊沿類型
import numpy as np
import cv2 as cv
filename = 'chessboard.png'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
cv.imshow('dst',img)
if cv.waitKey(0) & 0xff == 27:
    cv.destroyAllWindows()

在這裏插入圖片描述

Corner with SubPixel Accuracy

Harris角點檢測存在很多缺陷,如角點是像素級別的,速度較慢,準確度不高等

  • 函數原型:corners = cv.cornerSubPix( image, corners, winSize, zeroZone, criteria )
  • image:輸入圖像
  • corners:輸入的初始角點座標集合,通常是Harris角點檢測的結果,輸出時修改爲精確檢測的檢點座標
  • winSize:計算亞像素角點時考慮的區域的大小,大小爲NXN; N=(winSize*2+1);For example, if winSize=Size(5,5) , then a 5∗2+1×5∗2+1=11×11 search window is used.
  • zeroZone:類似於winSize,搜索窗口中dead region大小的一半,Size(-1,-1)表示忽略,主要用於避免自相關矩陣中可能的奇點(自己翻譯,不明所以)
  • criteria:評判規則,表示計算亞像素時停止迭代的標準,可選的值有cv::TermCriteria::MAX_ITER 、cv::TermCriteria::EPS(可以是兩者其一,或兩者均選),前者表示迭代次數達到了最大次數時停止,後者表示角點位置變化的最小值已經達到最小時停止迭代。二者均使用cv::TermCriteria()構造函數進行指定
import numpy as np
import cv2 as cv
filename = 'chessboard2.jpg'
img = cv.imread(filename)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# find Harris corners
gray = np.float32(gray)
dst = cv.cornerHarris(gray,2,3,0.04)
dst = cv.dilate(dst,None)
ret, dst = cv.threshold(dst,0.01*dst.max(),255,0)
dst = np.uint8(dst)
# find centroids
ret, labels, stats, centroids = cv.connectedComponentsWithStats(dst)
# define the criteria to stop and refine the corners
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
# Now draw them
res = np.hstack((centroids,corners))
res = np.int0(res)
img[res[:,1],res[:,0]]=[0,0,255]
img[res[:,3],res[:,2]] = [0,255,0]
cv.imwrite('subpixel5.png',img)

在這裏插入圖片描述
圖中紅色點表示Harris角點檢測的結果,綠色點表示經過SubPixel優化過的角點檢測結果。

Shi-Tomasi角點檢測

Shi-Tomasi 算法是Harris 算法的改進。Harris 算法最原始的定義是將矩陣 M 的行列式值與 M 的跡相減,再將差值同預先給定的閾值進行比較。後來Shi 和Tomasi 提出改進的方法,若兩個特徵值中較小的一個大於最小閾值,則會得到強角點。

  • 函數原型:corners = cv.goodFeaturesToTrack( image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]] )
  • image:8位或32位單通道灰度圖像
  • corners:角點向量,保存的是檢測到的角點的座標
  • maxCorners:定義可以檢測到的角點的數量的最大值,maxCorners <= 0 表示無限制
  • qualityLevel:檢測到的角點的質量等級,角點特徵值小於qualityLevel*最大特徵值的點將被捨棄 For example, if the best corner has the quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure less than 15 are rejected.
  • minDistance:兩個角點間最小間距,以像素爲單位
  • mask:感興趣的角點檢測區域,指定角點檢測區域,類型爲CV_8UC1
  • blockSize:計算協方差矩陣時的窗口大小
  • useHarrisDetector:是否使用Harris角點檢測,爲false,則使用Shi-Tomasi算子
  • k:Harris角點檢測算子用的中間參數,一般取經驗值0.04~0.06;useHarrisDetector參數爲false時,該參數不起作用
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('blox.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray,25,0.01,10)
corners = np.int0(corners)
for i in corners:
    x,y = i.ravel()
    cv.circle(img,(x,y),3,255,-1)
plt.imshow(img),plt.show()

在這裏插入圖片描述

尺度不變特徵變換算法SIFT (Scale-Invariant Feature Transform)

SIFT算法的特點:

  1. SIFT特徵是圖像的局部特徵,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持一定程度的穩定性;
  2. 獨特性(Distinctiveness)好,信息量豐富,適用於在海量特徵數據庫中進行快速、準確的匹配;
  3. 多量性,即使少數的幾個物體也可以產生大量的SIFT特徵向量;
  4. 高速性,經優化的SIFT匹配算法甚至可以達到實時的要求;
  5. 可擴展性,可以很方便的與其他形式的特徵向量進行聯合。

SIFT算法在一定程度上可解決目標的自身狀態、場景所處的環境和成像器材的成像特性等因素影響圖像配準/目標識別跟蹤的性能,主要有以下幾點:

  1. 目標的旋轉、縮放、平移
  2. 圖像仿射/投影變換
  3. 光照影響
  4. 目標遮擋
  5. 雜物場景
  6. 噪聲
import numpy as np
import cv2 as cv
img = cv.imread('test.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
kp = sift.detect(gray,None)
img=cv.drawKeypoints(gray,kp,img)
cv.imwrite('sift_keypoints.jpg',img)
  1. 函數 sift.compute() 用來計算這些關鍵點的描述符。例如: kp; des = sift:compute(gray; kp)。
  2. 函數 sift.detectAndCompute()一步到位直接找到關鍵點並計算出其描述符。

這裏需要描述一下函數:cv.drawKeypoints

  • outImage = cv.drawKeypoints( image, keypoints, outImage[, color[, flags]] )
  • image:查找關鍵點的圖像
  • keypoints:在圖像中查找到的關鍵點
  • outImage:輸出圖像,根據flag的取值,會在輸出圖像畫上flag只是的信息
  • color:關鍵點顏色
  • flags:在輸出圖像上描繪關鍵的標誌,取值如下
    cv2.DRAW_MATCHES_FLAGS_DEFAULT, cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS, cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG, cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS

SURF (Speeded-Up Robust Features)

SIFT 算法可以進行關鍵點檢測和描述,但是這種算法的執行速度比較慢。
與 SIFT 相同 OpenCV 也提供了 SURF 的相關函數。首先我們要初始化一個 SURF 對象,同時設置好可選參數: 64/128 維描述符, Upright/Normal 模式等。

>>> img = cv.imread('fly.png',0)
# Create SURF object. You can specify params here or later.
# Here I set Hessian Threshold to 400
>>> surf = cv.xfeatures2d.SURF_create(400)
# Find keypoints and descriptors directly
>>> kp, des = surf.detectAndCompute(img,None)
>>> len(kp)
 699
 
#在一幅圖像中顯示 699 個關鍵點太多了,我們把它縮減到 50 個再繪製到圖片上。
# Check present Hessian threshold
>>> print( surf.getHessianThreshold() )
400.0
# We set it to some 50000. Remember, it is just for representing in picture.
# In actual cases, it is better to have a value 300-500
>>> surf.setHessianThreshold(50000)
# Again compute keypoints and check its number.
>>> kp, des = surf.detectAndCompute(img,None)
>>> print( len(kp) )
47
>>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4)
>>> plt.imshow(img2),plt.show()

在這裏插入圖片描述

# 不檢測關鍵點的方向
# Check upright flag, if it False, set it to True
>>> print( surf.getUpright() )
False
>>> surf.setUpright(True)
# Recompute the feature points and draw it
>>> kp = surf.detect(img,None)
>>> img2 = cv.drawKeypoints(img,kp,None,(255,0,0),4)
>>> plt.imshow(img2),plt.show()

# 關鍵點描述符的大小,如果是 64 維的就改成 128 維
# Find size of descriptor
>>> print( surf.descriptorSize() )
64
# That means flag, "extended" is False.
>>> surf.getExtended()
 False
# So we make it to True to get 128-dim descriptors.
>>> surf.extended = True
>>> kp, des = surf.detectAndCompute(img,None)
>>> print( surf.descriptorSize() )
128
>>> print( des.shape )
(47, 128)

在這裏插入圖片描述

FAST Algorithm for Corner Detection

  • cv.FAST_FEATURE_DETECTOR_TYPE_5_8,
  • cv.FAST_FEATURE_DETECTOR_TYPE_7_12
  • cv.FAST_FEATURE_DETECTOR_TYPE_9_16

以上3個選擇是鄰域大小的選擇

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('simple.jpg',0)
# Initiate FAST object with default values
fast = cv.FastFeatureDetector_create()
# find and draw the keypoints
kp = fast.detect(img,None)
img2 = cv.drawKeypoints(img, kp, None, color=(255,0,0))
# Print all default params
print( "Threshold: {}".format(fast.getThreshold()) )
print( "nonmaxSuppression:{}".format(fast.getNonmaxSuppression()) )
print( "neighborhood: {}".format(fast.getType()) )
print( "Total Keypoints with nonmaxSuppression: {}".format(len(kp)) )
cv.imwrite('fast_true.png',img2)
# Disable nonmaxSuppression
fast.setNonmaxSuppression(0)
kp = fast.detect(img,None)
print( "Total Keypoints without nonmaxSuppression: {}".format(len(kp)) )
img3 = cv.drawKeypoints(img, kp, None, color=(255,0,0))
cv.imwrite('fast_false.png',img3)

至此,學習遇到瓶頸了,會有一大段時間不會更新OpenCV的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章