1. 程式人生 > >計算機視覺-影象描述符(圖片分類)

計算機視覺-影象描述符(圖片分類)

標籤: 關鍵點檢測、提取區域性特徵描述符

1、影象描述符、特徵描述符和特徵向量的定義

特徵向量:用於表示和量化影象的數字列表,簡單理解成將圖片轉化為一個數字列表表示。特徵向量中用來描述圖片的各種屬性的向量稱為特徵向量。

影象描述符:理解成一種演算法和方法,控制整個影象如何轉變為特徵向量。量化是的影象形狀,顏色,紋理,或三者的任何組合。輸入1個影象時,影象描述符將返回1個特徵向量。主要用於影象分類。缺乏區分影象中不同物件的能力。

特徵描述符:是一種演算法和方法,控制影象部分割槽域,對部分割槽域返回多個特徵向量。輸入1個影象,返回多個特徵向量(主要用來處理影象的區域性)。主要用於影象匹配(視覺檢測),匹配影象中的物品。

2、色彩通道統計

執行命令:python color_channel_stats.py

原理:通過統計影象中的每個色彩通道(及RGB色彩通道),憑據通道值和標準差等方法,量化和表示影象的顏色分佈,從而對影象進行分類。(主要運用顏色差異名義,不同場景圖片分類)

複製程式碼

from scipy.spatial import distance as dist
from imutils import paths
import numpy as np
import cv2
 
imagePaths = sorted(list(paths.list_images("dinos")))
index = {}
 
for imagePath in imagePaths:
    image = cv2.imread(imagePath)
    filename = imagePath[imagePath.rfind("/") + 1:]

    (means, stds) = cv2.meanStdDev(image)#計算影象中每個色彩通道的平均值和標準偏差
    features = np.concatenate([means, stds]).flatten()#將每個色彩通道的平均值和標準偏差連線在一起,形成我們的特徵向量
    index[filename] = features
query = cv2.imread(imagePaths[0])
cv2.imshow("Query (trex_01.png)", query)
keys = sorted(index.keys())
 
for (i, k) in enumerate(keys):
    if k == "trex_01.png":
        continue

    image = cv2.imread(imagePaths[i])
    d = dist.euclidean(index["trex_01.png"], index[k])#計算目標影象特徵向量與我們資料集中的特徵向量之間的歐幾里德距離。d越小,顏色通道越相似,圖片越相似。
 
    cv2.putText(image, "%.2f" % (d), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 2)
    cv2.imshow(k, image)

cv2.waitKey(0)

複製程式碼

 3、彩色直方圖

原理:通過顏色的分佈,運用機器學習中的K均值聚類運用於聚類顏色直方圖。無參考值進行影象分類。(關鍵是需要對顏色直方圖理解)

檔案結構:

|--- pyimagesearch

|    |--- __init__.py

|    |--- descriptors

|    |    |---- __init__.py

|    |    |--- labhistogram.py

|--- cluster_histograms.py

疑問:1、imutils.is_cv2() 意義?

labhistogram.py

複製程式碼

import cv2
import imutils
 
class LabHistogram:
    def __init__(self, bins):
        self.bins = bins
 
    def describe(self, image, mask=None):
        lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
        hist = cv2.calcHist([lab], [0, 1, 2], mask, self.bins,
            [0, 256, 0, 256, 0, 256])#獲取3D直方圖
        #將圖片大小標準化,忽略圖片大小對直方圖的影響
        if imutils.is_cv2():
            hist = cv2.normalize(hist).flatten()
 
        else:
            hist = cv2.normalize(hist,hist).flatten()
 
        return hist    

複製程式碼

cluster_histograms.py

複製程式碼

from pyimagesearch.descriptors.labhistogram import LabHistogram
from sklearn.cluster import KMeans
from imutils import paths
import numpy as np
import argparse
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
    help="path to the input dataset directory")
ap.add_argument("-k", "--clusters", type=int, default=2,
    help="# of clusters to generate")#預設設定k值為2,及將圖片分為倆類。
args = vars(ap.parse_args())

