AntiDupl.NET 开源项目全解析:从重复图片查重引擎到 Visual Studio 2022 源码构建实战
AntiDupl.NET 开源项目全解析:从重复图片查重引擎到 Visual Studio 2022 源码构建实战
AntiDupl.NET 是一款面向磁盘图片收藏的相似图片与缺陷图片自动检索工具,它通过基于文件内容(而非文件名或元数据)的比对算法,在 JPEG、PNG、WEBP、HEIF、AVIF 等 17 类主流格式中找出"几乎相同"乃至"仅内容相似"的图片,并附带 JPEG 截断、块效应、模糊等缺陷检测能力。本文以仓库根目录的 README.md 为主线,结合 AntiDupl.h 中的公共接口定义、adEngine.h 的引擎结构、adImageComparer.h 的比对器设计以及 vcpkg.json 的依赖清单,讲解该项目的核心原理、支持格式、缺陷检测分类,并给出从零开始用 Visual Studio 2022 + vcpkg 编译出完整程序的分步操作指南。读完本文,你将既能快速上手使用 AntiDupl.NET 清理磁盘重复图片,也能独立复现其源码构建流程,为二次开发打下基础。
本文所有命令与配置均以当前仓库实际内容为准;源码路径为仓库内相对路径。
一、项目定位:为什么要用"内容比对"来清理重复图片
现代电脑用户通常积累了大量不同格式的图片文件。图片收藏越多,出现重复文件的可能性就越大,用户自然会希望清理掉这些冗余。但当收藏规模足够大时,纯手工整理是一项极其枯燥且低效的工作。这正是 README.md 描述的 AntiDupl.NET 的诞生背景:自动完成重复图片的查找与展示,让用户把精力放在"删哪一张"的决策上,而不是"哪里重复了"的搜索上。
与按文件名、文件大小或哈希值去重的简单工具不同,AntiDupl.NET 的核心差异在于:
- 基于文件内容比对:程序读入图片的像素数据而不是只比对元数据,因此不仅能发现"几乎完全相同"的副本,还能发现因压缩参数、分辨率调整、轻微编辑而变得"相似"的图片(见 README.md 第 10-12 行)。
- 附带缺陷检测:除查重外,还能定位带有特定类型缺陷的图片文件。
- 免费开源、双界面:免费开源软件,提供俄语与英语两种界面,强调易用性与查重的高速度、高准确率(见 README.md 第 14-15 行)。
仓库中两个 .NET 前端项目——AntiDupl.NET.WPF 与 AntiDupl.NET.WinForms——分别承载现代与经典两种 Windows 桌面界面,而真正完成图片读取、收集、比对与缺陷检测的 C++ 核心引擎位于 src/AntiDupl。
二、支持的文件格式与"内容比对"背后的解码链路
README 明确列出程序可查找并展示重复图片的常用图形格式:
JPEG、GIF、TIFF、BMP、PNG、EMF、WMF、WEBP、EXIF、ICON、JP2、PSD、DDS、HEIF、HEIC、TGA、AVIF、JXL
这份清单与 C++ 引擎中的枚举定义完全对应。在 AntiDupl.h 中,adImageType 枚举依次定义了从 AD_IMAGE_BMP、AD_IMAGE_GIF、AD_IMAGE_JPEG、AD_IMAGE_PNG、AD_IMAGE_TIFF、AD_IMAGE_EMF、AD_IMAGE_WMF、AD_IMAGE_EXIF、AD_IMAGE_ICON、AD_IMAGE_JP2、AD_IMAGE_PSD、AD_IMAGE_DDS、AD_IMAGE_TGA、AD_IMAGE_WEBP、AD_IMAGE_HEIF、AD_IMAGE_AVIF 到 AD_IMAGE_JXL 共 17 种类型,与 README 列出的格式一一吻合。而在 adImage.cpp 中,每种格式还登记了各自的扩展名集合,例如 JPEG 家族包含 JPEG/JFIF/JPG/JPE/JIFF/JIF/J/JNG/JFF,TIFF 包含 TIF/TIFF,ICON 包含 ICON/ICO/ICN,JP2 家族包含 JP2/J2K/J2C/JPC/JPF/JPX,HEIF 家族包含 HEIF/HEIC——这意味着程序在实际扫描时按扩展名白名单收集候选文件。
内容比对的第一步是把磁盘文件解码为可计算的像素数据。引擎入口 TImage::Load 展示了完整的解码调度顺序:先依次尝试 OpenJPEG(JP2)、PSD、DDS、TGA、WebP、AVIF、JXL、HEIF 等专用解码器(对应 adOpenJpeg、adPsd、adDds、adTga、adWebp、adAvif、adJxl、adHeif 等实现文件),再在开启 useLibJpegTurbo 选项时用 TurboJPEG 处理 JPEG,最后回退到 Windows GDI+ 完成其余格式的加载。这种"专用解码器优先、GDI+ 兜底"的分层设计,是程序能同时覆盖传统格式与新兴格式的关键。这些第三方解码能力在 vcpkg.json 中体现为依赖清单:libjpeg-turbo、openjpeg、libwebp、libheif、simd、libavif、libjxl。
三、查重原理:从像素数据到相似度判定
"基于内容的比较"在引擎中落地为两个阶段:收集(Collect)与比对(Compare),由 TEngine 统一协调,内部持有 TCollectManager、TCompareManager、TSearcher、TResultStorage、TImageDataStorage、TMistakeStorage 等组件,并提供 Search() 作为一次完整扫描的入口。
3.1 扫描收集:TSearcher 如何挑选候选图片
TSearcher 负责遍历用户指定的目录(支持子文件夹递归),通过 IsWanted / IsForbidden 过滤路径,并通过 InitExtensions 与 AddExtensions 按各格式是否启用动态构建扩展名白名单。从 adConfig.h 的常量可见,引擎把每张图缩略为 REDUCED_IMAGE_SIZE_MIN = 16 到 INITIAL_REDUCED_IMAGE_SIZE = 256 之间的小尺寸位图(FAST_IMAGE_SIZE = 4 用于快速预筛),使后续比对的计算量大幅下降,这也是"高速度"的工程基础之一。
3.2 分层比对:TImageComparer 家族
adImageComparer.h 定义了抽象基类 TImageComparer:维护 m_mainThreshold、m_fastThreshold、m_maxDifference 等阈值,通过 Add/Compare/IsDuplPair 三个虚函数把"加入候选集"与"两两比对"分离。仓库中实现了多个具体比对策略:
TImageComparer_0D:基于整幅图像统计特征的快速粗筛;TImageComparer_1D:基于 256 级直方图(RANGE = 256)的一维比对;TImageComparer_3D:构造三维索引(像素总和s、左右半图差x、上下半图差y)进行多维空间预筛(见 adImageComparer.h);TImageComparer_SSIM:基于结构相似性指数(SSIM,内部维护C1、C2常量)的感知质量比对。
这些策略由工厂函数 CreateImageComparer 根据配置选择,adAlgorithmComparing 枚举(AD_COMPARING_SQUARED_SUM 与 AD_COMPARING_SSIM,见 AntiDupl.h)正是用户界面上"比对算法"选项的底层对应。粗筛用快速特征排除绝大多数无关图片,细筛再用全像素或 SSIM 精确判定,层层递进。
3.3 相似而非相同的判定:阈值与变换
adCompareOptions(见 AntiDupl.h)集中了比对阶段的全部可调参数:
| 参数字段 | 含义 |
|---|---|
checkOnEquality |
是否检查完全相等的图片对 |
transformedImage |
是否把旋转/镜像后的图片也视为候选(对应 adTransformType 中 TURN_90/180/270 与 MIRROR_TURN_* 共 8 种变换,见 AntiDupl.h) |
sizeControl / typeControl / ratioControl |
是否要求尺寸、格式、宽高比一致才比较 |
thresholdDifference |
允许的差异阈值,决定"相似"的严格程度 |
minimalImageSize / maximalImageSize |
只比较落在尺寸区间内的图片 |
compareInsideOneFolder / compareInsideOneSearchPath |
是否只在同一文件夹或同一搜索路径内找重复 |
algorithmComparing |
选择平方和(Squared Sum)或 SSIM 算法 |
从 adConfig.h 的常量可以看出引擎内部使用的关键基准:差异以 DENOMINATOR = 100 为分母的百分比形式衡量(PIXEL_MAX_DIFFERENCE = 0xFF),并定义了 D0_SEARCHED_FILE_NUMBER_MAX = 1000、D1_SEARCHED_FILE_NUMBER_MAX = 10000、D3_THRESHOLD_DIFFERENCE_MAX(差异上限 10%)与 D3_MAX_RANGES_STEP(步长 1%)等分级阈值——这解释了为什么程序能"找到相似但不完全相同"的图片:只要两图差异低于用户设定的阈值百分比,即判为重复对。
3.4 缺陷检测:不止查重,还能找坏图
README 提到的"部分类型的缺陷"在 adDefectType 枚举中明确列出(见 AntiDupl.h):
| 缺陷类型 | 含义 |
|---|---|
AD_DEFECT_UNKNOWN |
无法识别的缺陷 |
AD_DEFECT_JPEG_END_MARKER_IS_ABSENT |
JPEG 文件缺少结束标记(0xFFD9,对应 adConfig.h 中的 JPEG_FILE_MARKER 与 JPEG_FILE_MARKER_END),即文件被截断 |
AD_DEFECT_BLOCKINESS |
块效应(块状压缩伪影) |
AD_DEFECT_BLURRING |
模糊(对焦不准或过度降噪) |
块效应与模糊的检测由 adBlurringDetector.h 中的 TBlurringDetector 实现;adDefectOptions(AntiDupl.h)则暴露了 checkOnDefect、checkOnBlockiness、blockinessThreshold、checkOnBlockinessOnlyNotJpeg、checkOnBlurring、blurringThreshold 等开关与阈值,用户可在界面中独立启停每种检测。检测流程由 adImageData.h 中的 TImageData::DefectCheckingNeed / GetDefect 驱动,TImageData 结构体同时记录宽高比(ratio)、CRC32C 校验(crc32c)与像素数据(data)——CRC32C 用于快速区分内容差异,而宽高比用于旋转候选的匹配。
四、从源码构建:Visual Studio 2022 + vcpkg 完整流程
README.md 第 17-44 行给出了官方的构建步骤,以下按步骤复现并补充关键细节。构建产物同时包含 C++ 引擎(src/AntiDupl)与两个 .NET 前端(AntiDupl.NET.WPF、AntiDupl.NET.WinForms),解决方案文件为 src/AntiDupl.sln。
第 1 步:安装 Visual Studio 2022
下载 Visual Studio 2022(例如 Community 社区版)并安装。在 Visual Studio Installer 中选择以下工作负载:
- .NET Desktop development(.NET 桌面开发,用于编译 WPF/WinForms 前端);
- Desktop development with C++(使用 C++ 的桌面开发,用于编译核心引擎)。
注意:当前最新默认工具集为 v143(对应 VS2022)。
第 2 步:获取 vcpkg 依赖管理器
vcpkg 是微软开源的 C/C++ 依赖管理工具,本项目通过它自动拉取并编译全部第三方图片解码库。使用 git 克隆:
git clone https://github.com/Microsoft/vcpkg.git
第 3 步:安装并集成 vcpkg
在 vcpkg 目录内执行引导脚本与全局集成:
cd vcpkg
./bootstrap-vcpkg.bat
./vcpkg integrate install
integrate install 会让 Visual Studio 在构建时自动感知 vcpkg 已安装的包。
第 4 步:打开解决方案
用 Visual Studio 打开 src/AntiDupl.sln,即可看到 C++ 引擎项目与 .NET 前端项目。
第 5 步:开始构建
在 Visual Studio 中直接生成解决方案。README 明确说明:"依赖库将由 vcpkg 自动加载并构建"("Depended libraries will be automatically loaded and built by vcpkg")。仓库根目录的 vcpkg.json 即构建所需的依赖清单,包含:
| 依赖包 | 用途 |
|---|---|
libjpeg-turbo |
高性能 JPEG 编解码(对应引擎的 TurboJPEG 路径,由 AD_TURBO_JPEG_ENABLE 宏开启,见 adConfig.h) |
openjpeg |
JPEG 2000(JP2)解码 |
libwebp |
WebP 解码 |
libheif |
HEIF/HEIC 解码 |
libavif |
AVIF 解码 |
libjxl |
JPEG XL(JXL)解码 |
simd |
SIMD 加速库(引擎的 adSimd.h 基于其 Simd::View 类型组织像素视图,见 adConfig.h) |
这些依赖与上文 TImage::Load 的解码调度顺序一一对应:libavif→AVIF、libjxl→JXL、libheif→HEIF、libjpeg-turbo→JPEG,其余格式回退 GDI+。
构建要点小结
- 若只想编译核心引擎与特定前端,可在解决方案中选择对应项目单独生成;
- 首次构建耗时较长,因为 vcpkg 需要从源码编译全部依赖;
- 构建产物为 Windows 桌面程序,运行前请确保目标机器具备 .NET 运行环境(WPF 项目在 AntiDupl.NET.WPF.csproj 中声明了目标框架)。
五、界面与配置:两个前端如何对接引擎
仓库包含两套 Windows 桌面前端,共享同一 C++ 引擎:
- AntiDupl.NET.WPF:基于 XAML 的现代界面,采用 TinyIoC 轻量依赖注入容器组织服务(在 App.xaml.cs 中注册
IConfigurationModel、ILanguageService、CoreLib、IImageLoader、IThumbnailProvider等),MainViewModel作为界面与引擎之间的桥接层; - AntiDupl.NET.WinForms:经典 WinForms 实现,界面组件集中在
Form/与GUIControl/目录。
两个前端都通过 CoreLib.cs 封装对 C++ 引擎的调用,引擎导出的 TOptions(见 adOptions.h)通过 Import/Export 与各前端的选项模型互相转换,并支持把配置持久化为 INI 文件(TOption::Load/Save)。adSearchOptions(AntiDupl.h)以布尔开关形式逐项控制是否扫描 system(系统文件)、hidden(隐藏文件)以及上述 17 种格式——也就是说,用户界面上"要搜哪些格式"的勾选,最终会落到这张位图式的开关结构上。adAdvancedOptions(AntiDupl.h)则提供更底层的调优项:deleteToRecycleBin(删除前先进回收站)、mistakeDataBase(误判数据库)、ratioResolution(宽高比精度)、compareThreadCount/collectThreadCount(比对/收集线程数)、reducedImageSize(缩略图尺寸)、undoQueueSize(撤销队列深度)、resultCountMax(结果上限)、useLibJpegTurbo(是否启用 TurboJPEG)。
六、命令行工具 AntiDuplX:同算法的跨平台分支
README.md 第 46-49 行还提及一个独立的姊妹项目 AntiDuplX:这是一个命令行工具,同样用于搜索相似与损坏图片,采用与 AntiDupl.NET 类似的图片比对算法,且同时支持 Linux 与 Windows。需要强调的是,AntiDuplX 是独立于本仓库的单独项目(不在本仓库代码内);对需要脚本化、无界面批处理场景的用户,它是 AntiDupl.NET 图形界面的有益补充。
七、快速上手指南:下载、配置与运行
结合引擎的选项结构与界面设计,典型使用流程如下:
- 下载与启动:从项目发布渠道获取最新构建的 Windows 程序(本仓库仅提供源码,cmd 目录下的
MakeBin.cmd、MakePublish.cmd、MakeSrc.cmd等脚本展示了打包分发流程),启动后选择界面语言(俄语或英语,语言服务在 LanguageService.cs 中实现,资源文件为 lang.xaml 与 lang.ru-RU.xaml)。 - 配置搜索路径与选项:在路径窗口中添加要扫描的文件夹(支持排除路径),在选项中按需勾选要扫描的图片格式、是否包含隐藏/系统文件,以及比对阈值、缺陷检测开关等参数(对应上文
adSearchOptions/adCompareOptions/adDefectOptions结构)。 - 开始搜索:程序递归扫描所选路径,先收集全部图片并缩略,再进入多线程比对阶段(线程数可在高级选项中调整),最后把重复对/缺陷图汇总到结果列表。
- 处理结果:在结果列表中审阅重复图片,利用删除、重命名、移动等批量操作清理冗余;误删可借助撤销队列(
undoQueueSize)回退,勾选"删除到回收站"则进一步降低风险。
八、总结与延伸阅读
AntiDupl.NET 的价值在于把"按内容找相似图片"这一计算密集型任务,通过"格式白名单收集 → 小图缩略 → 多维索引粗筛 → SSIM/平方和精判"的多级流水线做到实用化,并以 17 种格式的解码覆盖和块效应/模糊/截断三种缺陷检测补齐了图片管理工具的能力拼图。对想深入源码的读者,推荐按以下顺序阅读:
- 格式与枚举定义:AntiDupl.h
- 引擎与线程模型:adEngine.h、adThreads.h、adThreadManagement.h
- 比对算法家族:adImageComparer.h、adImageComparer.cpp
- 缺陷检测:adBlurringDetector.h、adImageUtils.cpp
- 解码调度:adImage.cpp
- 前端对接:CoreLib.cs、MainViewModel.cs
按照本文第四部分的操作步骤,你可以在自己的 Windows 机器上从源码完整构建出 AntiDupl.NET;也可以进一步阅读界面帮助文档(docs/data/help/english 与 docs/data/help/russian 下的 options.html、paths.html、table.html 等章节)掌握每个选项的详细含义。