核心算法:
一、分別自定義三種計算圖片相似度算法
1)計算圖片相似度算法ORB算法
優點:
ORB 特徵具有以下優點:
1、特徵提取速度快;
2、在大多數情況下,去重效果能夠與 SIFT/SURF 持平;
3、提取的特徵直接是二元編碼形式,無需使用哈希學習方法就可以直接利用漢明距離快速計算相似度。
參考【python 圖像相似度】OpenCV圖像相似度ORB算法--相似圖像去重
https://blog.csdn.net/u013421629/article/details/87364489
2)局部敏感哈希phash算法
參考:文檔的相似度(3)--局部敏感哈希算法 分析的很透徹
https://blog.csdn.net/qq_29883591/article/details/63686371
3)傳統的直方圖計算相似度算法
參考:圖像處理之相似圖片識別(直方圖應用篇)
https://blog.csdn.net/jia20003/article/details/7771651
2、定義融合相似度閾值爲0.70,若三種算法計算出來的相似度最大值大於等於0.70,則取最大值爲融合算法之後的相似度。
否則,則取三種算法計算出來的相似度的最小值,作爲融合算法的之後的相似度。
3、定義最終相似度較高判斷閾值爲0.95,若融合之後的相似度值達到0.95,則認爲圖片非常相似。
4、圖片相似的圖片複製到一個文件夾下。
以下爲具體實現
函數文件 image_similarity_function.py
# -*- encoding=utf-8 -*-
# 導入包
import cv2
from functools import reduce
from PIL import Image
# 計算兩個圖片相似度函數ORB算法
def ORB_img_similarity(img1_path,img2_path):
"""
:param img1_path: 圖片1路徑
:param img2_path: 圖片2路徑
:return: 圖片相似度
"""
try:
# 讀取圖片
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
# 初始化ORB檢測器
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# 提取並計算特徵點
bf = cv2.BFMatcher(cv2.NORM_HAMMING)
# knn篩選結果
matches = bf.knnMatch(des1, trainDescriptors=des2, k=2)
# 查看最大匹配點數目
good = [m for (m, n) in matches if m.distance < 0.75 * n.distance]
similary = len(good) / len(matches)
return similary
except:
return '0'
# 計算圖片的局部哈希值--pHash
def phash(img):
"""
:param img: 圖片
:return: 返回圖片的局部hash值
"""
img = img.resize((8, 8), Image.ANTIALIAS).convert('L')
avg = reduce(lambda x, y: x + y, img.getdata()) / 64.
hash_value=reduce(lambda x, y: x | (y[1] << y[0]), enumerate(map(lambda i: 0 if i < avg else 1, img.getdata())), 0)
return hash_value
#計算兩個圖片相似度函數局部敏感哈希算法
def phash_img_similarity(img1_path,img2_path):
"""
:param img1_path: 圖片1路徑
:param img2_path: 圖片2路徑
:return: 圖片相似度
"""
# 讀取圖片
img1 = Image.open(img1_path)
img2 = Image.open(img2_path)
# 計算漢明距離
distance = bin(phash(img1) ^ phash(img2)).count('1')
similary = 1 - distance / max(len(bin(phash(img1))), len(bin(phash(img1))))
return similary
# 直方圖計算圖片相似度算法
def make_regalur_image(img, size=(256, 256)):
"""我們有必要把所有的圖片都統一到特別的規格,在這裏我選擇是的256x256的分辨率。"""
return img.resize(size).convert('RGB')
def hist_similar(lh, rh):
assert len(lh) == len(rh)
return sum(1 - (0 if l == r else float(abs(l - r))/max(l, r)) for l, r in zip(lh, rh))/len(lh)
def calc_similar(li, ri):
return sum(hist_similar(l.histogram(), r.histogram()) for l, r in zip(split_image(li), split_image(ri))) / 16.0
def calc_similar_by_path(lf, rf):
li, ri = make_regalur_image(Image.open(lf)), make_regalur_image(Image.open(rf))
return calc_similar(li, ri)
def split_image(img, part_size = (64, 64)):
w, h = img.size
pw, ph = part_size
assert w % pw == h % ph == 0
return [img.crop((i, j, i+pw, j+ph)).copy() for i in range(0, w, pw) \
for j in range(0, h, ph)]
————————————————
版權聲明:本文爲CSDN博主「開心果汁」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u013421629/article/details/87697794
實現文件:new_similarity_compare.py
# -*- encoding=utf-8 -*-
from similarity.image_similarity_function import *
import os
import shutil
# 融合相似度閾值
threshold1 = 0.70
# 最終相似度較高判斷閾值
threshold2 = 0.95
# 融合函數計算圖片相似度
def calc_image_similarity(img1_path,img2_path):
"""
:param img1_path: filepath+filename
:param img2_path: filepath+filename
:return: 圖片最終相似度
"""
similary_ORB=float(ORB_img_similarity(img1_path,img2_path))
similary_phash=float(phash_img_similarity(img1_path,img2_path))
similary_hist=float(calc_similar_by_path(img1_path, img2_path))
# 如果三種算法的相似度最大的那個大於0.7,則相似度取最大,否則,取最小。
max_three_similarity=max(similary_ORB,similary_phash,similary_hist)
min_three_similarity=min(similary_ORB,similary_phash,similary_hist)
if max_three_similarity>threshold1:
result=max_three_similarity
else:
result=min_three_similarity
return round(result,3)
if __name__ == '__main__':
# 搜索文件夾
filepath = 'D:/test/'
# 相似圖片存放路徑
newfilepath = 'F:/same_pic_new/'
for parent, dirnames, filenames in os.walk(filepath):
for srcfilename in filenames:
img1_path = filepath + srcfilename
for parent, dirnames, filenames in os.walk(filepath):
for filename in filenames:
# 全量的比對效率差,所以形成圖片時在名稱上做了標記,下劃線後面相同的進行比對
name1 = srcfilename.split('_')[1]
# 第二張照片對應的標記
name2 = filename.split('_')[1]
img2_path = filepath + filename
# 取兩張照片是否是同名
if name1 == name2 :
# 相同非同一張圖片的則比較
if img1_path != img2_path:
kk = calc_image_similarity(img1_path, img2_path)
try:
if kk >= threshold2:
# 將兩張照片同時拷貝到指定目錄(存在冗餘操作,待優化)
shutil.copy(img1_path, newfilepath)
shutil.copy(img2_path, newfilepath)
except Exception as e:
# print(e)
pass
以上功能可以實現對指定文件夾下所有具有相同標記的照片進行相似度的比對,並將比對的結果輸出到指定路徑。
初涉圖像比對還有很多不足指出,希望大神指教!
感謝以下博主的文章:
【python 以圖搜圖】三種圖片相似度計算融合算法
原文鏈接:https://blog.csdn.net/u013421629/article/details/87697794
參考:圖像處理之相似圖片識別(直方圖應用篇)
https://blog.csdn.net/jia20003/article/details/7771651
參考:文檔的相似度(3)--局部敏感哈希算法 分析的很透徹
https://blog.csdn.net/qq_29883591/article/details/63686371
參考【python 圖像相似度】OpenCV圖像相似度ORB算法--相似圖像去重
https://blog.csdn.net/u013421629/article/details/87364489