国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]

這篇具有很好參考價(jià)值的文章主要介紹了特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)

本文旨在總結(jié)opencv-python上特征點(diǎn)的檢測(cè)和匹配。
1、特征點(diǎn)的檢測(cè)(包括:ORB,SIFT,SURFT)
2、特偵點(diǎn)匹配方法 (包括:暴力法,F(xiàn)LANN,以及隨機(jī)抽樣一致性優(yōu)化RANSAC算法)
注:由于SURF專利問題,所以opencv官方包目前不支持SURF但支持ORB和SIFT,安裝opencv-contrib-python包就可以解決

pip uninstall opencv-python
pip install opencv-contrib-python==3.4.2.17	

一、特征點(diǎn)檢測(cè)
1、ORB算法
大致步驟:
ORB 的特點(diǎn)是速度超快,而且在一定程度上不受噪點(diǎn)和圖像變換的影響,例如旋轉(zhuǎn)和縮放變換等。
原理(步驟:)
(1)對(duì)圖像進(jìn)行多個(gè)版本的下采樣,構(gòu)建圖像金字塔。對(duì)每個(gè)采樣圖像進(jìn)行特征點(diǎn)檢測(cè)。
(2)采用FAST特征點(diǎn)檢測(cè)算法來檢測(cè)特征點(diǎn)。
(3)采用BRIEF描述子來描述每個(gè)特征點(diǎn)。注:描述子可以理解為一個(gè)用來描述特征點(diǎn)的向量,每個(gè)特偵點(diǎn)都有對(duì)應(yīng)的描述子,后面的特征點(diǎn)匹配就是對(duì)每個(gè)特征點(diǎn)之間描述子是否相似的判斷。
關(guān)于FAST特征點(diǎn)檢測(cè)算法:
FAST算法定義:特征點(diǎn)是如果某個(gè)像素點(diǎn)和他周圍領(lǐng)域足夠多的像素點(diǎn)處于不同區(qū)域,那么這個(gè)像素點(diǎn)就是特征點(diǎn)。
對(duì)于灰度圖,及特征點(diǎn)處灰度值與周圍足夠多像素灰度值不同。即設(shè)定一個(gè)閾值若16個(gè)點(diǎn)中有n(取12)個(gè)點(diǎn)的灰度與中心點(diǎn)的灰度差超過閾值則判斷為特征點(diǎn)。
關(guān)于BRIEF描述子
后面再補(bǔ)充—
實(shí)現(xiàn)代碼如下:

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


