# find_image_hide
**Repository Path**: CarGuo/find_image_hide
## Basic Information
- **Project Name**: find_image_hide
- **Description**: 一个本地批量跑的图片取证工具:CLI + 浏览器 UI,跨 Windows/macOS。一次性查 EXIF/XMP/IPTC、C2PA、可见水印 OCR、pHash 反查、Westfeld χ²/SPA 隐写检测、LSB 比特流提取、trailing data、FFT/DCT/Noise/ELA 频域与噪声异常,给每张图打 LOW/MEDIUM/HIGH 风险评分。Web UI 支持把整个文件夹直接拖进来,全程不出本机。
- **Primary Language**: Python
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-05-30
- **Last Updated**: 2026-05-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Image Forensics Inspector
一个跨平台(Windows + macOS)本地命令行 + 浏览器 UI 的图片取证分析工具,用于**批量扫描本地目录下所有图片**,输出统一的风险等级与可视化证据。所有分析在本机完成,不会上传到任何外部服务。
工具会同时给出:
- 基础信息:文件大小、SHA256、感知哈希 pHash、MIME;
- 元数据:EXIF / XMP / IPTC / PNG 文本块 / JPEG comment / 图库黑名单(Shutterstock、Getty 等关键词);
- 隐藏内容提取:附加在图像数据末尾的 trailing data(zip / 文本 / 文件签名)+ LSB 比特流文本提取;
- 隐写检测:Westfeld χ² POV、滑动 χ²、SPA 像素对统计;
- 可见水印 OCR:通过 Tesseract 读图上的 Getty / Shutterstock / 仅供预览 等可见水印(可选);
- 反查参考库:感知哈希 Hamming 距离匹配本地参考目录(可选);
- AI 来源凭证:C2PA(如系统中存在 `c2patool`)+ 关键词扫描(OpenAI / Gemini / SD / MJ / Adobe Firefly 等);
- FFT 频域:灰度 + RGB 频谱图、对称峰值检测;
- DCT:8x8 DCT 系数 heatmap、与 Laplace 自然分布的 K-S 检验;
- LSB:R/G/B 位平面图、熵 / 平衡度 / 邻域相关;
- 噪声残差:Gaussian residual、Laplacian、局部噪声不一致度;
- ELA 误差水平分析:再压缩误差,定位拼接 / 修图区域;
- 综合启发式风险评分:LOW / MEDIUM / HIGH / UNKNOWN,每个 tab 按风险染色。
> **重要免责声明**
> 本工具不能证明图片绝对包含或绝对没有水印,也不能证明图片绝对是或绝对不是 AI 生成。所有评分都是 heuristic,不构成法律鉴定结论。SynthID 不在常规 EXIF/XMP 中,本工具默认不做本地 SynthID 判定。
---
## 快速开始
### 依赖
- Python **3.10+**(Windows 上推荐官方安装包,macOS 上 `brew install python@3.11`);
- 可选:`c2patool`(用于读取 / 验证 C2PA)。如果没有装,工具仍可运行,C2PA 字段会标记 `c2pa_tool_available=false`;
- 可选:`tesseract`(用于读取图片上的可见水印)。未安装时 OCR 段会显示明确的安装指引,不影响其他模块;
- 可选:环境变量 `FORENSICS_PHASH_REFERENCE_DIR`(用于 pHash 参考库反查;指向一个本地目录即可)。
### Windows
```powershell
# 在项目根目录
.\start.bat # 仅启动 Web UI
.\start.bat --demo # 自动准备样本 + 跑一次完整 demo + 启动 Web UI(推荐首次使用)
```
脚本会自动创建 `.venv`、安装依赖、启动 Web UI 在 http://127.0.0.1:5050 ,并自动用默认浏览器打开。
### macOS
```bash
chmod +x start.sh
./start.sh # 仅启动 Web UI
./start.sh --demo # 自动准备样本 + 跑一次完整 demo + 启动 Web UI(推荐首次使用)
```
### 一键 Demo(最快上手方式)
无需手填路径,直接体验全部检测能力:
```bash
python demo.py # 仅准备样本 + 跑分析(CLI 输出每张图风险等级)
python demo.py --serve # 同上 + 启动 Web UI 并自动打开浏览器
python demo.py --no-download # 离线模式,只用合成样本
```
也可以在 Web UI 首页点击「**一键运行 Demo**」按钮,等价于 `POST /api/demo`:自动扫描内置 [tools/test_images](file:///d:/workspace/project/find_image_hide/tools/test_images),覆盖正常图、LSB 隐写、附加 ZIP / 文本、AI 元数据、版权图(Shutterstock / Getty 元数据 + 可见水印)、洗图反查(pHash 命中本地参考库)等典型场景。
> 真实样本来自 picsum.photos / Wikimedia Commons / NASA 等公开免费来源(见 [tools/download_test_images.py](file:///d:/workspace/project/find_image_hide/tools/download_test_images.py));可见水印 / 版权图样本基于这些真实图叠加生成(见 [tools/make_test_images.py](file:///d:/workspace/project/find_image_hide/tools/make_test_images.py))。
### 手动启动(任意平台)
```bash
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS / Linux:
source .venv/bin/activate
pip install -r requirements.txt
python webapp.py --host 127.0.0.1 --port 5050
```
> **关于端口**:默认端口是 `5050`。早期版本默认用 5000,但 macOS Monterey 起 5000 端口被系统的 AirPlay Receiver 占用,浏览器访问会被系统服务直接 403 拦截;Windows 上 5000 通常没被系统占用,但为了跨平台脚本一致,统一改成 5050。如果 5050 也被占,可手动指定其它端口,例如 `python webapp.py --port 5060`,并把浏览器地址同步改成 `http://127.0.0.1:5060`。
> **从手机 / Android 浏览器访问同一台电脑上的 Web UI**:默认 `--host 127.0.0.1` 只监听本机回环,手机访问不到。改为 `python webapp.py --host 0.0.0.0 --port 5050`,再让手机和电脑接到同一 Wi-Fi,用电脑的局域网 IP 访问,例如 `http://192.168.1.23:5050`。注意一旦绑到 `0.0.0.0`,同一网络下其它设备也能访问,**不要放到公网**,且最好仅在受信任网络下临时启用。
---
## 使用方式
启动后浏览器访问 http://127.0.0.1:5050 ,首页一共有三种触发扫描的方式:
### 方式一:把文件夹直接拖进来(推荐,最直观)
1. 启动 Web UI;
2. 从 Windows 资源管理器或 macOS Finder 里,把要扫描的整个文件夹拖到首页的虚线方框里;
3. 浏览器会递归读取该文件夹下所有支持的图片(JPG / PNG / WebP / BMP / TIFF / GIF),并以 multipart 一次性 POST 到本机 `/api/scan_upload`;
4. 上传过程中页面会显示进度条;上传完成后自动跳转到对应的 job 页,分析任务会立刻在后台开始;
5. 点方框的话也可以打开"选择文件夹"对话框(基于 ``),效果与拖拽一致;
6. 子目录结构会被保留:上传的文件被放到 `analysis_output//_uploaded/<原相对路径>` 下。
注意:
- 浏览器出于安全模型不会暴露被拖入文件的本地绝对路径,因此这种方式必然要"上传到本机后端"。整条数据流都在 127.0.0.1 内,不出网;
- 默认上传体积上限为 1 GB([webapp.py 中的 `MAX_UPLOAD_BYTES`](file:///d:/workspace/project/find_image_hide/webapp.py#L24-L24))。如果一次要扫的图集超过这个大小,请改用方式二;
- 服务端会自动忽略不支持的扩展名,并把跳过的文件数返回给前端展示。
### 方式二:填一个本机绝对路径
适合"原图就放在本机一个目录里、不想再上传一遍"的情况:
1. 在首页"方式二:填本地目录路径"卡片里输入目录绝对路径(Windows 例:`D:\photos`,macOS 例:`/Users/me/Pictures`);
2. 勾选是否递归扫描,设置 worker 并发数;
3. 点「开始扫描」,进入扫描结果页(支持文件名筛选、风险等级筛选);
4. 点击单条记录的「详情」查看每张图的 12 个分析模块。
### 方式三:一键 Demo
首页第三张卡片直接点「一键运行 Demo」即可,跑项目自带的样本集。
不论用哪种方式,详情页都会包含:
- 综合评估(badge:高风险 / 中风险 / 低风险 / 未知);
- 12 个 tab:隐藏内容提取 / 版权 · 图库 / 隐写检测 / 元数据 / AI 来源 / 频域 (FFT) / DCT 频域 / LSB 位平面 / 噪声残差 / ELA 误差 / 证据汇总 / 原始 JSON;
- 每个 tab 按各自模块的风险等级染色(红 / 黄 / 绿 / 灰),命中风险时还会显示小圆点;
- 每个 tab 顶部都有一段中文通俗解释,告诉你这一步在做什么、什么样的指标可疑;
- OCR / pHash 等可选模块未启用时会展示中文友好引导卡,包含完整的三步安装步骤。
所有结果保存在 `analysis_output//` 下,**目录扫描期间数据不会上传**到任何外部服务;只有"方式一"会让本地浏览器把文件 POST 给本机 webapp 进程。
### 命令行(仅 CLI)
```bash
# 单张图
python analyze_image.py --input ./test.jpg --output ./analysis_output
# 批量目录
python analyze_image.py --input ./photos --output ./analysis_output --recursive --workers 4
```
输出目录结构:
```
analysis_output/
summary.json # 整批汇总
_uploaded/ # 仅当通过 Web UI 拖拽上传时存在
__/
report.json # 单图完整报告
ai_provenance.json
visualizations/
spectrum.png, r/g/b_spectrum.png
dct_mean_heatmap.png, dct_histogram.png
lsb_r.png, lsb_g.png, lsb_b.png
residual.png, laplacian.png
```
---
## HTTP API 速览
webapp 启动后会暴露以下 HTTP 接口(仅监听 127.0.0.1):
| Method | Path | 用途 |
| --- | --- | --- |
| POST | `/api/scan` | 提交一个**本机绝对路径**的扫描任务,body 为 `{ "directory": "...", "recursive": true, "workers": 2 }` |
| POST | `/api/scan_upload` | 拖拽 / 选择文件夹后,前端用 multipart 上传文件,字段为 `files[]` 与配套的 `paths[]`(保留相对路径),可选 `recursive`、`workers` |
| POST | `/api/demo` | 一键运行内置 demo |
| GET | `/api/jobs/` | 查询 job 状态、已完成 / 总数 / 最新 50 条结果 |
| GET | `/api/jobs//summary` | 取整批 `summary.json` |
| GET | `/api/jobs//image//report` | 取单图完整 report |
| GET | `/jobs/` | 任务页(HTML) |
| GET | `/jobs//image/` | 单图详情页(HTML) |
`/api/scan_upload` 对路径做了严格清洗(拒绝 `..`、去掉盘符与起始斜杠、扩展名白名单),文件最终落到 `analysis_output//_uploaded/` 下,不会逃出该目录。
---
## report.json schema 速览
```json
{
"schema_version": "0.1.0",
"input": { "file_name": "...", "format": "PNG", "sha256": "...", ... },
"overall": {
"risk_level": "LOW|MEDIUM|HIGH|UNKNOWN",
"confidence": 0.0,
"summary": "...",
"module_scores": { "fft": 0.0, "dct": 0.0, "lsb": 0.0, "noise": 0.0, "metadata": 0.0, "provenance": 0.0 }
},
"metadata": { ... },
"ai_provenance": { "status": "NO_PROVENANCE_FOUND", ... },
"frequency_analysis": { ... },
"dct_analysis": { ... },
"lsb_analysis": { ... },
"noise_analysis": { ... },
"evidence_items": [ ... ]
}
```
---
## AI Provenance / C2PA 说明
- 如果系统中存在 `c2patool`(PATH 可见),工具会自动调用并解析 manifest;
- 否则只做关键词扫描(`OpenAI` / `Gemini` / `Imagen` / `SynthID` / `Stable Diffusion` / `Midjourney` / ...);
- 状态码:
- `VERIFIED_AI_GENERATED` / `VERIFIED_AI_EDITED`:C2PA 验证通过 + action 表明生成 / 编辑;
- `PROVENANCE_PRESENT_BUT_UNVERIFIED`:有 C2PA 但未验证;
- `POSSIBLE_AI_BUT_UNVERIFIED`:仅有元数据关键词;
- `NO_PROVENANCE_FOUND`:没有任何来源凭证。
---
## 安全 / 隐私
- webapp 默认只监听 `127.0.0.1`,不接受来自局域网或公网的请求。如果手动用 `--host 0.0.0.0`,请自己评估风险,工具不做任何鉴权;
- 所有图片处理、hash 计算、元数据读取都在本机完成,不会发往外部服务;
- C2PA 验证依赖系统中是否安装了 `c2patool`,本工具不会替你向 C2PA 服务做远程查询;
- pHash 反查仅与你在 `FORENSICS_PHASH_REFERENCE_DIR` 指向的本地目录比对,不会查云端图库;
- 拖拽上传场景:浏览器把文件 POST 给本机 webapp,整段 TCP 都在 127.0.0.1,不出本机;
- 上传体积默认上限 1 GB,超过会被 Flask 拒绝。若需要扫更大数据集,请改用「方式二:填本机绝对路径」。
---
## 限制
- 这个工具不会移除、破解或绕过任何水印;
- 不会伪造 C2PA 或 provenance metadata;
- 不能替代官方 SynthID 检测;
- FFT / DCT / LSB / Noise 异常都是统计启发式,不能直接证明 SynthID 或私有水印的存在;
- JPEG 等有损格式上 LSB 分析的可信度被自动降低;
- 拖拽上传依赖 Chromium / WebKit 系浏览器的 `webkitGetAsEntry` 能力,老版本浏览器可能只能拿到顶层文件;这种情况下请改用「方式二」。
---
## 目录结构
```
find_image_hide/
requirements.txt
analyze_image.py # CLI 入口
webapp.py # Flask Web UI(含 /api/scan、/api/scan_upload、/api/demo)
demo.py # 一键 demo
start.bat / start.sh # 跨平台启动脚本
image_forensics/ # 分析引擎
basic_info.py
metadata_analysis.py
ai_provenance_analysis.py
fft_analysis.py
dct_analysis.py
lsb_analysis.py
noise_analysis.py
extraction.py # trailing data + LSB 文本流提取
steganalysis.py # χ² POV / SPA 等
visible_watermark_ocr.py
phash_match.py
ela.py
scoring.py
analyzer.py
batch.py
utils.py
tools/
download_test_images.py # 真实公开样本下载
make_test_images.py # 合成 + 版权图样本
check_results.py # 期望表回归
test_images/ # demo 样本(运行后生成)
phash_reference/ # demo 参考库(运行后生成)
webui/
templates/ # Jinja2 模板(index.html / job.html / image.html)
static/ # app.css / app.js / image.js / job.js
analysis_output/ # 扫描结果(运行时生成)
/
_uploaded/ # 拖拽上传场景下的原始文件副本
summary.json
__/...
```