desc = LabHistogram([8, 8, 8])
data = []
 
imagePaths = list(paths.list_images(args["dataset"]))
imagePaths = np.array(sorted(imagePaths))
 
for imagePath in imagePaths:
    image = cv2.imread(imagePath)
    hist = desc.describe(image)
    data.append(hist)#描述符加入到資料集中
 
#對描述符進行聚類
clt = KMeans(n_clusters=args["clusters"])
labels = clt.fit_predict(data)

for label in np.unique(labels):
    #獲取每個叢集的唯一ID,進行分類
    labelPaths = imagePaths[np.where(labels == label)]
   #將同一叢集的圖片輸出顯示
    for (i, path) in enumerate(labelPaths):
        image = cv2.imread(path)
        cv2.imshow("Cluster {}, Image #{}".format(label + 1, i + 1), image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

複製程式碼

 4、胡默斯

作用:用於物品形狀檢測,處理二值圖片,提取圖片中物體的形狀。

執行命令:python extract_hu_moments.py

extract_hu_moments.py

複製程式碼

import cv2
import imutils
 
image = cv2.imread("planes.png")
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
moments = cv2.HuMoments(cv2.moments(image)).flatten()
print("ORIGINAL MOMENTS: {}".format(moments))
cv2.imshow("Image", image)
cv2.waitKey(0)

#找到圖片中每個物件的行輪廓
cnts = cv2.findContours(image.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
 
for (i, c) in enumerate(cnts):
    (x, y, w, h) = cv2.boundingRect(c)
    roi = image[y:y + h, x:x + w]
    #提取每個形狀的hu_monebts值
    moments = cv2.HuMoments(cv2.moments(roi)).flatten()

    print("MOMENTS FOR PLANE #{}: {}".format(i + 1, moments))
    cv2.imshow("ROI #{}".format(i + 1), roi)
    cv2.waitKey(0)

複製程式碼

作用:隨機生成資料集

執行命令:python generate_images.py --output output

genetate_images.py

複製程式碼

import numpy as np
import argparse
import uuid
import cv2
 
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", required=True,
    help="Path to the output directory")
ap.add_argument("-n", "--num-images", type=int, default=500,
    help="# of disctrator images to generate")
args = vars(ap.parse_args())
 
for i in range(0, args["num_images"]):
    image = np.zeros((500, 500, 3), dtype="uint8")
    (x, y) = np.random.uniform(low=105, high=405, size=(2,)).astype("int0")
    r = np.random.uniform(low=25, high=100, size=(1,)).astype("int0")[0]

    color = np.random.uniform(low=0, high=255, size=(3,)).astype("int0")
    color = tuple(map(int, color))
    cv2.circle(image, (x, y), r, color, -1)
    cv2.imwrite("{}/{}.jpg".format(args["output"], uuid.uuid4()), image)
image = np.zeros((500, 500, 3), dtype="uint8")
topLeft = np.random.uniform(low=25, high=225, size=(2,)).astype("int0")
botRight = np.random.uniform(low=250, high=400, size=(2,)).astype("int0")
 
color = np.random.uniform(low=0, high=255, size=(3,)).astype("int0")
color = tuple(map(int, color))
cv2.rectangle(image, tuple(topLeft), tuple(botRight), color, -1)
cv2.imwrite("{}/{}.jpg".format(args["output"], uuid.uuid4()), image)

複製程式碼

作用:從資料集中,找出異常形狀

執行命令:python find_rectangle.py --dataset output

find_rectangle.py

複製程式碼

from sklearn.metrics.pairwise import pairwise_distances
import numpy as np
import argparse
import glob
import cv2
import imutils
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True, help="Path to the dataset directory")
args = vars(ap.parse_args())
 
imagePaths = sorted(glob.glob(args["dataset"] + "/*.jpg"))
data = []
 
for imagePath in imagePaths:
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 5, 255, cv2.THRESH_BINARY)[1]
 
    cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    c = max(cnts, key=cv2.contourArea)
    (x, y, w, h) = cv2.boundingRect(c)
    roi = cv2.resize(thresh[y:y + h, x:x + w], (50, 50))#忽略圖片大小的影響
    moments = cv2.HuMoments(cv2.moments(roi)).flatten()
    data.append(moments)
