Python 实现 查找相同的图像文件

发布时间:2026/11/1 21:13:50

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/10/29 13:42:42

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

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

2026/10/30 18:18:55

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

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

2026/11/2 10:05:49

MATLAB BP神经网络手写数字识别:完整代码与实战调优指南

简介:这份资源面向学习机器学习与MATLAB编程的初学者及课程实践者,提供BP神经网络手写数字识别的完整实现代码与配套数据集,帮助读者从零跑通一个经典的模式识别项目。压缩包共5027个文件,约6.15MB,其中5000个bmp图片为…

2026/11/2 10:05:49

MATLAB手写BP神经网络实现手写数字识别:从零搭建到调优实战

简介:这份资源面向学习机器学习与MATLAB编程的初学者及课程实践者,提供BP神经网络手写数字识别的完整实现代码,帮助读者从零跑通数据预处理、网络构建、训练与评估全流程。压缩包共5027个文件,约6.15MB,其中5000个bmp图…

2026/11/2 10:05:49

基于TCP/IP的展厅智能中控软件:架构、通信与二次开发实战

简介:面向展厅、会议室等场景的中控系统搭建需求,这份资源提供了一套基于TCP/IP协议的可视化智能中控软件程序,适合弱电集成人员、展厅运维者及希望低成本自建中控的爱好者使用。软件采用所见即所得的拖拽式编辑方式,无需编程即可…

2026/11/2 10:05:49

建筑外衣设计:跨界融合服装与建筑的创新实践

1. 服装设计与建筑外衣的跨界思考当"服装大师"遇上"建筑外衣",这个看似跨界的组合实则蕴含着深刻的设计共通性。建筑外立面作为城市的"服装",同样需要考虑材质选择、结构支撑、视觉比例和功能性等要素。就像高级定制服装需…

2026/11/2 10:05:49

Unity3D FPS工程导入避坑指南:版本、管线与输入系统对齐

简介:这份资源是面向 Unity3D 初学者与进阶开发者的完整 FPS 游戏工程源码,聚焦第一人称射击游戏的核心实现,帮助读者通过可运行项目理解联机 FPS 的搭建思路。压缩包共 1609 个文件,约 38.91MB,以 bin、info、asset、…

2026/11/2 10:00:48

理论蒸馏:大模型知识提炼的核心技术与实践

1. 项目概述:理论蒸馏的本质与挑战"孤能子视角"这个独特的概念框架,为我们提供了一种审视知识提炼过程的新维度。在技术演进的长河中,理论蒸馏始终扮演着关键角色——它既是知识传承的桥梁,也是创新突破的催化剂。当我们…

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/2 1:04:04

工业级SPI隔离设计:硬件抗扰与信号完整性实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/2 1:04:04

PLFM_RADAR:主动探测数据通道,构建低误报的数据感知系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/2 1:04:04

工业SPI隔离设计:MAX14431与STM32F746硬件抗干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