【python工具开发笔记】基于tkinter比较筛选目录下是否存在相同图片

26 篇文章 1 订阅
20 篇文章 0 订阅

筛选目录下所有图片,是否有相同的图片存在,存在的话打印出相同的两张图的具体路径。

成品界面如下(MAC和windows版本界面是一样):

首先是先拿到路径下所有的图片,对比图片的相似度,经过百度有可以直接引用一个python的hash算法进行比较,传入图片路径和设定误差值即可。将相同的图片信息存在txt文件中用来保存。

考虑到路径下可能存在多个文件夹嵌套、图片名字相同的情况,传入hash算法的文件名必须是带路径的,否则只能检测当前目录下的图片,并不能遍历到子文件夹中。

大概思路如下:

1. 获取所有文件名(带路径)

com_path = [""]
def get_all(path):
	paths = os.listdir(path) # 列出指定路径下的所有目录和文件
	for i in paths:
		com_path = os.path.join(path,i)
		if os.path.isdir(com_path):
			get_all(com_path) # 如果该路径是目录,则调用自身方法
		elif os.path.isfile(com_path):
			if com_path.split(".")[-1] in ['jpg','png','bmp']:
				com_path_T = {com_path.split('\\')[-1]:com_path}
				compath.update(com_path_T)

用递归遍历获取所有带路径的文件名,将文件名和带路径的文件名存入字典中。开始考虑用列表存,但是在通过append函数循环添加时,参数是list时报错,所有就用的字典存放,后面查询也方便

2. 通过字符串切片用"."进行分割出后缀,即文件格式得到所有的图片

3. 拿到所有图片并带路径,循环两两比较图片,调用比较函数

hash算法比较图片函数(传入图片路径可直接使用):

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
	ImageFile.LOAD_TRUNCATED_IMAGES = True
	hash_1 = None
	hash_2 = None
	image_file1 = open(image_file_name_1,'rb').read()
	Has = hashlib.md5(image_file1).hexdigest()
	image_file2 = open(image_file_name_2,'rb').read()
	Has1 = hashlib.md5(image_file2).hexdigest()
	if image_file1 != image_file2:
		return False
	with open(image_file_name_1, 'rb') as fp:
		hash_1 = imagehash.average_hash(Image.open(fp))
	with open(image_file_name_2, 'rb') as fp:
		hash_2 = imagehash.average_hash(Image.open(fp))			#对比图片是否一样
	dif = hash_1 - hash_2
	if dif < 0:
		dif = -dif
	if dif <= max_dif:
		return True
	else:
		return False

函数compare_image_with_hash本身比较图片hash值的时候,发现对于一个图只改变了颜色,hash值是不变的,因此需要用image_file2 = open(image_file_name_2,'rb').read()
    Has1 = hashlib.md5(image_file2).hexdigest()加以判断。

4. 关于Windows打包,比较简单:

-c显示命令行窗口与-w相反,默认含有此参数
-w不显示命令行窗口编写GUI程序时使用此参数有用。
-F生成one-file的程序生成结果是一个exe文件,所有的第三方依赖、资源和代码均被打包进该exe内

出现上述问题,一般是因为磁盘不够运行导致的。跟打包的exe没有关系。

5. 关于Mac环境,遇到比较多的问题(打包app暂时没有解决):

首先装py2applet后,输入以下命令即可。打包前需要把第三方库,编辑setup.py手动添加第三方库。

py2applet   --make-setup  xxx.py

python setup.py py2app

6. 线程简单用法

def thread_it(func, *args):
  '''将函数放入线程中执行'''
  # 创建线程
  t = threading.Thread(target=func, args=args) 
  # 守护线程
  t.setDaemon(True) 
  # 启动线程
  t.start()

例如在按键启动线程执行函数:tkinter.Button(Root,text="开始查找",command=lambda :thread_it(getuser(函数名),函数参数)).pack()

7. tkinter基本用法

Root=tkinter.Tk() #创建Tk对象

Root.title("xxxxx") #设置窗口标题

Root.geometry("300x160+500+200") #设置窗口尺寸 

XX=tkinter.Label(Root,text="XXXXXXXX") #标签
XX.pack() #指定包管理器放置组件

该方法没有对位置进行设置,可以用label.place(x=20, y=20)进行位置设置。

--------------------------------------源码----------------------------------------------

