如何判断两张图片的相似度?原来图片对比也可以如此简单!

简介: 本文介绍了图片对比技术在多个场景中的应用,如图片去重、内容审核、版权维权及相似图片搜索,并详细解析了两种主流的图片对比方法。第一种是**MD5指纹对比**,适合精确匹配完全相同的图片,具有速度快、简单易用的特点,但对稍作修改的图片无能为力。第二种是**图像哈希对比**,包括平均哈希、感知哈希等算法,能够判断图片的相似程度,适用于处理缩放、旋转或亮度调整后的图片,但在语义相似性上仍有局限。最后提到,随着机器学习和深度神经网络的发展,图片相似度判断技术将有更多可能性,值得进一步探索。

在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:

  1. 图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个社交媒体平台的运营,每天要处理数万张图片。重复图片不仅占用存储空间,还会影响用户体验。
  2. 内容审核:一些平台需要筛选相似或重复的内容,防止版权侵犯和内容垃圾。
  3. 版权维权:检测图片有无被未经授权使用的情况,比如,摄影师和设计师需要知道自己的作品是否被未经授权使用。
  4. 相似图片搜索:网盘、云存储服务需要帮助用户清理重复文件。

在这些场景中,图片对比技术可以帮我们自动化处理大量图片,提高工作效率。

但是,图片对比可不像字符那样可以直接使用等于号=直接对比,那么,我们有哪些对比方式呢?

方法一:MD5指纹对比 - 精确匹配

MD5 是一种信息摘要算法,可以将任意长度的数据映射为固定长度的字符串。对于图片文件,我们可以将其计算出一个独一无二的 MD5 值,就像一个数字指纹,可以用来精确比对两个文件(不仅仅是图片)是否完全相同。

下面是使用 Go 语言计算图片 MD5 值的示例代码:

package main

import (
    "crypto/md5"
    "fmt"
    "io"
    "os"
)

// calculateMD5 计算文件的MD5值
// 为图片颁发独一无二的“身份证”
func calculateMD5(filePath string) (string, error) {
   
    // 打开文件
    file, err := os.Open(filePath)
    if err != nil {
   
        return "", fmt.Errorf("无法打开文件:%v", err)
    }
    defer file.Close()

    // 创建MD5哈希器
    hash := md5.New()

    // 将文件内容复制到哈希器中
    if _, err := io.Copy(hash, file); err != nil {
   
        return "", fmt.Errorf("计算MD5时出错:%v", err)
    }

    // 返回MD5字符串
    return fmt.Sprintf("%x", hash.Sum(nil)), nil
}

func main() {
   
    // 比较两张图片
    md51, err := calculateMD5("image1.jpg")
    if err != nil {
   
        fmt.Println("图片1处理失败:", err)
        return
    }

    md52, err := calculateMD5("image2.jpg")
    if err != nil {
   
        fmt.Println("图片2处理失败:", err)
        return
    }

    // 对比结果
    if md51 == md52 {
   
        fmt.Println("图片完全相同")
    } else {
   
        fmt.Println("图片不同")
    }
}

代码解读:

  1. 我们定义了一个 calculateMD5 函数,传入文件路径,返回计算出的 MD5 字符串。
  2. 函数中先打开文件,创建一个 MD5 哈希器 hash
  3. 通过io.Copy将文件内容写入哈希器中,计算出 MD5 值。
  4. 最后将 MD5 字节数组格式化为字符串返回。
  5. main 函数中,我们计算两个图片文件的 MD5 值,比对它们是否相等,输出结果。

MD5 比对的特点:

  • ✅ 速度快、计算简单
  • ✅ 可精确判断两个文件是否完全相同(只要是文件,都可以通过这种方式进行判断是否一样)
  • ❌ 无法检测内容相似但不完全相同的图片
  • 🐞 图片稍有改动(如添加水印)就会导致 MD5 值完全不同

所以 MD5 比对适合用于检测完全相同的图片,如文件去重等场景。如果两张图片只是稍作修改(如调整亮度、旋转等),MD5 就无能为力了。

比如下面这两张图,我只是稍微裁剪了一下

原图

裁剪后的