def ORB(img):
    """
     ORB角點(diǎn)檢測(cè)
     實(shí)例化ORB對(duì)象
    """
    orb = cv2.ORB_create(nfeatures=500)
    """檢測(cè)關(guān)鍵點(diǎn),計(jì)算特征描述符"""
    kp, des = orb.detectAndCompute(img, None)

    # 將關(guān)鍵點(diǎn)繪制在圖像上
    img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)

    cv2.imwrite("1.jpg", img2)

    # 畫圖
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img2[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


img1 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = ORB(img1)

結(jié)果如圖:
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
可以看出ORB可以提取一些關(guān)鍵的特征點(diǎn)

2、SIFT算法
SIFT特征點(diǎn):尺度不變特征變換(Scale-invariant feature transform):大致方法是首先搜索所有尺度下圖像的位置,通過高斯微分函數(shù)來識(shí)別潛在的對(duì)于尺度和旋轉(zhuǎn)不變的興趣點(diǎn),然后在候選位置通過擬合精細(xì)的模型來確定位置和尺度,再基于圖像梯度,分配給關(guān)鍵點(diǎn)一個(gè)或多個(gè)方向,最后在每個(gè)關(guān)鍵點(diǎn)的周圍鄰域,在選定的尺度下測(cè)量圖像局部梯度來描述關(guān)鍵點(diǎn)。(總的來說就是根據(jù)梯度描述關(guān)鍵點(diǎn))
圖像高斯金字塔就考慮了這兩個(gè)方面:① 圖像的遠(yuǎn)近程度;② 圖像的模糊程度(理解為粗細(xì)更好)。前者通過上下采樣來實(shí)現(xiàn),后者通過高斯平滑處理來實(shí)現(xiàn)。
所謂的高斯金字塔是由原始圖像的n層下采樣圖像組成,然后在每個(gè)下采樣的層中利用不同核大小的高斯濾波來生成t張圖像,t張圖像除了第一張和最后一張其余圖像在本張、上張、下張一共26個(gè)點(diǎn)中看是否為極值。
具體原理可參考
代碼如下:

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


def SIFT(img):
    # SIFT算法關(guān)鍵點(diǎn)檢測(cè)
    # 讀取圖像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # SIFT關(guān)鍵點(diǎn)檢測(cè)
    # 1. 實(shí)例化sift
    sift = cv2.xfeatures2d.SIFT_create()

    # 2. 利用sift.detectAndCompute()檢測(cè)關(guān)鍵點(diǎn)并計(jì)算
    kp, des = sift.detectAndCompute(gray, None)
    # gray: 進(jìn)行關(guān)鍵帶你檢測(cè)的圖像,注意是灰度圖像
    # kp: 關(guān)鍵點(diǎn)信息,包括位置,尺度,方向信息
    # des: 關(guān)鍵點(diǎn)描述符,每個(gè)關(guān)鍵點(diǎn)對(duì)應(yīng)128個(gè)梯度信息的特征向量

    # 3. 將關(guān)鍵點(diǎn)檢測(cè)結(jié)果繪制在圖像上
    # cv2.drawKeypoints(image, keypoints, outputimage, color, flags)
    # image: 原始圖像
    # keypoints: 關(guān)鍵點(diǎn)信息,將其繪制在圖像上
    # outputimage: 輸出圖片,可以是原始圖像
    # color: 顏色設(shè)置,通過修改(b, g, r)的值,更改畫筆的顏色,b = 藍(lán)色, g = 綠色, r = 紅色
    # flags: 繪圖功能的標(biāo)識(shí)設(shè)置
    # 1. cv2.DRAW_MATCHES_FLAGS_DEFAULT: 創(chuàng)建輸出圖像矩陣,使用現(xiàn)存的輸出圖像繪制匹配對(duì)象和特征點(diǎn),對(duì)每一個(gè)關(guān)鍵點(diǎn)只繪制中間點(diǎn)
    # 2. cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG: 不創(chuàng)建輸出圖像矩陣,而是在輸出圖像上繪制匹配對(duì)
    # 3. cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS: 對(duì)每一個(gè)特征點(diǎn)繪制帶大小和方向的關(guān)鍵點(diǎn)圖形
    # 4. cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS: 單點(diǎn)的特征點(diǎn)不被繪制
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))
    cv2.imwrite("1.jpg", img)
    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


img1 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SIFT(img1)

結(jié)果如圖:
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
看以看出SIFT算法所求的特征點(diǎn)遠(yuǎn)遠(yuǎn)大于ORB

3、SURF算法
SURF特征點(diǎn):加速穩(wěn)健特征(Speeded Up Robust Features):加速版的SIFT。通過修改濾波器的尺寸和模糊度從而得到不同層級(jí)的影像,別的和SIFT差不多。
Surf是可以說是對(duì)Sift算法的改進(jìn),該算子在保持 SIFT 算子優(yōu)良性能特點(diǎn)的基礎(chǔ)上,同時(shí)解決了 SIFT 計(jì)算復(fù)雜度高、耗時(shí)長(zhǎng)的缺點(diǎn),提升了算法的執(zhí)行效率,為算法在實(shí)時(shí)計(jì)算機(jī)視覺系統(tǒng)中應(yīng)用提供了可能,SIFT在一般的計(jì)算機(jī)對(duì)于日常使用的圖片想做到實(shí)時(shí)基本上是不可能的。
代碼如下:

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


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    cv2.imwrite("1.jpg", img)
    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


img1 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)

結(jié)果如圖
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
可以看到和SIFT差不多密密麻麻的一大片,密集恐懼癥看的都哭了,
可達(dá)鴨,你…綠了。 可達(dá)鴨:我%#@#¥%#¥#¥¥##¥¥%!你不準(zhǔn)丑化我,我可是頂流。
特征點(diǎn)檢測(cè)還有些其他的算法,就先介紹這么多,以后有時(shí)間在總結(jié)。