D = pairwise_distances(data).sum(axis=1)
i = np.argmax(D) #獲取距離最大的圖形,圓形距離很小,矩形距離較大
 
image = cv2.imread(imagePaths[i])
print("Found square: {}".format(imagePaths[i]))
cv2.imshow("Outlier", image)
cv2.waitKey(0)

複製程式碼

 5、Zernike時刻

運用Zernike矩陣量化影象中的形狀。在圖片中尋找某個特定的形狀

複製程式碼

from scipy.spatial import distance as dist
import numpy as np
import mahotas
import cv2
import imutils

def describe_shapes(image):
    shapeFeatures = []
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (13, 13), 0)
    cv2.imshow("2", blurred)
    thresh = cv2.threshold(blurred, 120, 255, cv2.THRESH_BINARY)[1]
    thresh  = cv2.dilate(thresh, None, iterations = 4)
    thres = cv2.erode(thresh, None, iterations = 2)
    cv2.imshow("1", thres)
    cv2.waitKey(0)
    
    cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]

    for c in cnts:
        mask = np.zeros(image.shape[:2], dtype = "uint8")
        cv2.drawContours(mask, [c], -1, 255, -1)
        (x, y, w, h) = cv2.boundingRect(c)
        roi = mask[y:y + h, x:x + w]
        cv2.imshow("roi", roi)
        cv2.waitKey(0)
        features = mahotas.features.zernike_moments(roi, cv2.minEnclosingCircle(c)[1], degree = 8)
        shapeFeatures.append(features)

    return(cnts, shapeFeatures)

refImage = cv2.imread("2.jpg")
(_, gameFeatures)  = describe_shapes(refImage)
shapesImage = cv2.imread("1.jpg")
(cnts, shapeFeatures) = describe_shapes(shapesImage)
D = dist.cdist(gameFeatures, shapeFeatures)
i = np.argmin(D) #獲取最小距離的下標

for (j, c) in enumerate(cnts):
    if i != j:
        box = cv2.minAreaRect(c)
        box = np.int0(cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box))
        cv2.drawContours(shapesImage, [box],  - 1, (0, 0, 255), 2)

box = cv2.minAreaRect(cnts[i])
box = np.int0(cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box))
cv2.drawContours(shapesImage, [box],  - 1, (0, 255, 0), 2)
(x, y, w, h) = cv2.boundingRect(cnts[i])
cv2.putText(shapesImage, "FOUND!", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 3)
cv2.imshow("Input Image", refImage)
cv2.imshow("Detected Shapes", shapesImage)
cv2.waitKey(0)

複製程式碼

 6、Haralick紋理功能

依據資料學習,分析紋理,再將資料圖片依據紋理分類:

複製程式碼

from sklearn.svm import LinearSVC
import argparse
import glob
import mahotas
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--training", required = True, help = "Path to the dataset of textures")
ap.add_argument("-t", "--test", required = True,help = "Path to the test images" )
args = vars(ap.parse_args())

print("[INFO] extracting features...")
data = []
labels = []
for imagePath in glob.glob(args["training"] + "/*.jpg"):
    image = cv2.imread(imagePath)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    texture = imagePath[imagePath.rfind("/") + 1:].split("_")[0]
    features = mahotas.features.haralick(image).mean(axis = 0)
    data.append(features)
    labels.append(texture)

print("[INFO] training model...")
model = LinearSVC(C = 10.0, random_state = 42)
model.fit(data, labels)
print("[INFO] classifying...")

