用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的好心的家伙刚刚为你做了这件事。检查您的样本文件夹"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的工作也是一个良好的开端