【问题标题】:Detecting if an object from one image is in another image with OpenCV使用 OpenCV 检测一个图像中的对象是否在另一个图像中
【发布时间】:2013-03-10 13:57:16
【问题描述】:

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

http://imgur.com/luj2Z

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

http://imgur.com/yBWgc

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

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

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

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

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

5) 我可以手动操作样本图像,例如勾勒出我希望检测的对象;候选图像太多,无法手动操作。

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

我最初的想法是先在示例图像中的对象周围画一个粗略的轮廓。然后,我可以识别对象中的角点和候选图像中的角点。我可以分析每个角周围的像素,看看它们是否相似,然后按每个角的最大相似度得分之和进行排名。我也不确定如何量化相似的像素。我猜只是它们的 RGB 值的欧几里得距离?

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

所以我有几个问题:

A) 这种思路总体上是否有意义,还是我遗漏了什么?

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

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

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

【问题讨论】:

    标签: c# python image-processing opencv computer-vision


    【解决方案1】:

    幸运的是,来自 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

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

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

    【讨论】:

      【解决方案2】:

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

      当然,这是一个非常高级的解释。魔鬼在细节中,对于那些你应该阅读一些论文。从 David Lowe 的 Distinctive image features from scale-invariant keypoints 开始,然后阅读 SURF 上的论文。

      另外,考虑将此问题移至Signal and Image Processing Stack Exchange

      【讨论】:

        【解决方案3】:

        如果将来有人出现,这里有一个使用 openCV 执行此操作的小示例。它基于opencv sample,但是(在我看来)这更清楚一些,所以我也将它包括在内。

        使用 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()
        

        【讨论】:

        • 谢谢,这为我指明了正确的方向。欣赏它。
        【解决方案4】:

        如前所述,SIFT 和 SURF 等算法包含一个特征点,该特征点对许多失真和描述符是不变的,该描述符旨在稳健地对特征点及其周围环境进行建模。

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

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

        这种方法允许软匹配和一定程度的泛化,例如检索所有带有飞机的图像。

        • VLfeat website 包含一个出色的 SIFT 库旁边的一个很好的演示,用于对 caltech 101 数据集进行分类。

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

        • LEAR的工作也是一个好的开始

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-22
          • 1970-01-01
          • 1970-01-01
          • 2011-01-30
          • 2014-03-15
          • 2012-06-09
          • 2012-07-07
          • 1970-01-01
          相关资源
          最近更新 更多