Metadata-Version: 2.4
Name: nearest-image-class
Version: 0.1.0
Summary: Embedding-based image classification using FAISS and DashScope API.
Author-email: marui199710 <marui199710@foxmail.com>
Maintainer-email: marui199710 <marui199710@foxmail.com>
License: MIT
Project-URL: Homepage, https://github.com/gokamisama/NearestImageClass
Project-URL: Repository, https://github.com/gokamisama/NearestImageClass
Project-URL: Documentation, https://github.com/gokamisama/NearestImageClass#readme
Project-URL: Bug Tracker, https://github.com/gokamisama/NearestImageClass/issues
Keywords: computer-vision,image-classification,embedding,faiss,dashscope,knn,retrieval
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.26.0
Requires-Dist: opencv-python>=4.8.0
Requires-Dist: pillow<13.0.0,>=9.0.0
Requires-Dist: faiss-cpu>=1.13.0
Requires-Dist: xxhash>=3.6.0
Requires-Dist: loguru>=0.6.0
Requires-Dist: tqdm>=4.60.0
Requires-Dist: dashscope<2.0.0,>=1.25.0
Dynamic: license-file

# nearest-image-class

基于嵌入向量（Embedding）和 FAISS 最近邻搜索的图像分类与检索工具包。底层调用 DashScope 通义千问视觉嵌入 API 生成图像向量，结合 FAISS 索引实现高效的相似度搜索与分类决策。

## ✨ 核心特性

- **嵌入向量检索**：基于 FAISS 实现高效的余弦相似度最近邻搜索，支持单条与批量查询。
- **多模态嵌入模型**：支持 DashScope 视觉嵌入模型，包括 `tongyi-embedding-vision-flash`、`tongyi-embedding-vision-plus` 和 `qwen3-vl-embedding`。
- **持久化存储**：使用 SQLite 持久化图像元数据与嵌入向量，支持增删改查与事务操作。
- **磁盘缓存**：嵌入向量支持 NPZ 格式磁盘缓存，避免对重复图像重复调用 API。
- **分类策略**：支持 `TOP_1`（最近邻类别）与 `MAJORITY_VOTE`（多数投票）两种分类决策策略。
- **线程安全**：FAISS 索引操作与数据库写操作均受可重入锁保护，支持并发场景。
- **配套工具脚本**：提供 GUI 审核录入、批量分类、图片聚类、去重、缓存预生成等实用工具。

## 📁 项目结构

```
nearest_image_class/
├── components/
│   ├── image_embedding.py      # 图像嵌入模型封装（DashScope API）
│   ├── faiss_manager.py        # FAISS 向量索引管理器
│   └── sqlite_manager.py       # SQLite 图像元数据管理器
├── tools/
│   ├── checker_plus.py         # GUI 图片审核录入工具
│   ├── classify_imgs.py        # 批量图片分类工具
│   ├── cluster_imgs.py         # 图片相似度聚类工具
│   ├── dedup_imgs.py           # 图片相似度去重工具
│   └── create_embedding_cache_file.py  # 预生成嵌入向量缓存
├── image_search_classifier.py  # 核心分类器（ImageSearchClassifier）
├── utils.py                    # 图像读取、编码、路径处理等通用工具
├── __init__.py
└── _version.py
```

## 🛠️ 环境要求

- Python >= 3.10
- Conda 或 venv 虚拟环境（推荐）

主要依赖：`numpy`, `opencv-python`, `pillow`, `faiss-cpu`, `dashscope`, `loguru`, `tqdm`, `xxhash`

## 📦 安装

### 1. 创建并激活 Conda 虚拟环境（推荐）

```bash
conda create -n nearest_image_class_env python=3.10 -y
conda activate nearest_image_class_env
```

### 2. 开发模式安装（可编辑安装）

适用于开发阶段，代码修改后无需重新安装即可生效：

```bash
pip install -e .
```

### 3. 普通安装（从源码安装）

```bash
pip install .
```

## 🚀 快速使用

### 初始化分类器