for imagePath in glob.glob(args["test"] + "/*.jpg"):
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    features = mahotas.features.haralick(gray).mean(axis = 0)
    print features
    pred  = model.predict(features.reshape(1,  - 1))[0]
    print pred
    cv2.putText(image, pred, (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 3)
    cv2.imshow("Image", image)
    cv2.waitKey(0)

複製程式碼

7、本地二進位制模式

原理:LBP 在本地處理畫素  而不是使用灰度共生矩陣。通過量化小區域特徵,分析圖片的特徵向量,再對圖片進行分類。

注意點:記住半徑r  和點數p的影響也很重要。積分越多p  你品嚐,更多的模式,你可以編碼,但在同一時間,你增加你的計算成本。另一方面,如果增加半徑大小r,  則可以在影象中捕捉較大的紋理細節。但是,如果增加r  而不增加p  ,那麼您將失去LBP描述符的區域性區分能力。

例:時尚索引

複製程式碼

檔案結構:
|--- pyimagesearch
|    |--- __init__.py
|    |--- descriptors
|    |    |---- __init__.py
|    |    |--- localbinarypatterns.py
|--- search_shirts.py

複製程式碼

作用:建立二進位制描述符。

localbinarypatterns.py

複製程式碼

from skimage import feature
import numpy as np

class LocalBinaryPatterns:
    def __init__(self, numPoints, radius): #圍繞中心畫素的圖案半徑,半徑外圍點數,決定計算量

        self.numPoints = numPoints
        self.radius = radius

    def describe(self, image, eps=1e-7):
        lbp = feature.local_binary_pattern(image, self.numPoints, self.radius, method="uniform")
        (hist, _) = np.histogram(lbp.ravel(), bins=range(0, self.numPoints + 3),
            range=(0, self.numPoints + 2))

        # normalize the histogram
        hist = hist.astype("float")
        hist /= (hist.sum() + eps)

        # return the histogram of Local Binary Patterns
        return hist

複製程式碼

作用:測試二進位制描述符的紋理特徵效果

執行命令:python search_shirts.py --dataset shirts --query queries/query_01.jpg

search_shirts.py:

複製程式碼

from __future__ import print_function
from pyimagesearch import LocalBinaryPatterns
from imutils import paths
import numpy as np
import argparse
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True, help="path to the dataset of shirt images")
ap.add_argument("-q", "--query", required=True, help="path to the query image")
args = vars(ap.parse_args())

desc = LocalBinaryPatterns(24, 8)
index = {}

for imagePath in paths.list_images(args["dataset"]):
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    hist = desc.describe(gray)

    filename = imagePath[imagePath.rfind("/") + 1:]
    index[filename] = hist

query = cv2.imread(args["query"])
queryFeatures = desc.describe(cv2.cvtColor(query, cv2.COLOR_BGR2GRAY))

cv2.imshow("Query", query)
results = {}

for (k, features) in index.items():

    d = 0.5 * np.sum(((features - queryFeatures) ** 2) / (features + queryFeatures + 1e-10))
    results[k] = d


results = sorted([(v, k) for (k, v) in results.items()])[:3]#選取前較小距離(相似性)高的,前3個結果

for (i, (score, filename)) in enumerate(results):#將前3個結果顯示出來
    print("#%d. %s: %.4f" % (i + 1, filename, score))
    image = cv2.imread(args["dataset"] + "/" + filename)
    cv2.imshow("Result #{}".format(i + 1), image)
    cv2.waitKey(0)

複製程式碼

 8、定向梯度直方圖

原理:運用HOG描述符,他主要用於描述影象中物體的結構形狀和外觀,使其成為物體分類的優秀描述符。但是,由於HOG捕獲區域性強度梯度和邊緣方向,因此它也會產生良好的紋理描述符

知識點:pixels_per_cell中的畫素  越多,我們的表示越粗糙。類似地,pixels_per_cell的較小值將產生更細粒度(輪廓更明顯)

疑問:1、from sklearn.neighbors import KNeighborsClassifier

解釋:http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html

執行命令:python recognize_car_logos.py --training car_logos --test test_images

recognize_car_logs.py

複製程式碼

from sklearn.neighbors import KNeighborsClassifier
from skimage import exposure
from skimage import feature
from imutils import paths
import argparse
import imutils
import cv2
 
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--training", required=True, help="Path to the logos training dataset")
ap.add_argument("-t", "--test", required=True, help="Path to the test dataset")
args = vars(ap.parse_args())
 
print "[INFO] extracting features..."
data = []
labels = []

