python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python图片去重

Python使用CRC实现图片去重

作者:lyshark

这篇文章主要为大家详细介绍了Python如何使用CRC实现图片去重功能,文中的示例代码讲解详细,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

使用CRC32还可实现图片去重功能,如下FindRepeatFile函数,运行后通过对所有文件做crc校验并将校验值存储至CatalogueDict字典内,接着依次提取CRC特征值并将其存储至CatalogueList列表内,接着通过统计特征值出现次数并将该次数放入到CountDict字典内,最后循环这个字典,并以此输出文件特征与重复次数,将重复值放入到RepeatFileFeatures列表内。

如下代码所示;

import zlib,os

def Find_Repeat_File(file_path,file_type):
    Catalogue = os.listdir(file_path)
    CatalogueDict = {}  # 查询字典,方便后期查询键值对对应参数
    for each in Catalogue:
        path = (file_path + each)
        if os.path.splitext(path)[1] == file_type:
            with open(path,"rb") as fp:
                crc32 = zlib.crc32(fp.read())
                # print("[*] 文件名: {} CRC32校验: {}".format(path,str(crc32)))
                CatalogueDict[each] = str(crc32)
    CatalogueList = []
    for value in CatalogueDict.values():
    # 该过程实现提取字典中的crc32特征组合成列表 CatalogueList
        CatalogueList.append(value)

    CountDict = {}
    for each in CatalogueList:
    # 该过程用于存储文件特征与特征重复次数,放入 CountDict
        CountDict[each] = CatalogueList.count(each)
        
    RepeatFileFeatures = []
    for key,value in CountDict.items():
    # 循环查找字典中的数据,如果value大于1就存入 RepeatFileFeatures
        if value > 1:
            print("[-] 文件特征: {} 重复次数: {}".format(key,value))
            RepeatFileFeatures.append(key)

if __name__ == "__main__":
    Find_Repeat_File("D://lyshark/",".png")

运行上述代码,则会扫描d://lyshark/目录下所有的png格式文件,并输出这些文件特征值,以及该特征的重复次数,如下图所示;

有了上述方法我们就可以实现去重了,当然上述方法还可以优化,通过使用groupby功能可以自动实现分组,f恩组后我们只需要对分组进行排序,并寻找对应符合条件的特征,找到后直接调用os.remove将其移除即可,实现代码如下所示;

import zlib,os,argparse
from operator import itemgetter
from itertools import groupby

def Find_Repeat_File(file_path,file_type):
    Catalogue = os.listdir(file_path)
    CatalogueList = []
    for each in Catalogue:
        path = (file_path + each)
        if os.path.splitext(path)[1] == file_type:
            with open(path,"rb") as fp:
                crc32 = zlib.crc32(fp.read())
                # print("[*] 文件名: {} CRC32校验: {}".format(path,str(crc32)))
                CatalogueList.append({ "CRC32": str(crc32) , "FILE": path })
    
    # 首先排序,然后根据字典中的CRC32排序
    CatalogueList.sort(key=itemgetter("CRC32"))
    for key,value in groupby(CatalogueList,key=itemgetter("CRC32")):
        # print("[*] CRC32特征码: {}\t".format(key))
        for each in value:
            RepeatNumber = len(list(value))
            if (RepeatNumber+1) > 1:
                try:
                    print("---> 重复图片: {} 已移除".format(each.values()))
                    os.remove(str(list(each.values())[1]))
                except FileNotFoundError:
                    pass

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-d","--dirs",dest="dirs",help="指定目录路径")
    parser.add_argument("-t","--types",dest="types",help="指定文件类型")
    args = parser.parse_args()
    # 使用方式: main.py -d "d://lyshark/" -t ".png"
    if args.dirs and args.types:
        os.chdir(args.dirs)
        try:
            for each in range(0,len(os.listdir())):
                Find_Repeat_File("./",args.types)
        except:
            pass
    else:
        parser.print_help()

如下图所示,我们通过传入d://lyshark/并设置.png类型,扫描该目录下所有重复文件,并将该文件移除,输出效果如下图所示;

当然上述方法是一次性清楚重复文件,在某些时候我们希望存入文件后自动清理,此时就需要动态监控文件或目录变化,函数MonitoringDirectory()可用于动态监控用户目录,当有新文件创建时自动校验是否存在该文件如果存在则删除重复的,其实现原理是不间断的遍历目录,当有新文件产生时自动将该文件计算特征对比,如果重复则删除,该方式虽然可实现目录监控但效率却很低,因为要不间断的遍历目录。

import os, time
from zlib import crc32

# 计算目标CRC32
def Calculation_crc32(filename):
    try:
        with open(filename,"rb") as fp:
            crc = crc32(fp.read())
            while True:
                temp = fp.read(8196)
                if not temp:
                    break
            fp.close()
            return crc
    except Exception:
        fp.close()
        return 0
    return 0

# 开始监控目录
def MonitoringDirectory(path_to_watch):
    crc_poll = []

    before = dict([(f, None) for f in os.listdir(path_to_watch)])
    while True:
        time.sleep (0.3)

        after = dict ([(f, None) for f in os.listdir (path_to_watch)])
        added = [f for f in after if not f in before]
        removed = [f for f in before if not f in after]

        # 新增文件时触发
        if added:
            # print("新建文件: {}".format(added))
            for index in range(0,len(added)):
                # 计算文件CRC32
                AbsolutePath = path_to_watch + "/" + added[index]
                crc = Calculation_crc32(AbsolutePath)
                print(f"计算文件路径: {AbsolutePath} 文件CRC32: {crc}")

                # 只要有新文件则加入到crc_pool
                if crc != 0:
                    crc_poll.append(crc)

                print("池内数据: {}".format(crc_poll))
                crc_count = 0

                # 循环池内的所有CRC数据
                for index in range(0,len(crc_poll)):

                    # 如果当前文件CRC与池内某个一致则递增
                    if crc_poll[index] == crc:
                        crc_count = crc_count + 1

                    # 只要大于2则说明有重复的
                    if crc_count >= 2:
                        try:
                            print("存在校验值,删除文件: {}".format(AbsolutePath))
                            os.remove(AbsolutePath)
                            crc_poll.remove(crc)
                        except Exception:
                            pass
        # 删除文件时触发
        if removed:
            print("移除文件: {}".format(removed))
        before = after

if __name__ == "__main__":
    MonitoringDirectory("d://lyshark")

运行上述程序,则会监控d://lyshark目录,当有心文件被创建时会自动对比特征值,如果相同则会被清理,如果无重复的则会被保留,如下图所示;

到此这篇关于Python使用CRC实现图片去重的文章就介绍到这了,更多相关Python图片去重内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文