#coding=utf-8
from tkinter import *
import tkinter as tk
from tkinter import Canvas as C
import tkinter,time,decimal,math,string
import tkinter.messagebox #这个是消息框,对话框的关键
import tkinter.font as tkFont
import os
from PIL import Image
from PIL import ImageFile

import imagehash
import threading
import hashlib

def thread_it(func, *args):
  '''将函数放入线程中执行'''
  # 创建线程
  t = threading.Thread(target=func, args=args) 
  # 守护线程
  t.setDaemon(True) 
  # 启动线程
  t.start()
def clear():
	if tkinter.messagebox.askokcancel('提示', '确认结束吗'):
		root.quit()
	
def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
	ImageFile.LOAD_TRUNCATED_IMAGES = True
	hash_1 = None
	hash_2 = None
	image_file1 = open(image_file_name_1,'rb').read()
	Has = hashlib.md5(image_file1).hexdigest()
	image_file2 = open(image_file_name_2,'rb').read()
	Has1 = hashlib.md5(image_file2).hexdigest()
	if image_file1 != image_file2:
		return False
	with open(image_file_name_1, 'rb') as fp:
		hash_1 = imagehash.average_hash(Image.open(fp))
	with open(image_file_name_2, 'rb') as fp:
		hash_2 = imagehash.average_hash(Image.open(fp))			#对比图片是否一样
	dif = hash_1 - hash_2
	if dif < 0:
		dif = -dif
	if dif <= max_dif:
		return True
	else:
		return False

com_path = [""]

compath = {}              #字典				
def get_all(path):
	#path =r'D:\Test3'
	paths = os.listdir(path) # 列出指定路径下的所有目录和文件
	for i in paths:
		com_path = os.path.join(path,i)
		# print(com_path)
		if os.path.isdir(com_path):
			get_all(com_path) # 如果该路径是目录,则调用自身方法
		elif os.path.isfile(com_path):
			#print(com_path.split(".")[-1])
			if com_path.split(".")[-1] in ['jpg','png','bmp','tif','gif','pcx','tga','exif','fpx','svg','psd','cdr','pcd','dxf','ufo','eps','ai','raw','WMF','webp','avif'
										   'JPG','PNG','BMP','TIF','GIF','PCX','TGA','EXIF','FPX','SVG','PSD','CDR','PCD','DXF','UFO','EPS','AI','RAW','WMF','WEBP','AVIF'
]:
				com_path_T = {com_path.split('\\')[-1]:com_path}
				compath.update(com_path_T)
				#print(com_path.split('\\')[-1],"======",com_path)
get_all(path=r'.')	
keyList = []
valueList = []
print(len(compath))
for key in compath.keys():
    keyList.append(key)
for value in compath.values():
    valueList.append(value)		
	
def getuser():
	line_new = open("test.txt",'w')
	FlagNum = 0
	strInfoT = "正在循环对比..."
	tkinter.Label(root,text=strInfoT).place(x=50, y=70)
	for i in range(0,len(valueList),1):
		strInfoNum = "已完成"+str(i+1)+"个..."
		tkinter.Label(root,text=strInfoNum).place(x=160, y=70)
		for j in range(1,len(valueList),1):
			if i!=j and i<j:
				if compare_image_with_hash(valueList[i],valueList[j],0) == True:
					FlagNum = 1
					line_new.write(valueList[i]+"和"+valueList[j]+"相同\n")
	line_new.close()				
	if FlagNum == 1:
		tkinter.messagebox.showwarning('警告','图片相同,相同照片以保持至根目录下的test.txt中,请确认!!')
	elif FlagNum == 0:
		tkinter.messagebox.showwarning('提示','当前路径下没有相同的图片!')
	else:
		tkinter.messagebox.showwarning('异常','异常情况!')	
root = tkinter.Tk()                     # 创建窗口对象的背景色
root.geometry("280x150+600+200")
root.title("图片筛查工具")
strInfo = "需要循环比较 "+str(len(compath))+" 个文件,请稍等!"
tkinter.Label(root,text=strInfo).place(x=50, y=40)
tkinter.Button(root,text="开始筛查",command=lambda :thread_it(getuser)).place(x=50, y=100)	 	#command绑定获取文本框内容方法
tkinter.Button(root,text="结束筛查",command= clear).place(x=170, y=100) 		#command绑定获取文本框内容方法
root.mainloop() #进入主循环


 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值