GUI和opencv实现余弦哈希算法图像相似匹配系统
发布时间
阅读量:
阅读量
该系统基于GUI设计,使用Python实现图像相似匹配功能。通过均值哈希、差值哈希和cos相似度算法计算图像相似度,并通过UI显示匹配结果。系统支持上传多张图像,自动计算并展示前三个最相似的图像,适合图像检索和匹配应用。
项目展示与讲解:基于GUI的OpenCV余弦哈希算法实现图像相似匹配系统
本博客付完整的代码数据:

import os
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import numpy as np
import cv2
# 环境配置 python 3.7 ,opencv-python==4.1.2.30
# pip install opencv-python==4.1.2.30 -i https://pypi.tuna.tsinghua.edu.cn/simple
class ImageMatcher(tk.Frame):
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
self.master = master
self.create_widgets()
def create_widgets(self):
# 创建左半部分控件
self.left_frame = tk.Frame(self)
self.left_frame.pack(side='left', fill='both', expand=True)
self.image_frame = tk.Frame(self.left_frame, bg='gray')
self.image_frame.pack(side='top', fill='both', expand=True, padx=10, pady=10)
self.upload_button = tk.Button(self.left_frame, text='上传图像', command=self.load_image)
self.upload_button.pack(side='left', padx=10, pady=10)
self.match_button = tk.Button(self.left_frame, text='图像匹配', command=self.match_images)
self.match_button.pack(side='left', padx=10, pady=10)
# 创建右半部分控件
self.right_frame = tk.Frame(self)
self.right_frame.pack(side='left', fill='both', expand=True)
self.image1_frame = tk.Frame(self.right_frame, bg='gray')
self.image1_frame.pack(side='top', fill='both', expand=True, padx=10, pady=10)
self.similarity1_label = tk.Label(self.right_frame, text='相似度:0.00')
self.similarity1_label.pack(side='top', padx=10, pady=10)
self.image2_frame = tk.Frame(self.right_frame, bg='gray')
self.image2_frame.pack(side='top', fill='both', expand=True, padx=10, pady=10)
self.similarity2_label = tk.Label(self.right_frame, text='相似度:0.00')
self.similarity2_label.pack(side='top', padx=10, pady=10)
self.image3_frame = tk.Frame(self.right_frame, bg='gray')
self.image3_frame.pack(side='top', fill='both', expand=True, padx=10, pady=10)
self.similarity3_label = tk.Label(self.right_frame, text='相似度:0.00')
self.similarity3_label.pack(side='top', padx=10, pady=10)
def load_image(self):
# 打开文件选择对话框,选择要上传的图像文件
filetypes = (("JPEG files", "*.jpg"), ("PNG files", "*.png"))
self.imgName = filedialog.askopenfilename(title="选择图像文件", filetypes=filetypes)
# 如果选择了文件,则使用 PIL 库打开并显示图像
if self.imgName:
# 清除先前显示的图像
self.clear_images()
image = Image.open(self.imgName)
image = self.resize_image(image, self.image_frame.winfo_width(), self.image_frame.winfo_height())
photo = ImageTk.PhotoImage(image)
self.image_label = tk.Label(self.image_frame, image=photo)
self.image_label.pack(side='top', fill='both', expand=True)
self.image_label.image = photo # 保持对 PhotoImage 对象的引用,以免被 Python 的垃圾回收机制销毁
def match_images(self):
# 如果没有上传图像,则不执行匹配操作
if not hasattr(self, 'image_label'):
return
# 加载所有图像文件,并使用 OpenCV 库计算它们与上传的图像的相似度
folder = os.path.dirname(self.imgName)
filenames = os.listdir(folder)
filenames = [f'{folder}/{f}' for f in filenames if f.endswith('.jpg') or f.endswith('.png')]
filenames.remove(self.imgName)
similarities1 = []
similarities2 = []
similarities3 = []
for filename in filenames:
print("filename:",filename)
similarity_1,similarity_2,similarity_3 = self.calculate_similarity(self.imgName, filename)
similarities1.append((filename, similarity_1))
similarities2.append((filename, similarity_2))
similarities3.append((filename, similarity_3))
# 根据相似度从高到低排序,并取出前三个最相似的图像
similarities1.sort(key=lambda x: x[1], reverse=False)
similarities2.sort(key=lambda x: x[1], reverse=False)
similarities3.sort(key=lambda x: x[1], reverse=True)# 这个没问图
top_similarities = [similarities1[0],similarities2[0],similarities3[0]]
# 在右半部分的三个区域中分别显示这三张图像
for i, (filename, similarity) in enumerate(top_similarities):
image = Image.open(filename)
image = self.resize_image(image, self.image1_frame.winfo_width(), self.image1_frame.winfo_height())
photo = ImageTk.PhotoImage(image)
label = tk.Label(self.right_frame, image=photo)
label.image = photo
if i == 0:
label.pack(in_=self.image1_frame, side='top', fill='both', expand=True)
self.similarity1_label.config(text=f'均值哈希算法相似度:{similarity:.2f}')
elif i == 1:
label.pack(in_=self.image2_frame, side='top', fill='both', expand=True)
self.similarity2_label.config(text=f'差值哈希算法相似度:{similarity:.2f}')
elif i == 2:
label.pack(in_=self.image3_frame, side='top', fill='both', expand=True)
self.similarity3_label.config(text=f'cos相似度算法相似度:{similarity:.2f}')
def clear_images(self):
# 清除左半部分中的图像和右半部分中的标注
if hasattr(self, 'image_label'):
self.image_label.pack_forget()
del self.image_label
for label in [self.similarity1_label, self.similarity2_label, self.similarity3_label]:
label.config(text='相似度:0.00')
for frame in [self.image1_frame, self.image2_frame, self.image3_frame]:
for widget in frame.winfo_children():
widget.pack_forget()
def resize_image(self, image, width, height):
# 将图像按照指定的宽度和高度等比例缩放
w, h = image.size
ratio = min(width / w, height / h)
size = (int(w * ratio), int(h * ratio))
return image.resize(size)
def dHash(self,img):
# 缩放8*8
img = cv2.resize(img, (9, 8), interpolation=cv2.INTER_CUBIC)
# 转换灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hash_str = ''
# 每行前一个像素大于后一个像素为1,相反为0,生成哈希
for i in range(8):
for j in range(8):
if gray[i, j] > gray[i, j + 1]:
hash_str = hash_str + '1'
else:
hash_str = hash_str + '0'
return hash_str
def aHash(self,img):
# 缩放为8*8
img = cv2.resize(img, (8, 8), interpolation=cv2.INTER_CUBIC)
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# s为像素和初值为0,hash_str为hash值初值为''
s = 0
hash_str = ''
# 遍历累加求像素和
for i in range(8):
for j in range(8):
s = s + gray[i, j]
# 求平均灰度
avg = s / 64
# 灰度大于平均值为1相反为0生成图片的hash值
for i in range(8):
for j in range(8):
if gray[i, j] > avg:
hash_str = hash_str + '1'
else:
hash_str = hash_str + '0'
return hash_str
def cmpHash(self,hash1, hash2):
n = 0
# hash长度不同则返回-1代表传参出错
if len(hash1) != len(hash2):
return -1
# 遍历判断
for i in range(len(hash1)):
# 不相等则n计数+1,n最终为相似度
if hash1[i] != hash2[i]:
n = n + 1
return n
def calculate_similarity(self, image1, image2):
image1=image1.split("/")[-2]+"/"+image1.split("/")[-1]
image2=image2.split("/")[-2]+"/"+image2.split("/")[-1]
print("image1:", image1)
print("image2:", image2)
# 方法1 均值哈希算法相似度 计算两张图像的相似度
img1 = cv2.imread(image1)
img2 = cv2.imread(image2)
hash1 = self.aHash(img1)
hash2 = self.aHash(img2)
similarity_1= self.cmpHash(hash1, hash2)
# 方法2 差值哈希算法相似度 计算两张图像的相似度
hash1 = self.dHash(img1)
hash2 = self.dHash(img2)
similarity_2= self.cmpHash(hash1, hash2)
# 方法3 计算两张图像的相似度
print("image1, image2:",image1, image2)
image1 = np.array(Image.open(image1))
image2 = np.array(Image.open(image2))
arr1_flat = image1.reshape(-1)
arr2_flat = image2.reshape(-1)
num_equal = np.sum(arr1_flat == arr2_flat)
similarity_3 = num_equal / len(arr1_flat)
print('均值哈希算法相似度:', similarity_1,'差值哈希算法相似度:', similarity_2,"np.sum:",similarity_3)
return similarity_1/100,similarity_2/100,similarity_3
# print("111")
# orb = cv2.ORB_create()
# keypoints1, descriptors1 = orb.detectAndCompute(image1, None)
# keypoints2, descriptors2 = orb.detectAndCompute(image2, None)
#
# if len(keypoints1) == 0 or len(keypoints2) == 0:
# return 0
# bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# matches = bf.match(descriptors1, descriptors2)
# matches = sorted(matches, key=lambda x: x.distance)
# num_matches = min(len(matches), 100)
# similarity = sum([matches[i].distance for i in range(num_matches)]) / num_matches
# return similarity
if __name__ == '__main__':
root = tk.Tk()
root.geometry('1000x600+400+200')
root.title('图像匹配系统')
app = ImageMatcher(master=root)
app.pack(fill='both', expand=True)
root.mainloop()
完整代码数据“:
(117份消息内容) 基于图形用户界面的图像相似匹配系统资源-文库
全部评论 (0)
还没有任何评论哟~
