使用OpenCV实现以图搜图

什么是以图搜图?

以图搜图,简单来说,就是通过搜索图像的文本或视觉特征,帮助用户找到与这张图片相似或相关的其他图形图像资料。

感知哈希算法

感知哈希算法(Perceptual Hashing Algorithm,简称PHA或PHash)是一种用于检测非结构化数据(如图像、视频、音频)相似性的技术。其原理是利用数据的频谱特征来描述对象,并通过一定的数学方法计算出一个哈希码(Hash String),以此来表示该对象的特征。当数据的频谱特征发生变化时,其对应的哈希码也会相应改变。

算法实现步骤

感知哈希算法实现步骤主要包括以下几步:

  1. 缩小尺寸:将图像缩小到一定的尺寸,比如8x8,总共64个像素。这一步的目的是去除图像的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图像差异。
  2. 简化色彩:将缩小后的图像转为灰度图,即所有像素点都转换为灰度值。简化色彩有助于突出图像的主要特征,降低计算的复杂度。
  3. 计算平均值:计算所有像素的灰度平均值。这个平均值将作为后续比较像素灰度的基准。
  4. 比较像素灰度:将每个像素的灰度值与平均值进行比较。如果像素的灰度值大于或等于平均值,则记录为1,否则记录为0。
  5. 计算哈希值:将上一步的比较结果组合在一起,形成一个固定长度的哈希值。这个哈希值就是图像的“指纹”,代表了图像的主要特征。
  6. 对比图片指纹:在生成了每个图像的哈希值(即指纹)之后,就可以开始对比不同的图片指纹了。通常,会计算两个指纹之间的差异度,例如,通过比较两个哈希值中不同位的数量。如果差异度低于某个预设的阈值,就认为这两张图片是相似的;如果差异度高于阈值,则认为它们是不同的图片。

效果

要搜索的图片:
在这里插入图片描述
搜索的图片库:
在这里插入图片描述
匹配出3个最接近的图片:
在这里插入图片描述

源码

import glob
import cv2
import numpy as np
import matplotlib.pyplot as plt


# ------------------ 辅助函数 ------------------

def resize_and_grayscale(image, size=(8, 8)):
    """将图像缩放并转换为灰度图。"""
    resized = cv2.resize(image, size)
    gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
    return gray


def compute_hash(image, size=(8, 8)):
    """计算图像的感知哈希值。"""
    gray = resize_and_grayscale(image, size)
    mean = np.mean(gray)
    binary = (gray > mean).astype(int)
    return binary.flatten()


def compute_hamming_distance(hash1, hash2):
    """计算两个哈希值之间的汉明距离。"""
    xor = np.bitwise_xor(hash1, hash2)
    return np.sum(xor)


def load_images_from_folder(folder, extensions=('jpg', 'jpeg', 'gif', 'png', 'bmp')):
    """从指定文件夹加载图像,并返回图像文件名和哈希值的列表。"""
    images = []
    for ext in extensions:
        images.extend(glob.glob(f'{folder}/*.{ext}'))
    hashes = {img_path: compute_hash(cv2.imread(img_path)) for img_path in images}
    return hashes


# ------------------ 主程序 ------------------

def main():
    # 设置检索图像路径
    query_image_path = "img_2.png"
    query_image = cv2.imread(query_image_path)
    if query_image is None:
        print(f"Error: Unable to load query image {query_image_path}")
        return

    query_hash = compute_hash(query_image)
    print(f"检索图像的感知哈希值为:\n{query_hash}")

    # 加载指定文件夹下的所有图像及其哈希值
    image_hashes = load_images_from_folder('img')

    # 找出最相似的图像
    distances = [(compute_hamming_distance(query_hash, image_hash), image_path)
                 for image_path, image_hash in image_hashes.items()]
    sorted_distances = sorted(distances)

    # 绘制结果
    fig, axs = plt.subplots(1, 4, figsize=(12, 4))
    axs[0].imshow(cv2.cvtColor(query_image, cv2.COLOR_BGR2RGB))
    axs[0].set_axis_off()
    axs[0].set_title("Query Image")

    for i, (distance, image_path) in enumerate(sorted_distances[:3], start=1):
        image = cv2.imread(image_path)
        axs[i].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        axs[i].set_axis_off()
        axs[i].set_title(f"Result {i} - Distance: {distance}")

    plt.tight_layout()
    plt.show()


if __name__ == "__main__":
    main()

相关推荐

  1. GO语言使用OpenCV

    2024-03-30 10:18:03       33 阅读
  2. 拍立淘助力电商新趋势:购物成主流

    2024-03-30 10:18:03       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 10:18:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 10:18:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 10:18:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 10:18:03       18 阅读

热门阅读

  1. FastAPI+React全栈开发14 FastAPI如何开发REST接口

    2024-03-30 10:18:03       18 阅读
  2. C语言如何进⾏函数的⼀般调⽤?

    2024-03-30 10:18:03       21 阅读
  3. YOLOv5训练过程中的各种报错

    2024-03-30 10:18:03       19 阅读
  4. CentOS 7.9上安装Redis

    2024-03-30 10:18:03       18 阅读
  5. 贪心,LeetCode 2952. 需要添加的硬币的最小数量

    2024-03-30 10:18:03       20 阅读
  6. 大型网站的容灾备份和高可用的详细技术和示例

    2024-03-30 10:18:03       18 阅读
  7. TCP的keepalive与HTTP的keep-alive的区别

    2024-03-30 10:18:03       19 阅读