虽然,裁剪之后,确实已经不是一摸一样的图片了,但是,我们还是觉得这两张图片其实就是长得非常像的两张图,其实我们还是得认为它们就是一张图。那么像这样的图片,我们如何区分呢?这时,我们可以借助图像哈希算法。

方法二:图像哈希对比

图像哈希(Image Hashing)是一类可以比较图片相似程度的算法。其基本原理是:将图片缩小、简化为一个哈希值,然后比较不同图片哈希值的差异度,来判断它们的相似程度。

常见的图像哈希算法有:

  1. 平均哈希(Average Hash)
  2. 感知哈希(Perceptual Hash)
  3. 差异哈希(Difference Hash)
  4. 小波哈希(Wavelet Hash)

这里我们以第三方包为例:

首先先安装这个包

go get github.com/corona10/goimagehash

然后我们来尝试实现一个图片相似度比对:

package main

import (
    "fmt"
    "image/png"
    "os"

    "github.com/corona10/goimagehash"
)

// compareImageSimilarity 比较图片相似度
func compareImageSimilarity(image1Path, image2Path string) error {
   
    file1, err := os.Open(image1Path)
    if err != nil {
   
        return fmt.Errorf("打开图片1失败:%v", err)
    }
    defer file1.Close()

    file2, err := os.Open(image2Path)
    if err != nil {
   
        return fmt.Errorf("打开图片2失败:%v", err)
    }
    defer file2.Close()

    // 加载图片
    img1, err := png.Decode(file1)
    if err != nil {
   
        return fmt.Errorf("加载图片1失败:%v", err)
    }

    img2, err := png.Decode(file2)
    if err != nil {
   
        return fmt.Errorf("加载图片2失败:%v", err)
    }

    // 生成平均哈希
    avgHash1, err := goimagehash.AverageHash(img1)
    if err != nil {
   
        return fmt.Errorf("生成图片1哈希失败:%v", err)
    }

    avgHash2, err := goimagehash.AverageHash(img2)
    if err != nil {
   
        return fmt.Errorf("生成图片2哈希失败:%v", err)
    }

    // 计算差异哈希
    diffHash1, err := goimagehash.DifferenceHash(img1)
    if err != nil {
   
        return fmt.Errorf("生成图片1差异哈希失败:%v", err)
    }

    diffHash2, err := goimagehash.DifferenceHash(img2)
    if err != nil {
   
        return fmt.Errorf("生成图片2差异哈希失败:%v", err)
    }

    // 计算汉明距离
    avgDistance, err := avgHash1.Distance(avgHash2)
    if err != nil {
   
        return fmt.Errorf("计算平均哈希距离失败:%v", err)
    }

    diffDistance, err := diffHash1.Distance(diffHash2)
    if err != nil {
   
        return fmt.Errorf("计算差异哈希距离失败:%v", err)
    }

    // 打印相似度
    fmt.Printf("平均哈希距离:%d\n", avgDistance)
    fmt.Printf("差异哈希距离:%d\n", diffDistance)

    // 判断相似程度
    if avgDistance == 0 && diffDistance == 0 {
   
        fmt.Println("两张图一样")
    } else if avgDistance <= 5 || diffDistance <= 5 {
   
        fmt.Println("图片高度相似")
    } else if avgDistance <= 10 || diffDistance <= 10 {
   
        fmt.Println("图片相似")
    } else {
   
        fmt.Println("图片差异较大")
    }

    return nil
}

func main() {
   
    err := compareImageSimilarity("img.png", "img_1.png")
    if err != nil {
   
        fmt.Println("图片对比出错:", err)
    }
}

图像哈希的特点:

  • ✅ 可以比较图片内容的相似程度
  • ✅ 对图片的缩放、旋转、亮度变化等稍微鲁棒
  • ✅ 计算难度适中,可应用于相似图片搜索等场景
  • ❌ 仍无法识别完全不同但语义相似的图片(比如同一物体不同角度的照片)

它们各有特点和适用场景:

MD5指纹:简单快速,适合精确匹配完全相同的图片。
图像哈希:可以比较图片的相似程度,在相似图片搜索等场景下很有用。

当然,这只是图像相似度算法的冰山一角。在实际应用中,我们还需要考虑性能、精度、复杂度等因素,选择最适合的方案。