二、特征點(diǎn)匹配算法
1、暴力求解
讓前一個(gè)圖像的每一個(gè)特征點(diǎn)直接遍歷后一個(gè)圖像的所有特征點(diǎn),找到最小值即為匹配,真的是簡(jiǎn)單粗暴。
代碼:暴力求解+SURF

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


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def ByBFMatcher(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
    (1)暴力法
    :param img1: 匹配圖像1
    :param img2: 匹配圖像2
    :param kp1: 匹配圖像1的特征點(diǎn)
    :param kp2: 匹配圖像2的特征點(diǎn)
    :param des1: 匹配圖像1的描述子
    :param des2: 匹配圖像2的描述子
    :return:
    """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法或SURF
        bf = cv2.BFMatcher_create(cv2.NORM_L1, crossCheck=False)
    else:
        # ORB方法
        bf = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck=False)
    ms = bf.match(des1, des2)
    # ms = sorted(ms, key=lambda x: x.distance)
    img3 = cv2.drawMatches(img1, kp1, img2, kp2, ms, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    cv2.imwrite("1.jpg", img3)
    cv2.imshow("Matches", img3)
    cv2.waitKey(0)
    return ms


img1 = cv2.imread("../asset/image/4.jpg")
img2 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)
kp2, des2 = SURF(img2)
matches = ByBFMatcher(img1, img2, kp1, kp2, des1, des2, "SIFT")

結(jié)果如下
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
可以看得出來,什么也看不出來,一團(tuán)亂麻,而且一看就有很多誤匹配的,不急后文講優(yōu)化的時(shí)候會(huì)解決這一問題?!?br> 可達(dá)鴨:喂喂喂,我人都沒了,你這可惡的人類。
如果想使用ORB就可以把上面的ORB函數(shù)粘貼進(jìn)來,然后修改這幾行,SIFT同理。

kp1, des1 = ORB(img1)
kp2, des2 = ORB(img2)
matches = ByBFMatcher(img1, img2, kp1, kp2, des1, des2, "ORB")

1、FLANN求解
使用快速近似最近鄰搜索算法尋找。
代碼:FLANN + SURF

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


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def ByFlann(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
        (1)FLANN匹配器
        :param img1: 匹配圖像1
        :param img2: 匹配圖像2
        :param kp1: 匹配圖像1的特征點(diǎn)
        :param kp2: 匹配圖像2的特征點(diǎn)
        :param des1: 匹配圖像1的描述子
        :param des2: 匹配圖像2的描述子
        :return:
        """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE,
                            trees=5)
        search_params = dict(check=50)
    else:
        # ORB方法
        FLANN_INDEX_LSH = 6
        index_params = dict(algorithm=FLANN_INDEX_LSH,
                            table_number=6,
                            key_size=12,
                            multi_probe_level=1)
        search_params = dict(check=50)
    # 定義FLANN參數(shù)
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.match(des1, des2)
    img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    cv2.imshow("Matches", img3)
    cv2.imwrite("1.jpg", img3)
    cv2.waitKey(0)
    return matches


img1 = cv2.imread("../asset/image/4.jpg")
img2 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)
kp2, des2 = SURF(img2)
matches = ByFlann(img1, img2, kp1, kp2, des1, des2, "SIFT")

結(jié)果如下
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
依舊看不見鴨鴨。

