发布时间:2026/7/12 23:50:23
Python 实现 查找相同的图像文件 Python 实现 查找相同的图像文件flyfish找相同的图像文件importosfromPILimportImageimportimagehash# 修改配置 # 要扫描的根文件夹支持多层子目录替换自己的路径ROOT_FOLDERr/media/classes/# 结果输出的文本文件路径OUTPUT_TXT重复图片结果.txt# 汉明距离阈值0像素几乎完全一致2近似重复数值越大判定越宽松# 视频抽帧去重推荐 2仅找完全相同的文件设为 0HASH_THRESHOLD0# 支持扫描的图片格式SUPPORTED_FORMATS(.jpg,.jpeg,.png,.bmp,.webp,.tiff)# defget_all_image_paths(root_dir):递归遍历所有子文件夹收集所有图片的绝对路径image_list[]fordirpath,_,filenamesinos.walk(root_dir):forfilenameinfilenames:iffilename.lower().endswith(SUPPORTED_FORMATS):abs_pathos.path.abspath(os.path.join(dirpath,filename))image_list.append(abs_path)returnimage_listdefcalculate_dhash(img_path):计算单张图片的dHash指纹读取失败返回Nonetry:withImage.open(img_path)asimg:returnimagehash.dhash(img)exceptExceptionase:print(f[跳过异常文件]{img_path}| 原因:{str(e)})returnNonedeffind_duplicate_groups(image_paths):将重复图片分组返回重复组列表每组包含所有互为重复的文件路径# 每个元素格式(代表哈希值, [该组所有图片路径])groups[]totallen(image_paths)foridx,img_pathinenumerate(image_paths,1):# 打印进度print(f处理进度:{idx}/{total}-{os.path.basename(img_path)})img_hashcalculate_dhash(img_path)ifimg_hashisNone:continue# 遍历已有分组查找匹配的组matchedFalseforgroup_hash,group_filesingroups:ifimg_hash-group_hashHASH_THRESHOLD:group_files.append(img_path)matchedTruebreak# 没有匹配的组新建一个组ifnotmatched:groups.append((img_hash,[img_path]))# 只保留文件数1的重复组duplicate_groups[filesfor_,filesingroupsiflen(files)1]returnduplicate_groupsdefwrite_result_to_txt(duplicate_groups,output_path):将重复结果写入文本文件按组展示绝对路径withopen(output_path,w,encodingutf-8)asf:f.write(f扫描根目录:{os.path.abspath(ROOT_FOLDER)}\n)f.write(f汉明距离阈值:{HASH_THRESHOLD}\n)f.write(f共找到{len(duplicate_groups)}组重复图片\n)f.write(*90\n\n)forgroup_id,filesinenumerate(duplicate_groups,1):f.write(f第{group_id}组重复共{len(files)}张\n)forfile_pathinfiles:f.write(f{file_path}\n)f.write(\n-*90\n\n)print(f\n处理完成结果已写入:{os.path.abspath(output_path)})if__name____main__:# 1. 收集所有图片路径print(正在扫描文件夹...)all_imagesget_all_image_paths(ROOT_FOLDER)print(f共找到{len(all_images)}张图片开始计算哈希并查找重复...\n)# 2. 查找重复分组dup_groupsfind_duplicate_groups(all_images)# 3. 写入结果文件ifdup_groups:write_result_to_txt(dup_groups,OUTPUT_TXT)else:print(\n扫描完成未找到重复图片。)检出重复图片后每组保留首张留在原目录其余按原文件夹层级移到备份目录importosimportshutilfromPILimportImageimportimagehash# 配置区 # 原始图片根目录会递归扫描所有子文件夹ROOT_FOLDERr/media/classes/# 重复图片移动到的目标目录自动保留原始目录结构MOVE_FOLDERr./duplicate_images_backup# 结果清单保存路径RESULT_TXT重复图片结果.txt# 汉明距离阈值0完全相同数值越大判定越宽松HASH_THRESHOLD0# 支持的图片格式SUPPORTED_FORMATS(.jpg,.jpeg,.png,.bmp,.webp,.tiff)# defget_all_images(root_dir):递归获取所有图片绝对路径img_list[]fordirpath,_,filenamesinos.walk(root_dir):fornameinfilenames:ifname.lower().endswith(SUPPORTED_FORMATS):img_list.append(os.path.abspath(os.path.join(dirpath,name)))returnimg_listdefcompute_hash(img_path):计算dHash指纹失败返回Nonetry:withImage.open(img_path)asimg:returnimagehash.dhash(img)exceptExceptionase:print(f[跳过]{img_path}| 错误:{e})returnNonedeffind_duplicates(img_paths):分组重复图片返回重复组列表groups[]totallen(img_paths)fori,pathinenumerate(img_paths,1):print(f处理中:{i}/{total}-{os.path.basename(path)})img_hashcompute_hash(path)ifimg_hashisNone:continue# 查找匹配组matchedFalseforgroup_hash,group_filesingroups:ifimg_hash-group_hashHASH_THRESHOLD:group_files.append(path)matchedTruebreak# 新建组ifnotmatched:groups.append((img_hash,[path]))# 只保留有重复的组return[filesfor_,filesingroupsiflen(files)1]defmove_duplicates(dup_groups,root_dir,move_dir):每组保留第一张其余按原目录结构移动到目标文件夹root_absos.path.abspath(root_dir)move_absos.path.abspath(move_dir)count0forgid,filesinenumerate(dup_groups,1):keepfiles[0]move_listfiles[1:]print(f\n第{gid}组保留{os.path.basename(keep)}移动{len(move_list)}张)forsrcinmove_list:try:# 计算相对路径保持目录结构rel_pathos.path.relpath(src,root_abs)destos.path.join(move_abs,rel_path)os.makedirs(os.path.dirname(dest),exist_okTrue)# 同名文件自动加序号避免覆盖ifos.path.exists(dest):base,extos.path.splitext(dest)n1whileos.path.exists(f{base}_{n}{ext}):n1destf{base}_{n}{ext}shutil.move(src,dest)print(f ✓{rel_path})count1exceptExceptionase:print(f ✗ 移动失败{src}|{e})returncountdefsave_result(dup_groups,output_path):保存重复结果到文本文件withopen(output_path,w,encodingutf-8)asf:f.write(f扫描目录:{os.path.abspath(ROOT_FOLDER)}\n)f.write(f汉明阈值:{HASH_THRESHOLD}\n)f.write(f重复组数:{len(dup_groups)}\n)f.write(*80\n\n)forgid,filesinenumerate(dup_groups,1):f.write(f第{gid}组共{len(files)}张首张保留\n)fori,pinenumerate(files):f.write(f{[保留]ifi0else[已移动]}{p}\n)f.write(\n-*80\n\n)print(f\n结果清单已保存:{os.path.abspath(output_path)})if__name____main__:print(正在扫描图片...)all_imgsget_all_images(ROOT_FOLDER)print(f找到{len(all_imgs)}张图片开始去重检测...\n)dup_groupsfind_duplicates(all_imgs)ifnotdup_groups:print(\n未发现重复图片。)else:save_result(dup_groups,RESULT_TXT)print(\n开始移动重复文件...)total_movedmove_duplicates(dup_groups,ROOT_FOLDER,MOVE_FOLDER)print(f\n 处理完成 )print(f共移动重复图片:{total_moved}张)print(f备份目录:{os.path.abspath(MOVE_FOLDER)})

