
在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:
在这些场景中,图片对比技术可以帮我们自动化处理大量图片,提高工作效率。
但是,图片对比可不像字符那样可以直接使用等于号=直接对比,那么,我们有哪些对比方式呢?
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("图片不同")
}
}代码解读:
calculateMD5 函数,传入文件路径,返回计算出的 MD5 字符串。hash。io.Copy将文件内容写入哈希器中,计算出 MD5 值。main 函数中,我们计算两个图片文件的 MD5 值,比对它们是否相等,输出结果。MD5 比对的特点:
所以 MD5 比对适合用于检测完全相同的图片,如文件去重等场景。如果两张图片只是稍作修改(如调整亮度、旋转等),MD5 就无能为力了。
比如下面这两张图,我只是稍微裁剪了一下


虽然,裁剪之后,确实已经不是一摸一样的图片了,但是,我们还是觉得这两张图片其实就是长得非常像的两张图,其实我们还是得认为它们就是一张图。那么像这样的图片,我们如何区分呢?这时,我们可以借助图像哈希算法。
图像哈希(Image Hashing)是一类可以比较图片相似程度的算法。其基本原理是:将图片缩小、简化为一个哈希值,然后比较不同图片哈希值的差异度,来判断它们的相似程度。
常见的图像哈希算法有:
这里我们以第三方包为例:
首先先安装这个包
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有需要的童鞋,可以自取。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。