三、優(yōu)化
由上圖匹配結(jié)果可以看出存在較多誤匹配現(xiàn)象所以必須采取手段來實(shí)現(xiàn)減少誤匹配。
1、RANSAC算法
RANSAC算法,是隨機(jī)抽樣一致。
代碼如下:FLANN + SURF + RANSAC

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


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def ByFlann(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
        (1)FLANN匹配器
        :param img1: 匹配圖像1
        :param img2: 匹配圖像2
        :param kp1: 匹配圖像1的特征點(diǎn)
        :param kp2: 匹配圖像2的特征點(diǎn)
        :param des1: 匹配圖像1的描述子
        :param des2: 匹配圖像2的描述子
        :return:
        """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE,
                            trees=5)
        search_params = dict(check=50)
    else:
        # ORB方法
        FLANN_INDEX_LSH = 6
        index_params = dict(algorithm=FLANN_INDEX_LSH,
                            table_number=6,
                            key_size=12,
                            multi_probe_level=1)
        search_params = dict(check=50)
    # 定義FLANN參數(shù)
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.match(des1, des2)
    # img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    # cv2.imshow("Matches", img3)
    # cv2.imwrite("1.jpg", img3)
    # cv2.waitKey(0)
    return matches

def RANSAC(img1, img2, kp1, kp2, matches):
    MIN_MATCH_COUNT = 10
    # store all the good matches as per Lowe's ratio test.
    matchType = type(matches[0])
    good = []
    print(matchType)
    if isinstance(matches[0], cv2.DMatch):
        # 搜索使用的是match
        good = matches
    else:
        # 搜索使用的是knnMatch
        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)

        # M: 3x3 變換矩陣.
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()

        # h, w = img1.shape
        # 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 = cv2.polylines(img2, [np.int32(dst)], True, 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)

    draw_params1 = dict(matchColor=(0, 255, 0),  # draw matches in green color
                        singlePointColor=None,
                        matchesMask=None,  # draw only inliers
                        flags=2)

    img33 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params1)
    cv2.imwrite("1.jpg", img33)
    cv2.imwrite("2.jpg", img3)
    cv2.imshow("before", img33)
    cv2.imshow("now", img3)
    cv2.waitKey(0)

img1 = cv2.imread("../asset/image/4.jpg")
img2 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)
kp2, des2 = SURF(img2)
matches = ByFlann(img1, img2, kp1, kp2, des1, des2, "SIFT")
RANSAC(img1, img2, kp1, kp2, matches)

結(jié)果:
不使用RANSAC
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
使用RANSAC
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
可以看到匹配的特征點(diǎn)減少了很多,但是還是存在誤匹配的現(xiàn)象,效果不夠理想。

2、使用knnMatch
就是將flann.knnMatch改為flann.match
使用knnMatch得到的matches會(huì)是一個(gè)tuple,里面儲(chǔ)存兩個(gè)match。
match結(jié)構(gòu)為:
queryIdx:當(dāng)前幀特征點(diǎn)序號(hào)
trainIdx:下一幀最為匹配的特征點(diǎn)序號(hào)
distance:距離
一個(gè)match存最接近,一個(gè)match存次最接近。
代碼如下:

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


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def ByFlann(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
        (1)FLANN匹配器
        :param img1: 匹配圖像1
        :param img2: 匹配圖像2
        :param kp1: 匹配圖像1的特征點(diǎn)
        :param kp2: 匹配圖像2的特征點(diǎn)
        :param des1: 匹配圖像1的描述子
        :param des2: 匹配圖像2的描述子
        :return:
        """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE,
                            trees=5)
        search_params = dict(check=50)
    else:
        # ORB方法
        FLANN_INDEX_LSH = 6
        index_params = dict(algorithm=FLANN_INDEX_LSH,
                            table_number=6,
                            key_size=12,
                            multi_probe_level=1)
        search_params = dict(check=50)
    # 定義FLANN參數(shù)
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)
    # img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    # cv2.imshow("Matches", img3)
    # cv2.imwrite("1.jpg", img3)
    # cv2.waitKey(0)
    return matches

def RANSAC(img1, img2, kp1, kp2, matches):
    MIN_MATCH_COUNT = 10
    # store all the good matches as per Lowe's ratio test.
    matchType = type(matches[0])
    good = []
    print(matchType)
    if isinstance(matches[0], cv2.DMatch):
        # 搜索使用的是match
        good = matches
    else:
        # 搜索使用的是knnMatch
        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)

        # M: 3x3 變換矩陣.
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()

        # h, w = img1.shape
        # 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 = cv2.polylines(img2, [np.int32(dst)], True, 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)

    draw_params1 = dict(matchColor=(0, 255, 0),  # draw matches in green color
                        singlePointColor=None,
                        matchesMask=None,  # draw only inliers
                        flags=2)

    img33 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params1)
    cv2.imwrite("1.jpg", img33)
    cv2.imwrite("2.jpg", img3)
    cv2.imshow("before", img33)
    cv2.imshow("now", img3)
    cv2.waitKey(0)

