1. 程式人生 > >計算機視覺(二):影象檢索以及基於影象描述符的搜尋

計算機視覺(二):影象檢索以及基於影象描述符的搜尋

1 - 引言

在影象識別中,我們通常將圖片的特徵提取出來,並使用這些主要特徵來進行識別。
在OpenCV中提供了許多特徵檢測演算法,下面讓我們來學習一下怎麼使用這些演算法

2 - 特徵定義

粗略的講,特徵就是有意義的影象區域,該區域具有獨特性或易於識別性。因此,角點以及高密度區域是很好的特徵,而大量重複的模式或低密度區域則不是好的特徵。大多數特徵檢測演算法都會涉及影象的角點、變和斑點的識別。

2.1 - 檢測角點特徵

Opencv提供cornerHarris來識別角點

import cv2
import numpy as np

img = cv2.imread('images/7.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray,2,23,0.04)
"""
第二引數是標記號的大小。即引數值越小,標記角點的記號越小
最重要的是第三個引數,該引數限定了Sobel運算元的中孔,取值必須是介於3和31之間的奇數。
"""
img[dst>0.01*dst.max()] = [0,0,255]
while(True):
    cv2.imshow('corners',img)
    if cv2.waitKey(0):
        break


在這裡插入圖片描述

2.2 - 使用DoG和SIFT進行特徵提取與描述

  • DoG(Diffrerence of Gaussians)是對同一影象使用不同高斯濾波器所得到的結果
  • SIFT是尺度不變特徵變換(Scale-Invariant Feature Transform, SIFT),可以解決因影象比例而損失特徵的變換
    (最新版本的OpenCV中SIFT函式已經被專利保護不能使用,需要安裝老版本才能使用,本文使用了3.4.2.16版本)
import cv2
import sys
import numpy as py

# 讀入影象
# imgpath=sys.argv[1]
imgpath = 'images/timg_1.jpg'
img = cv2.imread(imgpath)
# 更換顏色空間
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 建立sift物件,計算灰度影象,會使用dog檢測角點
sift = cv2.xfeatures2d.SIFT_create()
keypoints, descriptor = sift.detectAndCompute(gray, None)

# print(keypoints)
# 關鍵點有以下幾個屬性
# angle 表示特徵的方向
# class_id 關鍵點的id
# octave 特徵所在金字塔的等級
# pt 影象中關鍵點的座標
# response 表示關鍵點的強度
# size 表示特徵的直徑
img = cv2.drawKeypoints(image=img,
 outImage=img,
 keypoints=keypoints,
 color=(51, 163, 236),
 flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# 顯示影象
cv2.imshow('sift_keypoints', img)
while (True):
 if cv2.waitKey(int(1000 / 12)) & 0xFF == ord('q'):
    break
cv2.destroyAllWindows()

在這裡插入圖片描述

2.3 使用快速Hessian演算法和SURF來提取和檢測特徵

SURF特徵檢測演算法由Herbert Bay於2006年發表,該演算法比SIFT快好幾倍,它吸收了SIFT演算法的思想。(也被專利保護)

import cv2
import numpy as np

img = cv2.imread('images/timg_1.jpg')  # 讀取要處理的圖片
alg = input('Select an Alg --> ')


def fd(algorithm):
    if algorithm == 'SIFT':
        return cv2.xfeatures2d.SIFT_create()
    if algorithm == 'SURF':
        threshold = input('Enter a threshold --> ')  # 提示輸入SURF演算法所採用的閾值
        return cv2.xfeatures2d.SURF_create(float(threshold))


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 轉換為灰度影象
fd_alg = fd(alg)
keypoints, descriptor = fd_alg.detectAndCompute(gray, None)  # 進行演算法的檢測和計算

img = cv2.drawKeypoints(image=img, outImage=img, keypoints=keypoints,
                        flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
                        color=(51, 163, 236))
cv2.imshow('keypoints', img)
while (True):
    if cv2.waitKey(30) & 0xff == ord('q'):
        break
cv2.destroyAllWindows()

使用SURF演算法,並且閾值設為8000所得的結果,閾值越高提取的特徵也越少,我們可以修改閾值來達到最好的特徵提取效果
在這裡插入圖片描述

2.4 - 基於ORB的特徵檢測和特徵匹配

ORB處於起步階段,是用來替代SIFT和SURF的,與二者相比,ORB有更快的速度,在2011年才首次釋出,ORB基於FAST關鍵點檢測和BRIEF描述符的技術結合

  1. FAST演算法
    在畫素周圍繪製一個圓,該圓包括16個畫素,然後將每個畫素與加上一個閾值的圓心畫素進行比較,若有連續、比加上上一個閾值的圓心的畫素值還亮或者暗的畫素,則可認為圓心是角點。

  2. BRIEF演算法
    是一種關鍵點描述符,並找到他們的共同之處,是一種特徵匹配的演算法。

  3. 暴力匹配

下面先使用最簡單的暴力匹配來實現特徵匹配

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

img1 = cv2.imread('images/LAKERS_LOGO.jpg',cv2.IMREAD_GRAYSCALE)#希望檢測出的特徵圖片
img2 = cv2.imread('images/LAKERS.jpg',cv2.IMREAD_GRAYSCALE)#測試圖片

orb = cv2.ORB_create()
"""
分別對查詢影象和訓練影象進行檢測,然後計算關鍵點和描述符
"""
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True)
"""
使用暴力BFMatcher實現匹配
"""
matches = bf.match(des1,des2)
matches = sorted(matches, key= lambda x:x.distance)
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:40],img2,flags=2)
plt.imshow(img3),plt.show()

LOGO影象:
在這裡插入圖片描述

球場影象:
在這裡插入圖片描述

進行匹配後:
在這裡插入圖片描述

  1. K-NN匹配

使用機器學習中的K-NN演算法來替代暴力匹配法
只需稍微修改上面的程式碼即可

matches = bf.knnMatch(des1,des2,k=2)
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,img2,flags=2)
  1. FLANN匹配

FLANN是最近鄰的快速庫,也就是說FLANN可以在庫中根據資料本身來選擇最適合的演算法進行匹配,經驗證,FLANN比其他的最近鄰搜尋軟體塊10倍