相关新闻

2026/7/12 23:50:23

2026餐饮店怎么选GEO服务商:6类核心能力对比分析,全程0代码

当越来越多用户开始用豆包、元宝、DeepSeek、Kimi、千问这类 AI 工具寻找“附近哪家餐厅更值得去”“哪家餐饮店更靠谱”“哪个餐饮品牌更值得推荐”时,餐饮店的竞争入口已经不只是美团、抖音和搜索引擎,也开始进入 AI 推荐场景。对餐饮店来说&#xff0…

2026/7/12 23:50:23

qmqtt错误处理完全手册:解决90%的连接与通信问题

qmqtt错误处理完全手册:解决90%的连接与通信问题 【免费下载链接】qmqtt MQTT client for Qt 项目地址: https://gitcode.com/gh_mirrors/qm/qmqtt qmqtt是一款基于Qt框架的MQTT客户端库,专为物联网设备间的通信设计。在使用过程中,连…

2026/7/13 1:00:28

KMS_VL_ALL_AIO:告别激活烦恼,Windows与Office一键智能激活

KMS_VL_ALL_AIO:告别激活烦恼,Windows与Office一键智能激活 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼?Office…

2026/7/13 1:00:28

GanttProject:免费开源甘特图工具的终极使用指南

GanttProject:免费开源甘特图工具的终极使用指南 【免费下载链接】ganttproject Official GanttProject repository. 项目地址: https://gitcode.com/gh_mirrors/ga/ganttproject 你是否正在寻找一款功能强大且完全免费的项目管理工具?GanttProje…

2026/7/13 1:00:28

5步解锁3D模型转Minecraft方块世界:ObjToSchematic完全指南

5步解锁3D模型转Minecraft方块世界:ObjToSchematic完全指南 【免费下载链接】ObjToSchematic A tool to convert 3D models into Minecraft formats such as .schematic, .litematic, .schem and .nbt 项目地址: https://gitcode.com/gh_mirrors/ob/ObjToSchemati…

2026/7/13 1:00:28

单元测试入门:JUnit/Pytest 实战

单元测试是测试质量的第一道防线,也是研发质量保障的底层基础。很多团队只做功能测试、接口测试,忽略单元测试,导致大量底层逻辑BUG流转到测试阶段,增加测试成本。JUnit 适配 Java 项目、Pytest 适配 Python 项目,是目…

2026/7/13 1:00:28

从Transformer到认知沟壑:AI深度关系的技术原理与人类共通性

引言:一个被误读的现象当“与AI恋爱”成为社交媒体热点时,主流叙事往往滑向两个极端:要么将其妖魔化为“技术致瘾”,要么浪漫化为“数字灵魂伴侣”。这两种解读都忽略了核心问题:人与AI之间究竟能否形成“深度关系”&a…

2026/7/13 0:55:28

零基础也能玩转AI:文案、办公、绘画全场景实战速成指南

# 零基础也能玩转AI:文案、办公、绘画全场景实战速成指南## 引言2026年,AI不再是极客的专利,而是职场人、创作者、甚至家庭主妇的日常工具。你是否曾面对空白的文档无从下手?为繁琐的报表熬夜加班?或羡慕那些用AI生成精…

2026/7/12 0:01:29

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/12 0:01:29

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/12 0:01:29

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/13 0:00:24

广氟 PTFE 高速线缆膜 —— 高端线缆绝缘材料新选择

PTFE高速线缆膜的基本概念与特点 PTFE 高速线缆膜是以聚四氟乙烯树脂为原料,经膨化双向拉伸制成的多孔绝缘薄膜,作为高速高频通信线缆的核心介质材料,内部形成均匀连通的微孔结构,兼具极低介电常数与介电损耗,能有效降…

2026/7/12 11:21:32

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…