图像识别领域在不断发展,一些前沿技术如机器学习、深度神经网络等,为图片相似度判断带来了更多的可能性,值得我们去学习和探索。

源码我放在这里了 https://github.com/pudongping/golang-tutorial/tree/main/project/compare_image_similarity 有需要的童鞋,可以自取。

相关文章
|
算法 搜索推荐 计算机视觉
图片相似度计算及检索调研
图片相似度计算和相似图片搜索,是图片识别领域两个常见的应用场景。例如搜索相似商品,和相似的图片,在百度、淘宝中都有应用。在某些业务中,也存在对图片相似度的计算和判断。因此,在这里简单介绍一下相关算法。
1492 0
|
存储 人工智能 测试技术
图像相似度比较之 CLIP or DINOv2
图像相似度比较之 CLIP or DINOv2
|
3月前
|
人工智能 移动开发 JavaScript
AI + 低代码技术揭秘(一):概述
VTJ.PRO 是一个基于 AI 的 Vue3 低代码开发平台,支持 Vue 单文件组件(SFC)与领域特定语言(DSL)之间的双向转换。它构建于 monorepo 架构之上,提供同步版本控制和全面的软件包生态系统,涵盖可视化设计、代码生成及多平台部署功能,同时兼容现有 Vue 3 工作流。平台特点包括双向代码流、AI 集成、Vue 3 基础支持、多平台适配以及低学习门槛等。通过模块化架构与智能工具,VTJ 加速开发流程并保持灵活性,适用于 Web、移动及跨平台项目。当前版本为 0.12.40,源码托管于 Gitee。
157 8
AI + 低代码技术揭秘(一):概述
|
3月前
|
Ubuntu Linux 数据安全/隐私保护
Windows中安装WSL 2和Ubuntu系统的教程
回看这一路,有趣吧?你已经跨界成为了一个Windows和Linux的桥梁。期待在代码的世界里,把一切玩得风生水起!
238 1
|
7月前
|
机器学习/深度学习 人工智能
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
本文介绍了一种名为 Diffusion-DPO 的创新方法,该方法基于直接偏好优化(DPO)原理,简化了扩散模型与人类偏好的对齐过程。相比传统的基于人类反馈的强化学习(RLHF)方法,Diffusion-DPO 避免了显式奖励模型的训练,通过数学近似简化实现流程,并在处理开放词汇表场景时展现出更强的能力。实验结果表明,该方法在 Stable Diffusion 1.5 和 SDXL-1.0 等主流模型上显著提升了生成图像的质量和可控性,为未来扩散模型的发展提供了新的思路。
526 14
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
|
7月前
|
人工智能 自然语言处理 PyTorch
Sa2VA:别再用PS抠图了!字节跳动开源Sa2VA:一句话自动分割视频,连头发丝都精准
Sa2VA 是由字节跳动等机构联合推出的多模态大语言模型,结合 SAM2 和 LLaVA 实现对图像和视频的精确分割和对话功能。
437 15
Sa2VA:别再用PS抠图了!字节跳动开源Sa2VA:一句话自动分割视频,连头发丝都精准
|
7月前
|
人工智能 资源调度 API
AnythingLLM:34K Star!一键上传文件轻松打造个人知识库,构建只属于你的AI助手,附详细部署教程
AnythingLLM 是一个全栈应用程序,能够将文档、资源转换为上下文,支持多种大语言模型和向量数据库,提供智能聊天功能。
5716 76
|
11月前
|
机器学习/深度学习 人工智能 文字识别
ultralytics YOLO11 全新发布!(原理介绍+代码详见+结构框图)
本文详细介绍YOLO11,包括其全新特性、代码实现及结构框图,并提供如何使用NEU-DET数据集进行训练的指南。YOLO11在前代基础上引入了新功能和改进,如C3k2、C2PSA模块和更轻量级的分类检测头,显著提升了模型的性能和灵活性。文中还对比了YOLO11与YOLOv8的区别,并展示了训练过程和结果的可视化
17726 0
|
存储 并行计算 NoSQL
如何利用Java进行大数据处理?
如何利用Java进行大数据处理?

热门文章

最新文章