for imagePath in paths.list_images(args["training"]):  #提取每個標誌的hog特徵向量
    make = imagePath.split("/")[-2]
 
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edged = imutils.auto_canny(gray)
 
    cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]
    c = max(cnts, key=cv2.contourArea)
 
    (x, y, w, h) = cv2.boundingRect(c)
    logo = gray[y:y + h, x:x + w]
    logo = cv2.resize(logo, (200, 100))
 
    H = feature.hog(logo, orientations=9, pixels_per_cell=(10, 10),
        cells_per_block=(2, 2), transform_sqrt=True, block_norm="L1")
 
    data.append(H)
    labels.append(make)

print("[INFO] training classifier...") 
model = KNeighborsClassifier(n_neighbors=1)  #對特徵資料進行K值分類
model.fit(data, labels)
print("[INFO] evaluating...")

for (i, imagePath) in enumerate(paths.list_images(args["test"])):
    image = cv2.imread(imagePath)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    logo = cv2.resize(gray, (200, 100))

    (H, hogImage) = feature.hog(logo, orientations=9, pixels_per_cell=(10, 10),
        cells_per_block=(2, 2), transform_sqrt=True, block_norm="L1", visualise=True)
    pred = model.predict(H.reshape(1, -1))[0]
 
    hogImage = exposure.rescale_intensity(hogImage, out_range=(0, 255))
    hogImage = hogImage.astype("uint8")
    cv2.imshow("HOG Image #{}".format(i + 1), hogImage)
 
    cv2.putText(image, pred.title(), (10, 35), cv2.FONT_HERSHEY_SIMPLEX, 1.0,
        (0, 255, 0), 3)
    cv2.imshow("Test Image #{}".format(i + 1), image)
    cv2.waitKey(0)

複製程式碼

9、關鍵點檢測

9.1、FAST關鍵點檢測

原理:必須有至少Ñ沿著連續畫素圓形周邊具有半徑- R所有或者亮或更暗比中心畫素由閾值t

疑問:是否可以修改引數,半徑-R和N值?

執行命令:python fast_keypoint.py

fast_keypoint.py

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("FAST")
    kps = detector.detect(gray)
 
else:
    detector = cv2.FastFeatureDetector_create()
    kps = detector.detect(gray, None)
 
print("# of keypoints: {}".format(len(kps)))
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.2Harris關鍵點檢測

原理:將分別在xy方向上對該區域中的梯度值求和:

\ sum(G_ {x})^ {2} 和 \ sum(G_ {y})^ {2}

如果這兩個值都足夠“大”,那麼我們可以將該區域定義為角落。該過程針對輸入影象中的每個畫素完成。這種方法是有效的,因為紅色圓圈內的區域會有大量的水平和垂直梯度 - 當發生這種情況時,我們知道我們找到了一個角落.

疑問:1、harris函式的引數的作用:

  • img - 資料型別為 float32 的輸入影象。
  • blockSize - 角點檢測中要考慮的領域大小。
  • ksize - Sobel 求導中使用的視窗大小
  • k - Harris 角點檢測方程中的自由引數,取值引數為 [0,04,0.06].

2、harris什麼時候被呼叫?

harris_keypoint.py

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
def harris(gray, blockSize=2, apetureSize=3, k=0.1, T=0.02):
    gray = np.float32(gray)
    H = cv2.cornerHarris(gray, blockSize, apetureSize, k)
 
    kps = np.argwhere(H > T * H.max())
    kps = [cv2.KeyPoint(pt[1], pt[0], 3) for pt in kps]
 
    return kps

image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 

if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("HARRIS")
    kps = detector.detect(gray)
 

else:
    kps = harris(gray)
 
print("# of keypoints: {}".format(len(kps)))

for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
# show the image
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.3、GFTT關鍵點檢測