```python
from nearest_image_class.image_search_classifier import ImageSearchClassifier, ClassificationStrategy
from loguru import logger

classifier = ImageSearchClassifier(
    data_dir="./data",                                # 数据根目录
    model_name="tongyi-embedding-vision-flash-2026-03-06",  # 嵌入模型
    api_key="your-dashscope-api-key",                 # DashScope API 密钥
    dimension=768,                                    # 嵌入向量维度
    batch_size=20,                                    # 批量处理大小
    max_image_size=2048,                              # 图像长边最大尺寸
    max_workers=8,                                    # 并发线程数
    similarity_threshold=0.8,                         # 分类相似度阈值
    strategy=ClassificationStrategy.TOP_1,            # 分类策略
    top_k=5,                                          # 最近邻返回数量
    cache_file_path="./cache/embeddings.npz",         # 嵌入缓存路径（可选）
    logger=logger,
)
```

### 单张图像分类

```python
result = classifier.classify("path/to/image.jpg")
print(result)  # 输出预测的类别标签，若无可信结果则返回 None
```

### 批量图像分类

```python
images = ["path/to/img1.jpg", "path/to/img2.jpg"]
predictions = classifier.batch_classify(images)
print(predictions)
```

### 批量相似度搜索

```python
results_list = classifier.batch_search(images)
for results in results_list:
    for res in results:
        print(f"路径: {res.relative_image_path}, 类别: {res.category}, 相似度: {res.similarity_score:.4f}")
```

### 增量添加图片

向已有数据库中增量添加单张图片，自动更新索引，无需触发全量 rebuild：

```python
record_id = classifier.add_image("path/to/new_image.jpg", category="phone_case")
print(f"新增记录 ID: {record_id}")
```

### 相似度搜索

```python
results = classifier.search("path/to/image.jpg")
for res in results:
    print(f"路径: {res.relative_image_path}, 类别: {res.category}, 相似度: {res.similarity_score:.4f}")
```

### 释放资源

```python
classifier.close()
```

## 📂 数据目录约定

分类器要求图像数据按以下目录结构组织：

```
{data_dir}/
├── images/
│   ├── category_a/
│   │   ├── img_001.jpg
│   │   └── img_002.png
│   └── category_b/
│       └── img_003.jpg
└── images.db      # SQLite 数据库（自动创建）
```

- `{data_dir}/images/{category}/` 为图像存储路径，子目录名为类别标签。
- `images.db` 为自动创建的 SQLite 数据库，用于持久化图像路径、类别和嵌入向量。
- 初始化时会自动扫描 `images/` 目录，同步数据库并重建 FAISS 索引。

## 🧰 工具脚本

### checker_plus.py — GUI 图片审核录入工具

提供图形化界面进行图片审核：
- 左侧展示待审核图片列表，中间为图片预览
- 右侧实时显示相似图片推荐（Top-K 最近邻）
- 支持分类录入、忽略、一键忽略高相似度图片
- 自动检测疑似重复图片（相似度 ≥ 阈值时标记为不推荐录入）

```python
from tkinter import Tk
from nearest_image_class.tools.checker_plus import ImageReviewTool

root = Tk()
app = ImageReviewTool(
    root=root,
    data_dir="./data",
    model_name="tongyi-embedding-vision-flash-2026-03-06",
    api_key="your-api-key",
    dimension=768,
    batch_size=20,
    max_image_size=2048,
    max_workers=1,
    top_k=5,
    duplicate_threshold=0.97,
    similarity_threshold=0.8,
    cache_file_path="./cache/embeddings.npz",
)
root.mainloop()
```

### classify_imgs.py — 批量图片分类

对输入目录下的图片进行批量分类，按类别输出到子目录：

```python
from nearest_image_class.tools.classify_imgs import classify_imgs

classify_imgs(
    input_dir="./待分类图片",
    output_dir="./分类结果",
    data_dir="./data",
    model_name="tongyi-embedding-vision-flash-2026-03-06",
    api_key="your-api-key",
    dimension=768,
    batch_size=20,
    max_image_size=2048,
    strategy="top_1",          # 或 "majority_vote"
    similarity_threshold=0.8,
)
```

### dedup_imgs.py — 图片相似度去重

对输入目录内的图片进行全局去重，保留的图片输出到指定目录，重复图片可单独存放：

