首页 > 编程语言 >Python用哈希算法查找相似图片(包括不同分辨率,不同大小,不同格式的图片)

Python用哈希算法查找相似图片(包括不同分辨率,不同大小,不同格式的图片)

时间:2023-04-21 17:11:23浏览次数:40  
标签:hash 不同 self cv2 shape 哈希 path os 图片

# -*- coding: utf-8 -*-
'''
Python用哈希算法查找相似图片并放入[_df]的文件夹中

相似图片包括不同分辨率,不同大小,不同格式,只要图片相似就会算重复文件


安装cv2
pip install opencv-python

'''
import os
import cv2
import numpy as np
import shutil
import random

class DuplicateFiles (object): 
    dir = ''
    def __init__(self, dir):
        self.dir = dir  # 实例属性

    # 均值哈希算法
    def aHash(self,img,shape=(10,10)):
        # 缩放为10*10
        img = cv2.resize(img, shape)
        # 转换为灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # s为像素和初值为0,hash_str为hash值初值为''
        s = 0
        hash_str = ''
        # 遍历累加求像素和
        for i in range(shape[0]):
            for j in range(shape[1]):
                s = s + gray[i, j]
        # 求平均灰度
        avg = s / 100
        # 灰度大于平均值为1相反为0生成图片的hash值
        for i in range(shape[0]):
            for j in range(shape[1]):
                if gray[i, j] > avg:
                    hash_str = hash_str + '1'
                else:
                    hash_str = hash_str + '0'
        return hash_str

    # 差值感知算法
    def dHash(self,img,shape=(10,10)):
        # 缩放10*11
        img = cv2.resize(img, (shape[0]+1, shape[1]))
        # 转换灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        hash_str = ''
        # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
        for i in range(shape[0]):
            for j in range(shape[1]):
                if gray[i, j] > gray[i, j + 1]:
                    hash_str = hash_str + '1'
                else:
                    hash_str = hash_str + '0'
        return hash_str

    # 感知哈希算法(pHash)
    def pHash(self,img,shape=(10,10)):
        # 缩放32*32
        img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBIC

        # 转换为灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 将灰度图转为浮点型,再进行dct变换
        dct = cv2.dct(np.float32(gray))
        # opencv实现的掩码操作
        dct_roi = dct[0:10, 0:10]

        hash = []
        avreage = np.mean(dct_roi)
        for i in range(dct_roi.shape[0]):
            for j in range(dct_roi.shape[1]):
                if dct_roi[i, j] > avreage:
                    hash.append(1)
                else:
                    hash.append(0)
        return hash

    # 通过得到RGB每个通道的直方图来计算相似度
    def classify_hist_with_split(self,image1, image2, size=(256, 256)):
        # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
        image1 = cv2.resize(image1, size)
        image2 = cv2.resize(image2, size)
        sub_image1 = cv2.split(image1)
        sub_image2 = cv2.split(image2)
        sub_data = 0
        for im1, im2 in zip(sub_image1, sub_image2):
            sub_data += self.calculate(im1, im2)
        sub_data = sub_data / 3
        return sub_data

    # 计算单通道的直方图的相似值
    def calculate(self,image1, image2):
        hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
        hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
        # 计算直方图的重合度
        degree = 0
        for i in range(len(hist1)):
            if hist1[i] != hist2[i]:
                degree = degree + (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
            else:
                degree = degree + 1
        degree = degree / len(hist1)
        return degree

    # Hash值对比
    def cmpHash(self,hash1, hash2,shape=(10,10)):
        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/(shape[0]*shape[1])

    def mymovefile(self,srcfile,dstpath,ffname):           # 移动函数
        if not os.path.isfile(srcfile):
            print ("%s not exist!"%(srcfile))
        else:
            fpath,fname=os.path.split(srcfile)             # 分离文件名和路径
            if(ffname):fname=ffname
            if not os.path.exists(dstpath):
                os.makedirs(dstpath)                       # 创建路径
            shutil.move(srcfile, dstpath + fname)          # 移动文件
            #print ("move %s -> %s"%(srcfile, dstpath + fname))

    # 定义函数
    def list_all_files(self,rootdir):
        _files = []
    	# 列出文件夹下所有的目录与文件
        list = os.listdir(rootdir)
        for i in range(0, len(list)):
    		# 构造路径
            path = os.path.join(rootdir, list[i])
    		# 判断路径是否为文件目录或者文件
    		# 如果是目录则继续递归
            if os.path.isdir(path):
                _files.extend(list_all_files(path))
            if os.path.isfile(path):
                _files.append(path)
        return _files

    #处理文件
    def mvPhoto(self):
        
        photoList = self.list_all_files(self.dir)
        #print(photoList)

        for i,photo in enumerate(photoList):
            mvPhoto = False #是否移动主文件
            #如果不是文件则跳出
            if(not os.path.isfile(photo)):
                continue
            fpath,fname=os.path.split(photo)
            print('Master:'+fname)
            ffname = fname.split('.')

            #不是下列文件形式跳出
            if(ffname[1] not in {'jpg', 'bmp', 'png', 'jpeg', 'gif'}):
                continue

            img1 = cv2.imdecode(np.fromfile(photo,dtype=np.uint8),cv2.IMREAD_COLOR)
            for j in range(i+1,len(photoList)):
                #print('  ',j,photoList[j])
                if(not os.path.isfile(photo) or not os.path.isfile(photoList[j])):
                    continue
                spath,sname=os.path.split(photoList[j])
                #print(sname)
                ssname = sname.split('.')
                if(ssname[1] not in {'jpg', 'bmp', 'png', 'jpeg', 'jfif'}):
                    continue
                
                #img1 = cv2.imread(photo)
                img2 = cv2.imdecode(np.fromfile(photoList[j],dtype=np.uint8),cv2.IMREAD_COLOR)
                
                #hash1 = aHash(img1)
                #hash2 = aHash(img2)
                n1 = self.cmpHash(self.aHash(img1), self.aHash(img2))
                n2 = self.cmpHash(self.dHash(img1), self.dHash(img2))
                n3 = self.cmpHash(self.pHash(img1), self.pHash(img2))
                n4 = self.classify_hist_with_split(img1, img2)
                n5 = self.calculate(img1, img2)
                #print('    ',n1,n2,n3,n4,n5)
                if(n1>0.90 or n2>0.90 or n3>0.90 or n4>0.90 or n5>0.90):
                    mvPhoto = True
                    print('    move file:'+photoList[j])
                    if(os.path.isfile(photoList[j])):
                        print('ffname[0]:'+ffname[0])
                        #mymovefile(photoList[j],dir+'_重复'+'/',ffname[0]+'_'+str(random.randint(10,99))+'.'+ffname[1])
                        self.mymovefile(photoList[j],dir+'_df'+'/',ffname[0]+'_'+sname)
            
            #最后移动主文件
            if(mvPhoto==True):    
                self.mymovefile(photo,dir+'_df'+'/',fname)

if __name__ == "__main__":
    #指定路径
    #dir = r'E:\python\photoCompare\328' #指定目录地址
    dir = os.getcwd()                    #当前文件所在目录
    duplicateFiles = DuplicateFiles(dir)
    duplicateFiles.mvPhoto()

  

标签:hash,不同,self,cv2,shape,哈希,path,os,图片
From: https://www.cnblogs.com/kakasea/p/17341089.html

相关文章

  • dedecms 实现ctrl+v粘贴图片并上传、word粘贴带图片
    ​图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM.plugins['autoupload'],然后找到autoUploadHandler方法,注释掉其中的代码。加入下面的代码://判断剪贴......
  • 网易云信上传图片 点击两次才能上传图片
    网易云信上传图片点击两次才能上传图片原因:之前异步比打开文件夹先执行需要按两次才能上传文件fileInputElement.value的值永远是需要监视文件选择器有没有选择文件,如果选择了再执行异步,没有选择就取消constfileInputElement=ref<null|HTMLElement>(null);cons......
  • node实现登录图片验证码
    实现这里的图形验证码我是用的node里svg-captcha模块,可以全部支持字符和数字,全平台支持,用起来很简单。安装cnpmisvg-captcha--save在使用的地方导入varsvgCaptcha=require('svg-captcha');获取验证码安装cookie-parser,作用是将获取到的session保存到cookie,方便......
  • PHPCMS 实现ctrl+v粘贴图片并上传、word粘贴带图片
    ​ 这种方法是servlet,编写好在web.xml里配置servlet-class和servlet-mapping即可使用后台(服务端)java服务代码:(上传至ROOT/lqxcPics文件夹下)<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%@     page contentType="text/html;cha......
  • java实现两张图片的相似度
    图片相似度java实现:https://zhuanlan.zhihu.com/p/568827637https://github.com/MingGH/calculate-pic-looklike 前端html5调用摄像头:https://www.cnblogs.com/hss-blog/p/9984878.htmlhttps://jeff_zhong.gitee.io/demo/dist/camera.html需要改正的是:<inputid="file"ty......
  • 帝国CMS 实现ctrl+v粘贴图片并上传、word粘贴带图片
    ​ 在之前在工作中遇到在富文本编辑器中粘贴图片不能展示的问题,于是各种网上扒拉,终于找到解决方案,在这里感谢一下知乎中众大神以及TheViper。通过知乎提供的思路找到粘贴的原理,通过TheViper找到粘贴图片的方法。其原理为一下步骤:监听粘贴事件;【用于插入图片】获取光标位置;【......
  • 直接写和放在函数中不同的R语言用法
    索引数据框中的某一列df$A可以索引数据框df中列名为A的列的所有值。那么假如列名是一个R对象怎么做?df<-data.frame(A=1:5,B=(1:5)*2)df$A##[1]12345needed_column='A'#df$needed_column?Wrong#注意是双方括号df[[needed_column]]##[1]12345ggplo......
  • 动易CMS 实现ctrl+v粘贴图片并上传、word粘贴带图片
    ​如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
  • SiteFactory 实现ctrl+v粘贴图片并上传、word粘贴带图片
    ​ 自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了。一般情况下我们将Word内容粘贴到Web编辑器(富文本编辑器)中时,编辑器都无法自动上传图片。需要用户手动一张张上传Word图片。如果只有一张图片还能够接......
  • GD32F470II芯片LVGL不同驱动方式对比
    1、硬件对比屏幕尺寸:800*480 颜色格式:RGB565一帧数据:800*480*2=768000=750kLCD频率:32MHz/768000=41HZlvglfps:33优化等级:AC5-O3新硬件:GD32F470IISDRAM:32bit带宽,120MHzMCU:240MHz,768KRAM,2MFlashlv_demo_b......