原理:提出了以下R的計算來表明一個地區是否是一個角落:R = min(\ lambda_ {1},\ lambda_ {2})在這種情況下,我們只是取特徵值分解分量的最小值。如果這個值R大於我們的閾值T  (即R> = T),那麼我們可以將該區域標記為拐角。(在harris基礎上改進)

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
def gftt(gray, maxCorners=0, qualityLevel=0.01, minDistance=1,
    mask=None, blockSize=3, useHarrisDetector=False, k=0.04):

    kps = cv2.goodFeaturesToTrack(gray, maxCorners, qualityLevel,
        minDistance, mask=mask, blockSize=blockSize,
        useHarrisDetector=useHarrisDetector, k=k)
 
    return [cv2.KeyPoint(pt[0][0], pt[0][1], 3) for pt in kps]
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("GFTT")
    kps = detector.detect(gray)

else:
    kps = gftt(gray)
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
print("# of keypoints: {}".format(len(kps)))
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

 9.4、DoG關鍵點檢測器

通過對影象縮放變化,尋找角點,獲取的角點繪製出來的圓有大小區別。

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("SIFT")
    kps = detector.detect(gray)
 
else:
    detector = cv2.xfeatures2d.SIFT_create()
    (kps, _) = detector.detectAndCompute(gray, None)
 
print("# of keypoints: {}".format(len(kps)))

for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.5、Fast_Hessian關鍵點檢測

作用:類似於高斯差分,快速Hessian關鍵點檢測器用於定點陣圖像中可重複的“斑點”狀區域。這些區域可能是邊緣,角落或兩者

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils

image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("SURF")
    kps = detector.detect(gray)
 
else:
    detector = cv2.xfeatures2d.SURF_create()
    (kps, _) = detector.detectAndCompute(gray, None)
 
print("# of keypoints: {}".format(len(kps)))

for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.6、STAR關鍵點檢測

運用情況:用於檢測影象中的“斑點”狀區域

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("STAR")
    kps = detector.detect(gray)
 
else:
    detector = cv2.xfeatures2d.StarDetector_create()
    kps = detector.detect(gray)
 
print("# of keypoints: {}".format(len(kps)))
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.7、MSER關鍵點檢測

作用:MSER檢測器用於檢測影象中的“斑點”狀結構。假設這些區域很小,具有相對相同的畫素強度,並且被對比畫素包圍

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
# detect MSER keypoints in the image
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("MSER")
    kps = detector.detect(gray)
 
else:
    detector = cv2.MSER_create()
    kps = detector.detect(gray, None)
 
print("# of keypoints: {}".format(len(kps)))
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.8、密集關鍵點檢測

作用:濃密檢測器 將影象中的每個k畫素標記為關鍵點

複製程式碼

from __future__ import print_function
import numpy as np
import argparse
import cv2
import imutils
 
def dense(image, step, radius):
    kps = []
 
    for x in range(0, image.shape[1], step):
        for y in range(0, image.shape[0], step):
            kps.append(cv2.KeyPoint(x, y, radius * 2))
 
    return kps
 
ap = argparse.ArgumentParser()
ap.add_argument("-s", "--step", type=int, default=28, help="step (in pixels) of the dense detector")
args = vars(ap.parse_args())
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
kps = []
radii = (4, 8, 12)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("Dense")
    detector.setInt("initXyStep", args["step"])
    rawKps = detector.detect(gray)
 
else:
    rawKps = dense(gray, args["step"], 1)
 
for rawKp in rawKps:
    for r in radii:
        kp = cv2.KeyPoint(x=rawKp.pt[0], y=rawKp.pt[1], _size=r * 2)
        kps.append(kp)
 
print("# dense keypoints: {}".format(len(rawKps)))
print("# dense + multi radii keypoints: {}".format(len(kps)))
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 1)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.9、BRISK關鍵點檢測器

運用情況:多尺度版本

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("BRISK")
    kps = detector.detect(gray)
 
else:
    detector = cv2.BRISK_create()
    kps = detector.detect(gray, None)
 
print("# of keypoints: {}".format(len(kps)))

for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

9.10、ORB關鍵點檢測器的運用

作用:ORB用於檢測影象中的角點

複製程式碼

from __future__ import print_function
import numpy as np
import cv2
import imutils
 
