写点什么

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

作者:左诗右码
  • 2025-06-10
    上海
  • 本文字数:2894 字

    阅读完需:约 9 分钟

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

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


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


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


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

发布于: 刚刚阅读数: 5
用户头像

左诗右码

关注

全网同名,欢迎关注交流。 2018-11-22 加入

三观比五官更正,思想比套路更深。常用技术栈PHP、Go、Python,享受编程,平时爱好写点文章。V公主号:「左诗右码」,欢迎关注交流。

评论

发布
暂无评论
如何判断两张图片的相似度?原来图片对比也可以如此简单!_左诗右码_InfoQ写作社区