使用OpenCV检测来自一个图像的对象是否在另一个图像中

我有一个包含对象的示例图像,如下图中的耳环:

View post on imgur.com

然后,我有一个大的候选图像集,我需要确定哪一个最有可能包含对象,例如:

View post on imgur.com

所以我需要为每个图像生成一个分数,其中最高分对应于最可能包含目标对象的图像。 现在,在这种情况下,我有以下条件/约束来处理/周围:

1)我可以获得不同角度的多个样本图像。

2)样本图像可能与候选图像处于不同的分辨率,角度和距离。

3)有很多候选图像(> 10,000),所以它必须相当快。

4)我愿意为速度牺牲一些精度,所以如果这意味着我们必须搜索前100名而不是前10名,这很好,可以手动完成。

5)我可以手动操作样本图像,例如勾勒出我想要检测的对象; 候选图像不能手动操作,因为太多了。

6)我根本没有OpenCV或计算机视觉的真实背景,所以我从头开始。

我最初的想法是首先在样本图像中围绕对象绘制粗略轮廓。 然后,我可以识别候选图像中的对象和角落的角落。 我可以分析每个角落周围的像素,看看它们是否看起来相似,然后按每个角落的最大相似度得分的总和进行排名。 我也不确定如何量化类似的像素。 我想只是他们的RGB值的欧几里德距离?

问题在于它忽略了对象的中心。 在上面的例子中,如果耳环的角落都在金框附近,那么它就不会考虑耳环内的红色,绿色和蓝色gem。 我想我可以通过查看所有角对并通过沿着它们之间的线采样一些点来确定相似性来改进这一点。

所以我有几个问题:

A)这种思路一般是否有意义,或者是否有一些我缺失的东西?

B)我应该调查OpenCV的哪些特定算法? 我知道有多个角点检测算法,但我只需要一个,如果差异都在边缘上进行优化,那么我最好用。

C)使用算法的任何示例代码都有助于我的理解?

我的语言选择是Python或C#。

查看SURFfunction,它是openCV的一部分。 这里的想法是你有一个算法在两个图像中找到“兴趣点”。 您还有一个算法,用于计算每个兴趣点周围的图像块的描述符。 通常,该描述符捕获补丁中边缘方向的分布。 然后,您尝试找到点对应关系,即对于图像A中的每个兴趣点,尝试在图像B中找到对应的兴趣点。这通过比较描述符并寻找最接近的匹配来实现。 然后,如果您有一组通过某种几何变换相关的对应关系,则可以进行检测。

当然,这是一个非常高级别的解释。 魔鬼在细节中,对于那些你应该阅读一些文章。 从 David Lowe的尺度不变关键点开始,使用独特的图像特征 ,然后阅读SURF上的论文。

另外,请考虑将此问题移至信号和图像处理堆栈交换

幸运的是,来自OpenCV的那些人为你做了这件事。 检入您的samples文件夹“opencv \ samples \ cpp \ matching_to_many_images.cpp”。 编译并尝试使用默认图像。

该算法可以很容易地适应,使其更快或更精确。

主要是,对象识别算法分为两部分:关键点检测和描述与对象匹配。 对于他们两个,有许多算法/变体,你可以直接进入OpenCV。

检测/描述可以通过以下方式完成:SIFT / SURF / ORB / GFTT / STAR / FAST等。

对于匹配你有:暴力,汉明等(某些方法特定于给定的检测算法)

提示开始:

  • 裁剪原始图像,使有趣的对象尽可能多地覆盖图像区域。 用它作为训练。

  • SIFT是最准确和最懒的描述符。 FAST是精度和准确度的完美结合。 GFTT陈旧且非常不可靠。 ORB是OPENCV新增的,在速度和准确性方面非常有前景。

  • 结果取决于另一图像中对象的姿势。 如果它被resize,旋转,挤压,部分覆盖等,请尝试SIFT。 如果它是一个简单的任务(即它出现在几乎相同的大小/旋转/等,大多数描述符将很好地应对)
  • ORB可能还没有出现在OpenCV版本中。 尝试从openCV trunk下载最新版本并编译它https://code.ros.org/svn/opencv/trunk

因此,您可以通过反复试验找到最适合您的组合。

有关每个实现的详细信息,您应该阅读原始论文/教程。 谷歌学者是一个好的开始

如果将来有人出现,这是一个使用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   ''' 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  " 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这样的算法包含一个特征点,该特征点对于许多失真和描述符是不变的,其目的是对其周围的特征点进行鲁棒建模。

后者越来越多地用于图像分类和识别,通常称为“词袋”或“视觉词”方法。

在最简单的forms中,可以从所有图像中收集来自所有描述符的所有数据并将它们聚类,例如使用k-means。 然后,每个原始图像都具有对许多聚类有贡献的描述符。 这些聚类的质心,即视觉词,可以用作图像的新描述符。 然后,这些可以用于具有反向文件设计的体系结构中。

该方法允许软匹配和一定量的概括,例如用飞机检索所有图像。

  • VLfeat网站旁边有一个优秀的SIFT库,这个方法的一个很好的演示,对caltech 101数据集进行分类。

  • Caltech本身提供Matlab / C ++软件以及相关出版物。

  • LEAR的工作也是一个良好的开端