image = cv2.imread("next.png")
orig = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("ORB")
    kps = detector.detect(gray)
 
else:
    detector = cv2.ORB_create()
    kps = detector.detect(gray, None)
 
print("# of keypoints: {}".format(len(kps)))
 
for kp in kps:
    r = int(0.5 * kp.size)
    (x, y) = np.int0(kp.pt)
    cv2.circle(image, (x, y), r, (0, 255, 255), 2)
 
cv2.imshow("Images", np.hstack([orig, image]))
cv2.waitKey(0)

複製程式碼

 10、區域性不變描述符

10.1、SIFT

作用:檢測關鍵點並從影象中提取SIFT特徵向量

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("SIFT")
    extractor = cv2.DescriptorExtractor_create("SIFT")
 

    kps = detector.detect(gray)
    (kps, descs) = extractor.compute(gray, kps)
 
else:

    detector = cv2.xfeatures2d.SIFT_create()
 
    (kps, descs) = detector.detectAndCompute(gray, None)
 

print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

10.2、RootSIFT

作用:定義RootSIFT檢測器,獲取關鍵點特徵

rootsift.py

複製程式碼

import numpy as np
import cv2
import imutils
 
class RootSIFT:
    def __init__(self):
        if imutils.is_cv2():
            self.extractor = cv2.DescriptorExtractor_create("SIFT")
 
        else:
            self.extractor = cv2.xfeatures2d.SIFT_create()
 
    def compute(self, image, kps, eps=1e-7):
        if imutils.is_cv2:
            (kps, descs) = self.extractor.compute(image, kps)
 
        else:
            (kps, descs) = self.extractor.detectAndCompute(image, None)
 
        if len(kps) == 0:
            return ([], None)

        descs /= (descs.sum(axis=1, keepdims=True) + eps)
        descs = np.sqrt(descs)

        return (kps, descs)

複製程式碼

作用:從影象中提取RootSIFT描述符

extract_rpptsift.py

複製程式碼

from __future__ import print_function
from pyimagesearch.descriptors import RootSIFT
import argparse
import cv2
import imutils
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("SIFT")
    extractor = RootSIFT()
 
    kps = detector.detect(gray)
 
else:
    detector = cv2.xfeatures2d.SIFT_create()
    extractor = RootSIFT()
 
    (kps, _) = detector.detectAndCompute(gray, None)

(kps, descs) = extractor.compute(gray, kps)
 
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

10.3、SURF

作用:SURF的第一步是選擇圍繞關鍵點的影象的矩形區域。在關鍵點檢測階段確定區域的確切大小

extract_surf.py

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("SURF")
    extractor = cv2.DescriptorExtractor_create("SURF")
 
    kps = detector.detect(gray)
    (kps, descs) = extractor.compute(gray, kps)
 
else:
    detector = cv2.xfeatures2d.SURF_create()
 
    (kps, descs) = detector.detectAndCompute(gray, None)
 
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

 10.4、實值特徵匹配

知識點:提取關鍵點的影象座標,例:ksp[0].pt

執行命令:1、python draw_matches.py --first jp_01.png --second jp_02.png --detector SURF --extractor SIFT

2、python draw_matches.py --first jp_01.png --second jp_02.png --detector SURF --extractor RootSIFT

3、python draw_matches.py --first jp_01.png --second jp_02.png --detector SURF --extractor SURF

複製程式碼