img1 = cv2.imread("../asset/image/4.jpg")
img2 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)
kp2, des2 = SURF(img2)
matches = ByFlann(img1, img2, kp1, kp2, des1, des2, "SIFT")
RANSAC(img1, img2, kp1, kp2, matches)

結(jié)果:
使用FLANN + SURF(match) + RANSAC
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
使用FLANN + SURF(knnMatch) + 不使用RANSAC
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
使用FLANN + SURF(knnMatch) + RANSAC
特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]
由上面可以看出,就算不使用RANSAC,單單就FLANN + SURF(knnMatch)的效果就已經(jīng)比FLANN + SURF(match) + RANSAC好很多,當(dāng)然效果最好的還是FLANN + SURF(knnMatch) + RANSAC。
可達(dá)鴨:我就一直綠唄。

四、總結(jié)
1、總的來說就時(shí)效性應(yīng)該是ORB>SURF>SIFT, FLANN>暴力求解。具體對(duì)比可以參考這篇文章
2、從效果來看FLANN + SURF/SURF(knnMatch) + RANSAC是最好的。ORB好像不支持knnMatch,我后面再測(cè)測(cè)看。
3、整個(gè)程序源碼放在最后,大家可以依據(jù)自己的需要組合成不的方式。

程序代碼:
要想使用knnMatch,把SURT,SIFT函數(shù)里面的

matches = flann.match(des1, des2)

改為文章來源地址http://www.zghlxwxcb.cn/news/detail-461677.html

matches = flann.knnMatch(des1, des2, k=2)
"""
圖像特征點(diǎn)的檢測(cè)與匹配
主要涉及:
1、ORB
2、SIFT
3、SURF
"""

"""
一、圖像特征點(diǎn)的檢測(cè)
"""
import numpy as np
import cv2
from matplotlib import pyplot as plt