```python
from nearest_image_class.tools.dedup_imgs import dedup_imgs

dedup_imgs(
    input_dir="./待去重图片",
    output_dir="./去重后",
    duplicate_dir="./重复图片",    # 可选
    model_name="tongyi-embedding-vision-flash-2026-03-06",
    api_key="your-api-key",
    dimension=768,
    similarity_threshold=0.95,     # 去重阈值
)
```

### cluster_imgs.py — 图片相似度聚类

对输入目录内的图片按相似度自动聚类，相似图片归入同一 `cluster_xxx` 目录，孤立的图片放入 `未分类`：

```python
from nearest_image_class.tools.cluster_imgs import cluster_imgs

cluster_imgs(
    input_dir="./待聚类图片",
    output_dir="./聚类结果",
    model_name="tongyi-embedding-vision-flash-2026-03-06",
    api_key="your-api-key",
    dimension=768,
    batch_size=20,
    max_image_size=2048,
    similarity_threshold=0.85,     # 聚类相似度阈值
    min_cluster_size=1,            # 最小聚类大小
)
```

### create_embedding_cache_file.py — 预生成嵌入缓存

从指定目录批量生成图片嵌入向量并保存为 NPZ 缓存文件，便于后续重复使用：

```python
from nearest_image_class.tools.create_embedding_cache_file import create_embedding_cache_file

create_embedding_cache_file(
    image_dir="./图片目录",
    cache_file_path="./cache/embeddings.npz",
    api_key="your-api-key",
    model_name="tongyi-embedding-vision-flash-2026-03-06",
    dimension=768,
)
```

## ⚙️ 配置参数说明

| 参数 | 说明 | 典型值 |
|---|---|---|
| `data_dir` | 数据根目录 | `"./data"` |
| `model_name` | DashScope 嵌入模型名称 | `"tongyi-embedding-vision-flash-2026-03-06"` |
| `dimension` | 嵌入向量维度 | `768`（flash）、`1024`（plus） |
| `batch_size` | API 批量处理大小 | `20`（flash/plus）、`1`（qwen3-vl） |
| `max_image_size` | 图像预处理时长边最大尺寸 | `2048` |
| `max_workers` | 并发线程数 | `8` |
| `similarity_threshold` | 分类/去重相似度阈值 | `0.8`（分类）、`0.95`（去重） |
| `top_k` | 最近邻搜索返回结果数 | `5` |
| `strategy` | 分类策略 | `"top_1"` / `"majority_vote"` |
| `cache_file_path` | 嵌入向量缓存文件路径（NPZ） | `"./cache/embeddings.npz"` |

## 🏗️ 构建分发包

首先安装构建工具：

```bash
pip install build
```

然后在项目根目录运行：

```bash
python -m build
```

构建完成后，`dist/` 目录将包含两个文件：
- `nearest_image_class-<VERSION>.tar.gz`（源码分发包，sdist）
- `nearest_image_class-<VERSION>-py3-none-any.whl`（二进制分发包，wheel）

> ✅ 推荐始终通过 `python -m build` 构建，而非直接调用 `setup.py`。

## 📤 上传到 PyPI

#### 步骤 1：安装上传工具
```bash
pip install twine
```

#### 步骤 2：验证分发包（可选但推荐）
```bash
twine check dist/*
```

#### 步骤 3：上传到 TestPyPI（测试）
```bash
twine upload --repository testpypi dist/*
```
> 需要 [TestPyPI 账号](https://test.pypi.org/)。

#### 步骤 4：上传到正式 PyPI
```bash
twine upload dist/*
```
> 需要 [PyPI 账号](https://pypi.org/) 并配置 API Token（推荐使用 `__token__` 作为用户名）。

> 🔐 **安全提示**：建议使用 [API Token](https://pypi.org/help/#apitoken) 而非密码进行上传。

## 📝 注意事项

- 确保项目根目录包含 `LICENSE` 和 `README.md`，它们会被自动包含在分发包中。
- **版本号由 `nearest_image_class/_version.py` 中的 `__version__` 变量控制**，例如：
  ```python
  # nearest_image_class/_version.py
  __version__ = "0.1.0"
  ```
- 每次上传 PyPI 前**必须更新 `__version__` 的值**（PyPI 不允许重复版本号）。