#coding=utf-8
from __future__ import print_function
import numpy as np
import argparse
import cv2
from imutils.feature.factories import FeatureDetector_create, DescriptorExtractor_create, DescriptorMatcher_create
ap = argparse.ArgumentParser()
ap.add_argument("-f", "--first", required = True, help = "Path to first image") #提取關鍵點和特徵向量的第一幅影象的路經
ap.add_argument("-s", "--second", required = True, help = "Path to second image")#提取關鍵點和特徵向量的第二幅影象的路經
ap.add_argument("-d", "--detector", type = str, default="SURF", help = "Kepyoint detector to use.Options ['BRISK', 'DENSE', 'DOG', 'SIFT', 'FAST', 'FASTHESSIAN', 'SURF', 'GFTT','HARRIS',  'MSER',  'ORB',  'STAR']")#用於在倆個影象執行關鍵點檢測的關鍵點的檢測器
ap.add_argument("-e", "--extractor", type = str, default = "SIFT", help = "Keypoint detector to use.Options['RootSIFT', 'SIFT', 'SURF']")#關鍵點區域提取區域性不變描述符
ap.add_argument("-m", "--matcher", type = str, default ="BruteForce", help = "Feature matcher to use. Options ['BruteForce', 'BruteForce-SL2', 'BruteForce-L1','FlannBased']")#尋找沒對描述符最小距離方法
#ap.add_argument("-v", "--visualize", type = str, default = "Yes", help="Whether the visualiz image should be shown. Options ['Yes', 'No', 'Each']")
ap.add_argument("-v", "--visualize", type = str, default = "Yes", help="Whether the visualiztion image should be shown. Options ['Yes',  'No',  'Each']")#繪製對關鍵點和描述符之間的匹配
args = vars(ap.parse_args())

if args["detector"] == "DOG":
    detector = FeatureDetector_create("SIFT")
elif args["detector"] == "FASTHESSIAN":
    detector = FeatureDetector_create("SURF")
else:
    detector = FeatureDetector_create(args["detector"])
extractor = DescriptorExtractor_create(args["extractor"])#提取關鍵點區域的特徵描述符

matcher = DescriptorMatcher_create(args["matcher"])
imageA = cv2.imread(args["first"])
imageB = cv2.imread(args["second"])
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
#提取關鍵點
kpsA = detector.detect(grayA)
kpsB = detector.detect(grayB)
#提取關鍵的區域性特徵描述符
(kpsA, featuresA) = extractor.compute(grayA, kpsA)
(kpsB, featuresB)  = extractor.compute(grayB, kpsB)
rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
matches = []
if rawMatches is not None:
    for m in rawMatches:
        #篩選符合條件的關鍵點
        if len(m) == 2 and m[0].distance < m[1].distance*0.8:
            matches.append((m[0].trainIdx, m[0].queryIdx))

    print("# of keypoints from first image:{}".format(len(kpsA)))

複製程式碼

 11、二進位制描述符

11.1、ORB

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():

    detector = cv2.FeatureDetector_create("ORB")
    extractor = cv2.DescriptorExtractor_create("ORB")
 
    kps = detector.detect(gray)
    (kps, descs) = extractor.compute(gray, kps)

else:
    detector = cv2.ORB_create()

    (kps, descs) = detector.detectAndCompute(gray, None)
 
# show the shape of the keypoints and local invariant descriptors array
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

11.2、BRISK

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("BRISK")
    extractor = cv2.DescriptorExtractor_create("BRISK")
 
    kps = detector.detect(gray)
    (kps, descs) = extractor.compute(gray, kps)
 
else:
    detector = cv2.BRISK_create()
 

    (kps, descs) = detector.detectAndCompute(gray, None)
 
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

11.3、BRIEF

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())

image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("FAST")
    extractor = cv2.DescriptorExtractor_create("BRIEF")
 
else:
    detector = cv2.FastFeatureDetector_create()
    extractor = cv2.xfeatures2d.BriefDescriptorExtractor_create()
 

kps = detector.detect(gray)
(kps, descs) = extractor.compute(gray, kps)
 
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼

複製程式碼

from __future__ import print_function
import argparse
import cv2
import imutils
 
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
if imutils.is_cv2():
    detector = cv2.FeatureDetector_create("FAST")
    extractor = cv2.DescriptorExtractor_create("FREAK")
    kps = detector.detect(gray)
    (kps, descs) = extractor.compute(gray, kps)
 
else:

    detector = cv2.FastFeatureDetector_create()
    extractor = cv2.xfeatures2d.FREAK_create()
 
    kps = detector.detect(gray, None)
    (kps, descs) = extractor.compute(gray, kps)
 
print("[INFO] # of keypoints detected: {}".format(len(kps)))
print("[INFO] feature vector shape: {}".format(descs.shape))

複製程式碼