从图像数据库中查找图像
Find image from a database of images
我将在 Python 中使用 OpenCV 迈出第一步。
我想要做的是给定一张图片,从一组参考图片中找到它的 "original" 一张。需要说明的是,查询图片是整张图片(卡片)的一张简单照片,所以不是场景"find an object inside a photo",而是"just"相似度测试
我的最终数据库会非常大(大约 25 000 张图像),但我开始在较小的范围内进行一些测试(只有 270 张图像)。
识别效果完美,但速度非常慢:迭代所有 270 张图像需要 8 秒。我能够通过将描述符保存到磁盘并加载它们来加快工作速度,而不是计算它们;无论如何它仍然很慢。
所以我开始研究 FLANN:我得到了一些结果,但我的主要问题是找到匹配的图像。我得到了一大堆点,但我不知道如何获取正确的图像。
这是我的代码:
scanned = 'tests/temp_bw.png'
surf = cv2.xfeatures2d.SURF_create(400)
surf.setUpright(True)
img1 = cv2.imread(scanned, 0)
kp1, des1 = surf.detectAndCompute(img1, None)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
des_all = None
for filename in os.listdir('images'):
img2 = cv2.imread('images/' + filename, 0)
kp2, des2 = surf.detectAndCompute(img2, None)
if des_all is None:
des_all = des2
else:
des_all = np.concatenate((des_all, des2))
flann = cv2.flann.Index()
print "Training..."
flann.build(des_all, index_params)
print "Matching..."
indexes, matches = flann.knnSearch(des1, 10)
# and now???
关于如何参考最相似的图片有什么建议吗?
编辑
这是des2
的形状
print des2.shape
(1731, 64)
(2144, 64)
(1811, 64)
(1649, 64)
这些是来自 flann.knnSearch
的 return 值:
pprint(matches[0])
array([ 0.0463759], dtype=float32)
pprint(indexes[0])
array([249106], dtype=int32)
在构建您的 des_all 时,创建一个长度与描述符数量相同的列表,其中每个元素都是该描述符所来自的图像的索引。
获得匹配的特征后,您可以在列表中查找匹配该特征的图像。然后您可以对哪个图像正确进行简单多数投票,或者使用距离的倒数按重要性权衡选票。
编辑:如果您像这样修改您的 for 循环,您可以构建一个列表,其中包含生成了哪些图像的特征的数量:
for index, filename in enumerate(os.listdir('images')):
img2 = cv2.imread('images/' + filename, 0)
kp2, des2 = surf.detectAndCompute(img2, None)
indexList.extend([index]*des2.shape[0])
如果采用多数投票的方式进行投票,可以这样进行(每个特征为匹配到的图像投票,得票最多的图像获胜)
votes = indexList[indexes]
from collections import Counter
votes = Counter()
likelyMatch = votes.most_common()[0][0]
如果你想用火柴的距离来衡量,你应该记住matches
中的距离是平方的,你应该取平方根。这些距离可以用作反权重,使每个特征投票具有更高或更低的权重,具体取决于匹配的好坏。
一种简单(而且非常古老,至少 1980 年代)的技术是从每个图像计算空间散列,然后匹配散列。例如:
http://www.hackerfactor.com/blog/?/archives/529-Kind-of-Like-That.html
您可以很快找到完全匹配的内容。
找到近似匹配有点困难:您需要存储低分辨率哈希值,匹配它们,然后计算较大哈希值的汉明距离。
周围有很多实现,例如 dhash
是基于 ImageMagick 的 Ruby gem:
https://github.com/maccman/dhash
您还可以比较直方图。它们具有在旋转下不变的优点。
我将在 Python 中使用 OpenCV 迈出第一步。
我想要做的是给定一张图片,从一组参考图片中找到它的 "original" 一张。需要说明的是,查询图片是整张图片(卡片)的一张简单照片,所以不是场景"find an object inside a photo",而是"just"相似度测试
我的最终数据库会非常大(大约 25 000 张图像),但我开始在较小的范围内进行一些测试(只有 270 张图像)。
识别效果完美,但速度非常慢:迭代所有 270 张图像需要 8 秒。我能够通过将描述符保存到磁盘并加载它们来加快工作速度,而不是计算它们;无论如何它仍然很慢。
所以我开始研究 FLANN:我得到了一些结果,但我的主要问题是找到匹配的图像。我得到了一大堆点,但我不知道如何获取正确的图像。
这是我的代码:
scanned = 'tests/temp_bw.png'
surf = cv2.xfeatures2d.SURF_create(400)
surf.setUpright(True)
img1 = cv2.imread(scanned, 0)
kp1, des1 = surf.detectAndCompute(img1, None)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
des_all = None
for filename in os.listdir('images'):
img2 = cv2.imread('images/' + filename, 0)
kp2, des2 = surf.detectAndCompute(img2, None)
if des_all is None:
des_all = des2
else:
des_all = np.concatenate((des_all, des2))
flann = cv2.flann.Index()
print "Training..."
flann.build(des_all, index_params)
print "Matching..."
indexes, matches = flann.knnSearch(des1, 10)
# and now???
关于如何参考最相似的图片有什么建议吗?
编辑
这是des2
print des2.shape
(1731, 64)
(2144, 64)
(1811, 64)
(1649, 64)
这些是来自 flann.knnSearch
的 return 值:
pprint(matches[0])
array([ 0.0463759], dtype=float32)
pprint(indexes[0])
array([249106], dtype=int32)
在构建您的 des_all 时,创建一个长度与描述符数量相同的列表,其中每个元素都是该描述符所来自的图像的索引。
获得匹配的特征后,您可以在列表中查找匹配该特征的图像。然后您可以对哪个图像正确进行简单多数投票,或者使用距离的倒数按重要性权衡选票。
编辑:如果您像这样修改您的 for 循环,您可以构建一个列表,其中包含生成了哪些图像的特征的数量:
for index, filename in enumerate(os.listdir('images')):
img2 = cv2.imread('images/' + filename, 0)
kp2, des2 = surf.detectAndCompute(img2, None)
indexList.extend([index]*des2.shape[0])
如果采用多数投票的方式进行投票,可以这样进行(每个特征为匹配到的图像投票,得票最多的图像获胜)
votes = indexList[indexes]
from collections import Counter
votes = Counter()
likelyMatch = votes.most_common()[0][0]
如果你想用火柴的距离来衡量,你应该记住matches
中的距离是平方的,你应该取平方根。这些距离可以用作反权重,使每个特征投票具有更高或更低的权重,具体取决于匹配的好坏。
一种简单(而且非常古老,至少 1980 年代)的技术是从每个图像计算空间散列,然后匹配散列。例如:
http://www.hackerfactor.com/blog/?/archives/529-Kind-of-Like-That.html
您可以很快找到完全匹配的内容。
找到近似匹配有点困难:您需要存储低分辨率哈希值,匹配它们,然后计算较大哈希值的汉明距离。
周围有很多实现,例如 dhash
是基于 ImageMagick 的 Ruby gem:
https://github.com/maccman/dhash
您还可以比较直方图。它们具有在旋转下不变的优点。