|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
- from tkinter import *
- import cv2
- from webbrowser import open as webopen
- import numpy as np
- from threading import Thread
- from multiprocessing.dummy import Pool
- from os import listdir, mkdir, remove, startfile, getcwd
- from os.path import isdir, isfile, join, exists
- from tkinter import filedialog
- from windnd import hook_dropfiles
- from PIL import Image, ImageTk
- from tkinter.messagebox import showinfo, askyesno
- from shutil import copy
- from skimage import io
- from pickle import dump, load
- from time import time
- class APP:
- def __init__(self):
- self.root = Tk()
- self.root.geometry('450x430')
- self.root.title('星猫搜图~')
- self.imgnum = 0 #用于判断文件夹内图片个数
- self.if_change = 0 #判断图片数量是否变化
- self.file = ''
- self.hashdic = {}
- self.img11 = 0
- self.num111 = 0
- self.badimg = 0
- self.badimglist = []
- self.msg1 = StringVar(value=r'C:\Users\陈东豪\Desktop')
- self.if_top123 = 0
- self.filelist = []
- self.initimg = []
- self.pk_file = 'hashֵ.pk'
- if not isfile(self.pk_file):
- with open(self.pk_file, 'wb') as (f):
- dump(self.hashdic, f)
- with open(self.pk_file, 'rb') as (b):
- self.hashdic = load(b)
- def wait(self):
- """等候时打开页面,显示加载过程"""
- self.wait1 = Label((self.root), text='请稍等...')
- def main(self):
- Label((self.root), text='img文件路径:').grid(row=0, column=0)
- self.hostVar = StringVar(value=r'C:\Users\Administrator\Desktop')
- self.numVar = StringVar(self.root, str(len(self.filelist)) + '张')
- self.filename = Entry((self.root), textvariable=(self.hostVar))
- self.filename.grid(row=0, column=1)
-
- self.bt = Button((self.root), text='确定', command=self.change_lujing)
- self.bt.grid(row=0, column=2)
- self.lb4 = Label((self.root), textvariable=(self.numVar))
- self.lb4.grid(row=0, column=3)
- self.bt2 = Button((self.root), text='打开目标img文件夹', command=(self.open_lujing))
- self.bt2.grid(row=1, column=0)
- self.bt4 = Button((self.root), text='此次查找详情', command=lambda:self.show_init(self.initimg))
- self.bt4.grid(row=1, column=1)
- self.bt5 = Button((self.root), text='打开星猫图片', command=(self.open_files))
- self.bt5.grid(row=1, column=3)
- self.bt6 = Button((self.root), text='查看损坏img', command=(self.see_badimg))
- self.bt6.grid(row=1, column=2)
- self.balloon = Label(self.root)
- self.bt.bind('<Button-3>', self.chose_dir)
- self.bt.bind('<Enter>', lambda event: self.Balloon_show(event, msg='单击鼠标右键打开文件选择框!', fg='blue'))
- self.bt5.bind('<Enter>', lambda event: self.Balloon_show(event, msg='双击鼠标右键打开百度搜图\n[url]https://graph.baidu.com/pcpage/index?tpl_from=pc'[/url], fg='blue'))
- self.root.bind('<Leave>', self.Balloon_destroy)
- self.root.bind('<Double-Button-3>', self.baidu)
- hook_dropfiles(self.root, func=self.dragged_files) #当拖入文件时触发
- self.change_lujing()
- self.display_num()
- self.root.mainloop()
-
-
-
- def show_init(self,filename):
- '''展示目标img信息'''
- file_msg = '\n'.join((item for item in filename))
- showinfo(title='提示', message=('总共有' + str(len(filename)) + '张相似图片!\n相似度为' +\
- str(100 - self.min_) + '\n' + file_msg + '\n损坏图片:' + str(self.badimg) + \
- '张\n共耗时:' + str(self.t) + 's'))
-
- def Balloon_destroy(self, event):
- """隐藏气泡ʾ"""
- try:
- self.balloon.place_forget()
- except:
- pass
- def Balloon_show(self, event, msg, fg=None, bg=None, font=('微软雅黑', 10, 'bold')):
- try:
- self.balloon.place_forget()
- except:
- pass
- else:
- self.balloon['fg'] = fg
- self.balloon['bg'] = bg
- self.balloon['text'] = msg
- self.balloon['font'] = font
- self.balloon.place(x=35, y=190)
- def baidu(self, event):
- """百度搜图"""
- webopen('https://graph.baidu.com/pcpage/index?tpl_from=pc')
- def chose_dir(self, event):
- file = filedialog.askopenfilename()
- if file != '':
- file1 = file.rsplit('/', 1)[0]
- self.hostVar.set(file1)
- self.change_lujing()
- def open_lujing(self, *args):
- """打开目标img文件夹"""
- if len(self.initimg) == 0:
- showinfo(title='提示', message='无目标img!')
- else:
- files = []
- for each in self.initimg:
- files.append(each.rsplit('\\', 1)[0])
- else:
- files = list(set(files))
- for each in files:
- startfile(each)
- def open_files(self, *args):
- """打开文件夹"""
- fname = getcwd() + '//星猫图片'
- startfile(fname)
- def see_badimg(self, *args):
- """损坏badimg"""
- if len(self.badimglist) == 0:
- showinfo(title='提示', message='没有badimg!')
- else:
- msg = '\n'.join(self.badimglist)
- showinfo('badimg路径', msg)
- if askyesno('警告', '是否删除损坏imgs?'):
- for each in self.badimglist:
- try:
- remove(each)
- self.badimglist.remove(each)
- except Exception as e:
- showinfo(title='提示', message=e)
- def display_num(self):
- """提示图片数量, 判断图片个数是否不再改变"""
- num = len(self.filelist)
- self.numVar.set(str(num) + '张')
- if self.imgnum!=num:
- self.imgnum = num
- self.if_change = 1
- else:
- if self.if_change:
- #如果变化停止则开始计算hash值
- self.if_change = 0
- self.pool_map(self.compute_hash,self.filelist)
- # showinfo('提示','开始计算图片hash值啦!')
- self.root.after(1000, self.display_num)
- def change_lujing(self):
- """更改搜图路径"""
- self.file = self.filename.get()
- if isdir(self.file):
- pass
- else:
- lujing = getcwd()
- self.hostVar.set(lujing)
- self.file = self.filename.get()
- self.filelist = []
- self.thread_it(self.getFileList, self.file, self.filelist)
- def pool_map(self, func, *args):
- """多进程"""
- pool = Pool()
- pool.map_async(func, args)
- pool.close()
- pool.join()
- def getFileList(self, dir, imglist, ext=['jpg', 'png', 'jpeg', 'bmp', 'webp']):
- """
- 获取文件夹及其子文件夹中图片列表
- 输入 dir:文件夹根目录
- 输入 ext: 扩展名
- 返回: 文件路径列表
- """
- newDir = dir
- if isfile(dir):
- if dir.rsplit('.', 1)[(-1)] in ext:
- imglist.append(dir)
- elif isdir(dir):
- try:
- for s in listdir(dir):
- newDir = join(dir, s)
- self.getFileList(newDir, imglist, ext)
- except Exception as e:
- print(s,'\n',e)
- return imglist
- #打开指定的图片,缩放到指定尺寸
- def get_img(self,filename,width=445,height=365):
- try:
- im = Image.open(filename).resize((width,height))
- # 引用:添加一个Label,用来存储图片。使用PanedWindow也行。
- panel = Label(master=self.root)
- panel.photo = ImageTk.PhotoImage(im) # 将原本的变量photo改为panel.photo
- return panel.photo
- except:
- return 0
- def compute_hash(self,imgname):
- '''专门用于计算大规模计算hash值'''
- if imgname not in self.hashdic:
- img2_ = self.cv_imread(imgname)
- hash2 = self.aHash(img2_, imgname)
- if hash2 != 0:
- self.hashdic[str(imgname)] = hash2
-
- def dragged_files(self, files):
- """拖拽图片"""
- sum_msg2 = [item.decode('gbk') for item in files]
- for sum_msg in sum_msg2:
- ext1 = sum_msg.rsplit('.', 1)[(-1)]
- try:
- self.img.destroy()
- except:
- pass
-
- if ext1 in ('jpg', 'png', 'jpeg', 'bmp', 'ico', 'webp'):
- if ext1 == 'ico':
- showinfo('提示', '暂不支持ico格式图片搜索!')
- else:
- image1 = self.get_img(sum_msg)
- if image1 != 0:
- self.img = Label((self.root), image=image1)
- self.img.grid(row=2, columnspan=4)
- self.imgdict = {} #用来保存图片相似度
- self.thread_it(self.Compare2, sum_msg)
- else:
- showinfo('提示',sum_msg+'\n该图片有问题!')
-
- else:
- showinfo(title='提示', message=('暂不支持当前格式搜索!(' + str(ext1) + ')'))
- def Compare2(self, img):
- '''开始搜索相似图片ing'''
- t1 = time()
- img1 = self.cv_imread(img)
- self.hash1 = self.aHash(img1,img)
- if self.hash1 == 0:
- showinfo('提示', '此图片损坏,请更换其他图片!')
- else:
- # self.pool_map(self.compare, self.filelist)
- #使用多进程加速
- pool = Pool()
- pool.map_async(self.compare, self.filelist)
- pool.close()
- pool.join()
- try:
- self.min_ = min(self.imgdict.values())
- min_key = [i for i in self.imgdict.keys() if self.imgdict[i] == self.min_]
- self.initimg = min_key
- if not exists('星猫图片'):
- mkdir('星猫图片')
- for each_img in min_key:
- try:
- copy(each_img, './/星猫图片')
- except:
- pass
- if self.min_ == 0:
- file_img = []
- file_img.append(min_key[0])
- self.show_img1(file_img)
- else:
- self.show_img1(min_key)
- with open(self.pk_file, 'wb') as (f):
- dump(self.hashdic, f)
- t2 = time()
- self.t = t2 - t1
- except:
- showinfo('提示', '无相关图片!')
- def show_msg(self, title1='提示', msg='呱呱呱!', ms=0, fontbig=20):
- """显示消息"""
- if msg != self.msg1:
- self.msg1.set(msg)
- if not self.if_top123:
- self.top123 = Toplevel()
- self.top123.title(title1)
- self.top123.protocol('WM_DELETE_WINDOW', self.destroytop)
- msg1 = Label((self.top123), textvariable=(self.msg1), font=('微软雅黑', fontbig, 'bold'))
- msg1.pack()
- if ms != 0:
- self.top123.after(ms, self.destroytop)
- def destroytop(self):
- """关闭窗口"""
- self.top123.destroy()
- self.if_top123 = 0
- def show_img1(self, filename=[], ms=4500, num=0):
- """可切换显示多张照片"""
- try:
- if not self.img11:
- self.top11 = Toplevel()
- self.top11.title('星猫图片浏览~')
- self.top11.geometry('640x400')
- self.top11.protocol('WM_DELETE_WINDOW', lambda : self.closeimg(filename))
- self.img11 = 1
- self.img2 = Label((self.top11), image=(self.get_img(filename[num], 640, 400)))
- self.img2.pack()
- else:
- self.img2.destroy()
- self.img2 = Label((self.top11), image=(self.get_img(filename[num], 640, 400)))
- self.img2.pack()
- num += 1
- self.top11.after(3000, self.show_img1, filename, ms, num)
- except:
- self.closeimg(filename)
- def closeimg(self, filename):
- """窗口关闭时触发"""
- self.img11 = 0
- self.top11.destroy()
- def thread_it(self, func, *args):
- """多线程"""
- t = Thread(target=func, args=args)
- t.setDaemon(True)
- t.start()
- #差值感知算法
- def aHash(self,img,imgname,if_shishi=0):
- '''img:图片矩阵,imgname:图片名字,if_shishi是否'''
- try:
- #缩放8*9
- img1=cv2.resize(img,(9,8),interpolation=cv2.INTER_CUBIC)
- #转换灰度图
- gray=cv2.cvtColor(img1,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
- except:
- '''如果打开图片失败,就重新保存试一试'''
- if not if_shishi:
- '''如果是第一次失败,则重试'''
- try:
- image = io.imread(imgname)
- image = cv2.cvtColor(image, cv2.COLOR_RGBA2BGRA)
- cv2.imencode(imgname.rsplit('.',1)[-1],image)[1].tofile(imgname)
- return self.aHash(image,imgname,1)
- except:
- print(imgname,'打开失败!')
- self.badimg+=1
- return 0
- else:
- '''表示获取hash失败!'''
- return 0
-
- def cmpHash(self, hash1, hash2):
- n = 0
- if len(hash1) != len(hash2):
- return -1
- for i in range(len(hash1)):
- if hash1[i] != hash2[i]:
- n = n + 1
- return n
- def cv_imread(self, filePath):
- cv_img = cv2.imdecode(np.fromfile(filePath, dtype=(np.uint8)), -1)
- return cv_img
- def compare(self, img2):
- '''比较图片相似度并保存相似度n1'''
- imgname = img2
- try:
- if str(imgname) in self.imgdict:
- pass
- elif str(imgname) not in self.hashdic:
- img2_ = self.cv_imread(img2)
- hash2 = self.aHash(img2_, imgname=img2)
- if hash2 != 0:
- self.hashdic[str(imgname)] = hash2
- n1 = self.cmpHash(self.hash1, self.hashdic[str(imgname)])
- if n1 != (-1):
- self.imgdict[str(imgname)] = n1
- elif n1 == 0:
- self.num111+=1
- else:
- n1 = self.cmpHash(self.hash1, self.hashdic[str(imgname)])
- if n1 != (-1):
- self.imgdict[str(imgname)] = n1
- elif n1 == 0:
- self.num111+=1
- # print(n1)
- except Exception as e:
- print(e)
- if __name__ == '__main__':
- a = APP()
- a.main()
复制代码
|
-
代码运行效果
评分
-
参与人数 3 | 荣誉 +5 |
鱼币 +4 |
贡献 +5 |
收起
理由
|
Hello.
| + 1 |
|
+ 1 |
鱼C有你更精彩^_^ |
逃兵
| + 2 |
+ 2 |
+ 2 |
鱼C有你更精彩^_^ |
小甲鱼
| + 2 |
+ 2 |
+ 2 |
鱼C有你更精彩^_^ |
查看全部评分
|