def ORB(img):
    """
     ORB角點(diǎn)檢測(cè)
     實(shí)例化ORB對(duì)象
    """
    orb = cv2.ORB_create(nfeatures=500)
    """檢測(cè)關(guān)鍵點(diǎn),計(jì)算特征描述符"""
    kp, des = orb.detectAndCompute(img, None)

    # 將關(guān)鍵點(diǎn)繪制在圖像上
    img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)

    # 畫圖
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img2[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def SIFT(img):
    # SIFT算法關(guān)鍵點(diǎn)檢測(cè)
    # 讀取圖像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # SIFT關(guān)鍵點(diǎn)檢測(cè)
    # 1. 實(shí)例化sift
    sift = cv2.xfeatures2d.SIFT_create()

    # 2. 利用sift.detectAndCompute()檢測(cè)關(guān)鍵點(diǎn)并計(jì)算
    kp, des = sift.detectAndCompute(gray, None)
    # gray: 進(jìn)行關(guān)鍵帶你檢測(cè)的圖像,注意是灰度圖像
    # kp: 關(guān)鍵點(diǎn)信息,包括位置,尺度,方向信息
    # des: 關(guān)鍵點(diǎn)描述符,每個(gè)關(guān)鍵點(diǎn)對(duì)應(yīng)128個(gè)梯度信息的特征向量

    # 3. 將關(guān)鍵點(diǎn)檢測(cè)結(jié)果繪制在圖像上
    # cv2.drawKeypoints(image, keypoints, outputimage, color, flags)
    # image: 原始圖像
    # keypoints: 關(guān)鍵點(diǎn)信息,將其繪制在圖像上
    # outputimage: 輸出圖片,可以是原始圖像
    # color: 顏色設(shè)置,通過修改(b, g, r)的值,更改畫筆的顏色,b = 藍(lán)色, g = 綠色, r = 紅色
    # flags: 繪圖功能的標(biāo)識(shí)設(shè)置
    # 1. cv2.DRAW_MATCHES_FLAGS_DEFAULT: 創(chuàng)建輸出圖像矩陣,使用現(xiàn)存的輸出圖像繪制匹配對(duì)象和特征點(diǎn),對(duì)每一個(gè)關(guān)鍵點(diǎn)只繪制中間點(diǎn)
    # 2. cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG: 不創(chuàng)建輸出圖像矩陣,而是在輸出圖像上繪制匹配對(duì)
    # 3. cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS: 對(duì)每一個(gè)特征點(diǎn)繪制帶大小和方向的關(guān)鍵點(diǎn)圖形
    # 4. cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS: 單點(diǎn)的特征點(diǎn)不被繪制
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


def SURF(img):
    surf = cv2.xfeatures2d.SURF_create()
    kp, des = surf.detectAndCompute(img, None)
    cv2.drawKeypoints(img, kp, img, (0, 255, 0))

    # 圖像顯示
    plt.figure(figsize=(10, 8), dpi=100)
    plt.imshow(img[:, :, ::-1])
    plt.xticks([]), plt.yticks([])
    plt.show()
    return kp, des


"""
2.圖像特征點(diǎn)匹配方法
(1)暴力法
(2)FLANN匹配器
"""


def ByBFMatcher(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
    (1)暴力法
    :param img1: 匹配圖像1
    :param img2: 匹配圖像2
    :param kp1: 匹配圖像1的特征點(diǎn)
    :param kp2: 匹配圖像2的特征點(diǎn)
    :param des1: 匹配圖像1的描述子
    :param des2: 匹配圖像2的描述子
    :return:
    """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法
        bf = cv2.BFMatcher_create(cv2.NORM_L1, crossCheck=False)
    else:
        # ORB方法
        bf = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck=False)
    ms = bf.knnMatch(des1, des2, k=2)
    # ms = sorted(ms, key=lambda x: x.distance)
    # img3 = cv2.drawMatches(img1, kp1, img2, kp2, ms, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    # cv2.imshow("Matches", img3)
    # cv2.waitKey(0)
    return ms


def ByFlann(img1, img2, kp1, kp2, des1, des2, flag="ORB"):
    """
        (1)FLANN匹配器
        :param img1: 匹配圖像1
        :param img2: 匹配圖像2
        :param kp1: 匹配圖像1的特征點(diǎn)
        :param kp2: 匹配圖像2的特征點(diǎn)
        :param des1: 匹配圖像1的描述子
        :param des2: 匹配圖像2的描述子
        :return:
        """
    if (flag == "SIFT" or flag == "sift"):
        # SIFT方法
        FLANN_INDEX_KDTREE = 1
        index_params = dict(algorithm=FLANN_INDEX_KDTREE,
                            trees=5)
        search_params = dict(check=50)
    else:
        # ORB方法
        FLANN_INDEX_LSH = 6
        index_params = dict(algorithm=FLANN_INDEX_LSH,
                            table_number=6,
                            key_size=12,
                            multi_probe_level=1)
        search_params = dict(check=50)
    # 定義FLANN參數(shù)
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)
    return matches


"""
優(yōu)化匹配結(jié)果
RANSAC算法是RANdom SAmple Consensus的縮寫,意為隨機(jī)抽樣一致
"""


def RANSAC(img1, img2, kp1, kp2, matches):
    MIN_MATCH_COUNT = 10
    # store all the good matches as per Lowe's ratio test.
    matchType = type(matches[0])
    good = []
    print(matchType)
    if isinstance(matches[0], cv2.DMatch):
        # 搜索使用的是match
        good = matches
    else:
        # 搜索使用的是knnMatch
        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)

        # M: 3x3 變換矩陣.
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()

        # h, w = img1.shape
        # 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 = cv2.polylines(img2, [np.int32(dst)], True, 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)

    draw_params1 = dict(matchColor=(0, 255, 0),  # draw matches in green color
                        singlePointColor=None,
                        matchesMask=None,  # draw only inliers
                        flags=2)

    img33 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params1)

    cv2.imshow("before", img33)
    cv2.imshow("now", img3)
    cv2.waitKey(0)


img1 = cv2.imread("../asset/image/4.jpg")
img2 = cv2.imread("../asset/image/5.jpg")
kp1, des1 = SURF(img1)
kp2, des2 = SURF(img2)
matches = ByFlann(img1, img2, kp1, kp2, des1, des2, "SIFT")
RANSAC(img1, img2, kp1, kp2, matches)

到了這里,關(guān)于特征點(diǎn)的檢測(cè)與匹配(ORB,SIFT,SURFT比較)[opencv-python]的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包