Go語言如何判斷兩張圖片的相似度
在介紹技術(shù)細(xì)節(jié)前,我們先來看看圖片對(duì)比在哪些場景下可以用得到:
- 圖片去重:自動(dòng)刪除重復(fù)圖片,為存儲(chǔ)空間"瘦身"。想象你是一個(gè)社交媒體平臺(tái)的運(yùn)營,每天要處理數(shù)萬張圖片。重復(fù)圖片不僅占用存儲(chǔ)空間,還會(huì)影響用戶體驗(yàn)。
- 內(nèi)容審核:一些平臺(tái)需要篩選相似或重復(fù)的內(nèi)容,防止版權(quán)侵犯和內(nèi)容垃圾。
- 版權(quán)維 權(quán):檢測圖片有無被未經(jīng)授權(quán)使用的情況,比如,攝影師和設(shè)計(jì)師需要知道自己的作品是否被未經(jīng)授權(quán)使用。
- 相似圖片搜索:網(wǎng)盤、云存儲(chǔ)服務(wù)需要幫助用戶清理重復(fù)文件。
在這些場景中,圖片對(duì)比技術(shù)可以幫我們自動(dòng)化處理大量圖片,提高工作效率。
但是,圖片對(duì)比可不像字符那樣可以直接使用等于號(hào)=
直接對(duì)比,那么,我們有哪些對(duì)比方式呢?
方法一:MD5指紋對(duì)比 - 精確匹配
MD5 是一種信息摘要算法,可以將任意長度的數(shù)據(jù)映射為固定長度的字符串。對(duì)于圖片文件,我們可以將其計(jì)算出一個(gè)獨(dú)一無二的 MD5 值,就像一個(gè)數(shù)字指紋,可以用來精確比對(duì)兩個(gè)文件(不僅僅是圖片)是否完全相同。
下面是使用 Go 語言計(jì)算圖片 MD5 值的示例代碼:
package main import ( "crypto/md5" "fmt" "io" "os" ) // calculateMD5 計(jì)算文件的MD5值 // 為圖片頒發(fā)獨(dú)一無二的“身份證” func calculateMD5(filePath string) (string, error) { // 打開文件 file, err := os.Open(filePath) if err != nil { return "", fmt.Errorf("無法打開文件:%v", err) } defer file.Close() // 創(chuàng)建MD5哈希器 hash := md5.New() // 將文件內(nèi)容復(fù)制到哈希器中 if _, err := io.Copy(hash, file); err != nil { return "", fmt.Errorf("計(jì)算MD5時(shí)出錯(cuò):%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 } // 對(duì)比結(jié)果 if md51 == md52 { fmt.Println("圖片完全相同") } else { fmt.Println("圖片不同") } }
代碼解讀:
- 我們定義了一個(gè)
calculateMD5
函數(shù),傳入文件路徑,返回計(jì)算出的 MD5 字符串。 - 函數(shù)中先打開文件,創(chuàng)建一個(gè) MD5 哈希器
hash
。 - 通過
io.Copy
將文件內(nèi)容寫入哈希器中,計(jì)算出 MD5 值。 - 最后將 MD5 字節(jié)數(shù)組格式化為字符串返回。
- 在
main
函數(shù)中,我們計(jì)算兩個(gè)圖片文件的 MD5 值,比對(duì)它們是否相等,輸出結(jié)果。
MD5 比對(duì)的特點(diǎn):
- 速度快、計(jì)算簡單
- 可精確判斷兩個(gè)文件是否完全相同(只要是文件,都可以通過這種方式進(jìn)行判斷是否一樣)
- 無法檢測內(nèi)容相似但不完全相同的圖片
- 圖片稍有改動(dòng)(如添加水印)就會(huì)導(dǎo)致 MD5 值完全不同
所以 MD5 比對(duì)適合用于檢測完全相同的圖片,如文件去重等場景。如果兩張圖片只是稍作修改(如調(diào)整亮度、旋轉(zhuǎn)等),MD5 就無能為力了。
方法二:圖像哈希對(duì)比
圖像哈希(Image Hashing)是一類可以比較圖片相似程度的算法。其基本原理是:將圖片縮小、簡化為一個(gè)哈希值,然后比較不同圖片哈希值的差異度,來判斷它們的相似程度。
常見的圖像哈希算法有:
- 平均哈希(Average Hash)
- 感知哈希(Perceptual Hash)
- 差異哈希(Difference Hash)
- 小波哈希(Wavelet Hash)
這里我們以第三方包為例:
首先先安裝這個(gè)包
go get github.com/corona10/goimagehash
然后我們來嘗試實(shí)現(xiàn)一個(gè)圖片相似度比對(duì):
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) } // 計(jì)算差異哈希 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) } // 計(jì)算漢明距離 avgDistance, err := avgHash1.Distance(avgHash2) if err != nil { return fmt.Errorf("計(jì)算平均哈希距離失?。?v", err) } diffDistance, err := diffHash1.Distance(diffHash2) if err != nil { return fmt.Errorf("計(jì)算差異哈希距離失敗:%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("圖片對(duì)比出錯(cuò):", err) } }
圖像哈希的特點(diǎn):
- 可以比較圖片內(nèi)容的相似程度
- 對(duì)圖片的縮放、旋轉(zhuǎn)、亮度變化等稍微魯棒
- 計(jì)算難度適中,可應(yīng)用于相似圖片搜索等場景
- 仍無法識(shí)別完全不同但語義相似的圖片(比如同一物體不同角度的照片)
它們各有特點(diǎn)和適用場景:
MD5指紋:簡單快速,適合精確匹配完全相同的圖片。 圖像哈希:可以比較圖片的相似程度,在相似圖片搜索等場景下很有用。
當(dāng)然,這只是圖像相似度算法的冰山一角。在實(shí)際應(yīng)用中,我們還需要考慮性能、精度、復(fù)雜度等因素,選擇最適合的方案。
圖像識(shí)別領(lǐng)域在不斷發(fā)展,一些前沿技術(shù)如機(jī)器學(xué)習(xí)、深度神經(jīng)網(wǎng)絡(luò)等,為圖片相似度判斷帶來了更多的可能性,值得我們?nèi)W(xué)習(xí)和探索。
到此這篇關(guān)于Go語言如何判斷兩張圖片的相似度的文章就介紹到這了,更多相關(guān)Go判斷圖片相似度內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言k8s?kubernetes使用leader?election實(shí)現(xiàn)選舉
這篇文章主要為大家介紹了Go語言?k8s?kubernetes?使用leader?election選舉,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10golang使用iconv報(bào)undefined:XXX的問題處理方案
這篇文章主要介紹了golang使用iconv報(bào)undefined:XXX的問題處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03Go語言標(biāo)準(zhǔn)庫sync.Once使用場景及性能優(yōu)化詳解
這篇文章主要為大家介紹了Go語言標(biāo)準(zhǔn)庫sync.Once使用場景及性能優(yōu)化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12Go語言封裝一個(gè)Cron定時(shí)任務(wù)管理器
在現(xiàn)代應(yīng)用中,定時(shí)任務(wù)是非常常見的需求,無論是用于定時(shí)清理數(shù)據(jù),還是定時(shí)執(zhí)行系統(tǒng)維護(hù)任務(wù),下面我們就來使用Go語言封裝一個(gè)Cron定時(shí)任務(wù)管理器吧2024-12-12