从图像数据库中搜索对象

Searching for objects from database on image

假设我的数据库包含数千张不同形式和大小(小于 100 x 100 像素)的图像,并且保证每张图像只显示一个对象 - 符号、徽标、路标等。我想能够从互联网上获取任何图像 ("my_image.jpg") 并回答问题 "Do my_image contains any object (object can be resized, but without deformations) from my database?" - 假设有 95% 的可靠性。简化 my_images 将有白色背景。

我正在尝试使用 imagehash (https://github.com/JohannesBuchner/imagehash),这将非常有帮助,但为了获得有益的结果,我认为我必须(几乎)计算 my_image 的每个可能的哈希值 - 原因我不知道 my_image:

上的对象大小和位置
hash_list = []
MyImage = Image.open('my_image.jpg')

for x_start in range(image_width):
    for y_start in range(image_height):
        for x_end in range(x_start, image_width):
            for y_end in range(y_start, image_height):
                hash_list.append(imagehash.phash(MyImage.\
                crop(x_start, y_start, x_end, y_end)))

...然后尝试在数据库中找到类似的散列,但是当例如 image_width = image_height = 500 时,这个循环和搜索将花费很长时间。当然,我可以稍微优化一下,但对于更大的图像,它仍然看起来像切腹:

MIN_WIDTH = 30
MIN_HEIGHT = 30
STEP = 2

hash_list = []
MyImage = Image.open('my_image.jpg')

for x_start in range(0, image_width - MIN_WIDTH, STEP):
    for y_start in range(0, image_height - MIN_HEIGHT, STEP):
        for x_end in range(x_start + MIN_WIDTH, image_width, STEP):
            for y_end in range(y_start + MIN_HEIGHT, image_height, STEP):
                hash_list.append(...)

我想知道是否有一些很好的方法来定义 my_image 的哪些部分对计算哈希值有利 - 例如切割边缘看起来不是个好主意。也许有更简单的解决方法?如果程序能在最多 20 分钟内给出答案,那就太好了。如果有任何建议,我将不胜感激。

PS:对不起我的英语:)

对我来说,这看起来像是一个图像检索问题。但是,在您的情况下,您对二进制是/否答案更感兴趣,它告诉您输入图像 (my_image.jpg) 是否属于数据库中存在的对象。

我可以建议的第一件事是,您可以将所有图像(包括输入)的大小调整为固定大小,比如 100 x 100。但是如果某些图像中的对象非常小或存在于特定的图像区域(例如,左上角)然后调整大小会使事情变得更糟。但是,从您的问题中并不清楚这在您的情况下有多大可能。

关于你的第二个问题,找出物体的位置,我想你是在考虑这个,因为你的输入图像尺寸很大,比如 500 x 500?如果是这样,那么调整大小是更好的主意。但是,如果你问这个问题是因为对象定位到图像中的特定区域,那么我认为你可以计算一个梯度图像,这将帮助你如下识别背景区域:因为背景没有变化(完全白色)梯度值将是属于背景区域的像素为零。

与其计算和使用图像哈希,我建议您阅读基于视觉词袋(例如,here)的对象分类方法。虽然您的目标不是对对象进行分类,但它会帮助您想出不同的方法来解决您的问题。

毕竟我找到了对我来说非常好的解决方案,也许它对其他人有用:

我正在使用 SIFT 从 my_image 检测 "best candidates":

def multiscale_template_matching(template, image):
    results = []
    for scale in np.linspace(0.2, 1.4, 121)[::-1]:
        res = imutils.resize(image, width=int(image.shape[1] * scale))
        r = image.shape[1] / float(res.shape[1])
        if res.shape[0] < template.shape[0] or res.shape[1] < template.shape[1];
           break

        ## bigger correlation <==> better matching
        ## template_mathing uses SIFT to return best correlation and coordinates
        correlation, (x, y) = template_matching(template, res)
        coordinates = (x * r, y * r)
        results.appent((correlation, coordinates, r))

    results.sort(key=itemgetter(0), reverse=True)
    return results[:10]

然后我正在计算哈希值的结果:

ACCEPTABLE = 10

def find_best(image, template, candidates):
    template_hash = imagehash.phash(template)
    best_result = 50  ## initial value must be greater than ACCEPTABLE
    best_cand = None

    for cand in candidates:
        cand_hash = get_hash(...)
        hash_diff = template_hash - cand_hash
        if hash_diff < best_result:
            best_result = hash_diff
            best_cand = cand

    if best_result <= ACCEPTABLE:
        return best_cand, best_result
    else:
        return None, None

如果结果 < 可接受,我几乎可以肯定答案是 "GOT YOU!" :) 这个解决方案允许我在 7 分钟内将 my_image 与 1000 个对象进行比较。