python特征匹配_OpenCV3-Python特征匹配—纹身特征匹配实例

本博文基于FLANN算法介绍一个基于纹身取证的应用程序示例,参考《OpenCV3计算机视觉:Python语言实现(原书第2版)》第6章。

1. 保存图像描述符到文件

应用程序扫描保存图像的文件夹,并创建相应的描述符文件,供后面搜索使用,整个过程包括:加载图像、创建特征检测器、检测并计算、保存描述符到文件。# -*- coding: utf-8 -*-

"""

Created on Sun Jun 24 14:17:31 2018

@author: lu

"""

import cv2

import numpy as np

from os import walk

from os.path import join

def create_descriptors(folder):

files = []

for (dirpath, dirnames, filenames) in walk(folder):

files.extend(filenames)

for f in files:

save_descriptor(folder, f, cv2.xfeatures2d.SIFT_create())  #采用SIFT算法获取特征点

def save_descriptor(folder, image_path, feature_detector):

print ("reading %s" % image_path)

if image_path.endswith("npy"):

return

img = cv2.imread(join(folder, image_path), 0)

keypoints, descriptors = feature_detector.detectAndCompute(img, None)

descriptor_file = image_path.replace("jpg", "npy")  #保存为特征描述符文件,后缀为.npy

np.save(join(folder, descriptor_file), descriptors) #save()函数将数据保存为一个文件

#定义图像存放的目录

picDir = "./anchors"

#创建描述图像,用于FLANN检测

create_descriptors(picDir)

2. 扫描查找匹配

将描述符保存为文件后,接下来对所有描述符进行单应性处理,步骤如下:

<1> 加载查询图像,并为其创建描述符(如:tattoo_seed.jpg);

<2> 扫描加载文件夹中的描述符;

<3> 对于每一个描述符,通过FLANN算法进行匹配;

<4> 获取特征符匹配的数目,包括潜在罪犯的档案;

<5> 对于匹配的罪犯,认为匹配最多的图像是潜在的犯罪嫌疑人;# -*- coding: utf-8 -*-

"""

Created on Sun Jun 24 14:18:26 2018

@author: lu

"""

from os.path import join

from os import walk

import numpy as np

import cv2

# create an array of filenames

folder = "./anchors"

query = cv2.imread(join(folder, "tattoo_seed.jpg"), 0)

# create files, images, descriptors globals

files = []

images = []

descriptors = []

for (dirpath, dirnames, filenames) in walk(folder):

files.extend(filenames)

for f in files:

if f.endswith("npy") and f != "tattoo_seed.npy":

descriptors.append(f)

print (descriptors)

# create the sift detector

sift = cv2.xfeatures2d.SIFT_create()

query_kp, query_ds = sift.detectAndCompute(query, None)

# create FLANN matcher

FLANN_INDEX_KDTREE = 0

index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

# minimum number of matches

MIN_MATCH_COUNT = 10

potential_culprits = {}

print (">> Initiating picture scan...")

for d in descriptors:

print ("--------- analyzing %s for matches ------------" % d)

matches = flann.knnMatch(query_ds, np.load(join(folder, d)), k =2)

good = []

for m,n in matches:

if m.distance 

good.append(m)

if len(good) > MIN_MATCH_COUNT:

print ("%s is a match! (%d)" % (d, len(good)))

else:

print ("%s is not a match" % d)

potential_culprits[d] = len(good)

max_matches = None

potential_suspect = None

for culprit, matches in potential_culprits.items():

if max_matches == None or matches > max_matches:

max_matches = matches

potential_suspect = culprit

print ("potential suspect is %s" % potential_suspect.replace("npy", "").upper())

3. 形象化显示匹配

根据步骤2中方法,可获取最佳匹配图像。实际应用中,需要更形象化标识出源图像与目标图像之间的匹配情况,此时可通过如下代码实现形象化显示。# -*- coding: utf-8 -*-

"""

Created on Sun Jun 24 13:12:00 2018

@author: lu

"""

import numpy as np

import cv2

from matplotlib import pyplot as plt

'''

简单来说:

单应性就是当两幅图像中的一幅出现投影畸变(perspective distortion)时,它们还能彼此匹配

'''

#至少10个点匹配

MIN_MATCH_COUNT = 10

##电影光盘

#img1 = cv2.imread('./bb.jpg',0)

#img2 = cv2.imread('./bb_small.jpg',0)

#纹身检测

img1 = cv2.imread('./anchors/tattoo_seed.jpg',0)

img2 = cv2.imread('./anchors/dr-hurt.jpg',0)

# Initiate SIFT detector

sift = cv2.xfeatures2d.SIFT_create()

# find the keypoints and descriptors with SIFT

kp1, des1 = sift.detectAndCompute(img1,None)

kp2, des2 = sift.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE = 0

index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1,des2,k=2)

# store all the good matches as per Lowe's ratio test.

good = []

for m,n in matches:

if m.distance 

good.append(m)

'''

https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html?highlight=findhomography

Now we set a condition that atleast 10 matches (defined by MIN_MATCH_COUNT) are to be there to find the object. Otherwise simply show a message saying not enough matches are present.

If enough matches are found, we extract the locations of matched keypoints in both the images.

They are passed to find the perpective transformation. Once we get this 3x3 transformation matrix, we use it to transform the corners of queryImage to corresponding points in trainImage. Then we draw it.

'''

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)

'''

We have seen that there can be some possible errors while matching which may affect the result. To solve this problem, algorithm uses RANSAC or LEAST_MEDIAN (which can be decided by the flags).

So good matches which provide correct estimation are called inliers and remaining are called outliers.

cv2.findHomography() returns a mask which specifies the inlier and outlier points.

'''

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为灰度图像,因此设置为255对应边框为白色

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 = (51, 163, 236),

singlePointColor = None,

matchesMask = matchesMask, # draw only inliers

flags = 2)

# **表示接收的参数作为字典来处理

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)

cv2.imshow("HomographyMatch",img3)

cv2.waitKey()

cv2.destroyAllWindows()

注意:本站所有文章除特别说明外,均为原创,转载请务必以超链接方式并注明作者出处。

你可能感兴趣的:(python特征匹配)