用OpenCV检测一个图像中的对象是否在另一个图像中
本文关键字:图像 对象 是否 另一个 一个 检测 OpenCV | 更新日期: 2023-09-27 18:12:10
我有一个示例图像,其中包含一个对象,例如以下图像中的耳环:
https://i.stack.imgur.com/N5w9a.jpg 然后我有一个大的候选图像集,我需要确定哪一个最可能包含对象,例如: https://i.stack.imgur.com/xYL90.jpg所以我需要为每个图像生成一个分数,其中最高分对应于最有可能包含目标对象的图像。现在,在这种情况下,我有以下条件/约束来处理/绕过:
1)我可以获得多个不同角度的样本图像。
2)样本图像可能与候选图像具有不同的分辨率、角度和距离。
3)有很多候选图像(> 10,000),所以它必须相当快。
4)我愿意牺牲一些精度来换取速度,所以如果这意味着我们必须搜索前100名而不仅仅是前10名,那很好,可以手动完成。
5)我可以手动操作样本图像,例如勾勒出我想要检测的对象;候选图像太多,无法手动操作。
6)我在OpenCV或计算机视觉方面没有真正的背景,所以我在这里从头开始。
我最初的想法是首先在样本图像中的对象周围画一个粗略的轮廓。然后,我可以识别物体中的角和候选图像中的角。我可以分析每个角周围的像素,看看它们是否相似,然后根据每个角的最大相似分数的总和进行排名。我也不知道如何量化相似的像素。我猜就是它们的RGB值的欧几里得距离?
这里的问题是它忽略了对象的中心。在上面的例子中,如果耳环的四角都靠近金框,那么它就不会考虑耳环内的红、绿、蓝宝石。我想我可以通过观察所有角对,并通过沿着它们之间的线采样一些点来确定相似性来改进这一点。
所以我有几个问题:
A)这种思路总体上是有意义的,还是我遗漏了什么?
B)我应该调查使用OpenCV的哪些特定算法?我知道有多种角点检测算法,但我只需要一个,如果差异都在边缘上优化,那么我可以用最快的。
C)任何使用算法的示例代码,这将有助于我的理解?
我的语言选项是Python或c#。
幸运的是,来自OpenCV的好心的家伙刚刚为你做了这件事。检查您的样本文件夹"opencv'samples'cpp'matching_to_many_images.cpp"。编译并尝试使用默认图像。
该算法可以很容易地进行调整,使其更快或更精确。
目标识别算法主要分为两部分:关键点检测;描述和对象匹配。对于它们都有许多算法/变体,您可以使用它们直接在OpenCV中播放。
检测/描述可通过:SIFT/SURF/ORB/GFTT/STAR/FAST等方法完成。
对于匹配,你有:蛮力,汉明等(有些方法是特定于给定的检测算法)
提示:
-
裁剪原始图像,使有趣的对象覆盖尽可能多的图像区域。
-
SIFT是最准确和最懒惰的描述符。FAST是精密度和准确度的良好结合。GFTT老旧而且相当不可靠。ORB是OPENCV中新添加的,在速度和精度方面都非常有前途。
- 结果取决于物体在另一张图像中的姿态。如果它是调整大小,旋转,挤压,部分覆盖等,尝试SIFT。如果它是一个简单的任务(即它以几乎相同的大小/旋转等出现,大多数描述符将处理得很好)
- ORB可能还没有在OpenCV版本中。尝试从openCV主干下载最新版本并编译https://code.ros.org/svn/opencv/trunk
所以,你可以通过反复试验找到最适合你的组合。
对于每个实现的细节,您应该阅读原始论文/教程。Google scholar是一个好的开始
查看SURF特性,它是openCV的一部分。这里的想法是,你有一个算法来寻找两张图像中的"兴趣点"。你也有一个算法来计算每个兴趣点周围图像补丁的描述符。典型地,这个描述符捕获补丁中边缘方向的分布。然后尝试找到点对应,即对于图像A中的每个兴趣点,尝试在图像b中找到相应的兴趣点。这是通过比较描述符来完成的,并寻找最接近的匹配。然后,如果你有一组由一些几何变换联系起来的对应,你就有了一个检测。
当然,这是一个非常高级的解释。细节决定成败,对于这些问题,你应该读一些论文。从David Lowe的尺度不变关键点的独特图像特征开始,然后阅读SURF的论文。
另外,考虑将这个问题转移到信号和图像处理堆栈交换
以防将来有人出现,这里有一个使用openCV的小示例。它是基于opencv示例的,但是(在我看来),这更清楚一些,所以我也包括它。
使用openCV 2.4.4测试
#!/usr/bin/env python
'''
Uses SURF to match two images.
Finds common features between two images and draws them
Based on the sample code from opencv:
samples/python2/find_obj.py
USAGE
find_obj.py <image1> <image2>
'''
import sys
import numpy
import cv2
###############################################################################
# Image Matching
###############################################################################
def match_images(img1, img2, img1_features=None, img2_features=None):
"""Given two images, returns the matches"""
detector = cv2.SURF(3200)
matcher = cv2.BFMatcher(cv2.NORM_L2)
if img1_features is None:
kp1, desc1 = detector.detectAndCompute(img1, None)
else:
kp1, desc1 = img1_features
if img2_features is None:
kp2, desc2 = detector.detectAndCompute(img2, None)
else:
kp2, desc2 = img2_features
#print 'img1 - %d features, img2 - %d features' % (len(kp1), len(kp2))
raw_matches = matcher.knnMatch(desc1, trainDescriptors=desc2, k=2)
kp_pairs = filter_matches(kp1, kp2, raw_matches)
return kp_pairs
def filter_matches(kp1, kp2, matches, ratio=0.75):
"""Filters features that are common to both images"""
mkp1, mkp2 = [], []
for m in matches:
if len(m) == 2 and m[0].distance < m[1].distance * ratio:
m = m[0]
mkp1.append(kp1[m.queryIdx])
mkp2.append(kp2[m.trainIdx])
kp_pairs = zip(mkp1, mkp2)
return kp_pairs
###############################################################################
# Match Diplaying
###############################################################################
def draw_matches(window_name, kp_pairs, img1, img2):
"""Draws the matches"""
mkp1, mkp2 = zip(*kp_pairs)
H = None
status = None
if len(kp_pairs) >= 4:
p1 = numpy.float32([kp.pt for kp in mkp1])
p2 = numpy.float32([kp.pt for kp in mkp2])
H, status = cv2.findHomography(p1, p2, cv2.RANSAC, 5.0)
if len(kp_pairs):
explore_match(window_name, img1, img2, kp_pairs, status, H)
def explore_match(win, img1, img2, kp_pairs, status=None, H=None):
"""Draws lines between the matched features"""
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
vis = numpy.zeros((max(h1, h2), w1 + w2), numpy.uint8)
vis[:h1, :w1] = img1
vis[:h2, w1:w1 + w2] = img2
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
if H is not None:
corners = numpy.float32([[0, 0], [w1, 0], [w1, h1], [0, h1]])
reshaped = cv2.perspectiveTransform(corners.reshape(1, -1, 2), H)
reshaped = reshaped.reshape(-1, 2)
corners = numpy.int32(reshaped + (w1, 0))
cv2.polylines(vis, [corners], True, (255, 255, 255))
if status is None:
status = numpy.ones(len(kp_pairs), numpy.bool_)
p1 = numpy.int32([kpp[0].pt for kpp in kp_pairs])
p2 = numpy.int32([kpp[1].pt for kpp in kp_pairs]) + (w1, 0)
green = (0, 255, 0)
red = (0, 0, 255)
for (x1, y1), (x2, y2), inlier in zip(p1, p2, status):
if inlier:
col = green
cv2.circle(vis, (x1, y1), 2, col, -1)
cv2.circle(vis, (x2, y2), 2, col, -1)
else:
col = red
r = 2
thickness = 3
cv2.line(vis, (x1 - r, y1 - r), (x1 + r, y1 + r), col, thickness)
cv2.line(vis, (x1 - r, y1 + r), (x1 + r, y1 - r), col, thickness)
cv2.line(vis, (x2 - r, y2 - r), (x2 + r, y2 + r), col, thickness)
cv2.line(vis, (x2 - r, y2 + r), (x2 + r, y2 - r), col, thickness)
vis0 = vis.copy()
for (x1, y1), (x2, y2), inlier in zip(p1, p2, status):
if inlier:
cv2.line(vis, (x1, y1), (x2, y2), green)
cv2.imshow(win, vis)
###############################################################################
# Test Main
###############################################################################
if __name__ == '__main__':
if len(sys.argv) < 3:
print "No filenames specified"
print "USAGE: find_obj.py <image1> <image2>"
sys.exit(1)
fn1 = sys.argv[1]
fn2 = sys.argv[2]
img1 = cv2.imread(fn1, 0)
img2 = cv2.imread(fn2, 0)
if img1 is None:
print 'Failed to load fn1:', fn1
sys.exit(1)
if img2 is None:
print 'Failed to load fn2:', fn2
sys.exit(1)
kp_pairs = match_images(img1, img2)
if kp_pairs:
draw_matches('find_obj', kp_pairs, img1, img2)
else:
print "No matches found"
cv2.waitKey()
cv2.destroyAllWindows()
如前所述,SIFT和SURF等算法包含一个特征点和一个描述子,特征点对许多畸变都是不变的,描述子旨在对特征点周围环境进行鲁棒建模。
后者越来越多地用于图像分类和识别,通常被称为"词袋"或"视觉词"方法。
在最简单的形式中,可以从所有图像的所有描述符中收集所有数据并对它们进行聚类,例如使用k-means。然后,每个原始图像都有描述符,这些描述符有助于生成多个聚类。这些聚类的质心,即视觉词,可以用作图像的新描述符。然后可以在具有反向文件设计的体系结构中使用它们。
这种方法允许软匹配和一定程度的泛化,例如检索所有带有飞机的图像。
-
VLfeat网站包含,在一个优秀的SIFT库旁边,一个很好的这种方法的演示,分类caltech 101数据集。
-
Caltech本身提供Matlab/c++软件以及相关出版物。
-
LEAR的工作也是一个良好的开端