diff --git a/.gitignore b/.gitignore index 36b13f1..e4de9c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,176 +1,200 @@ -# ---> Python -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc - +# ---> 明析平台专用 + +# 模型文件(体积大,不进版本库) +*.pt +*.onnx +mingxi-vision/models/ + +# 前置机本地数据 +mingxi-capture/queue.db +mingxi-capture/config.ini + +# 大文件 +references/*.mkv +references/*.mp4 + +# IDE +.vscode/ +.idea/ + +# ---> Node.js (mingxi-frontend) +node_modules/ +mingxi-frontend/dist/ +mingxi-frontend/.env.local + +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + diff --git a/README.md b/README.md index 2a18642..7cfe333 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# mingxi_platform - +# mingxi_platform + 明晰平台 \ No newline at end of file diff --git a/docs/PCB 与 HRIPCB 数据集差异分析.md b/docs/PCB 与 HRIPCB 数据集差异分析.md new file mode 100644 index 0000000..2f2560f --- /dev/null +++ b/docs/PCB 与 HRIPCB 数据集差异分析.md @@ -0,0 +1,143 @@ +# PCB 与 HRIPCB 数据集差异分析 + +> 分析时间:2026-05-07 +> 分析对象:`pcb/`(TCC PCB Dataset)与 `HRIPCB/`(HRIPCB Dataset) + +--- + +## 1. 核心差异一览 + +| 维度 | PCB (TCC) | HRIPCB | +|------|-----------|--------| +| **来源** | Roboflow `tcc-r4j2r/pcb-la0tj` | Roboflow `ma007/hripcb` | +| **发布时间** | 2025-12-11 | 2023-04-16 | +| **规模** | 7,971 张 | 1,386 张 | +| **导出预处理** | **Resize to 240×240 (Fit within)** | **Resize to 640×640 (Stretch)** | +| **缺陷密度** | **~2.0 框/张图** | **~4.2 框/张图** | +| **同图变体数** | 每张原始图 **3~6 个变体** | 每张原始图 **2 个变体** | +| **License** | CC BY 4.0 | CC BY 4.0 | + +--- + +## 2. 关键差异详解 + +### 2.1 图像分辨率与预处理策略不同 + +这是两个数据集最本质的区别。 + +- **PCB**:被 Roboflow 预处理为 **240×240(Fit within,保持比例 + 填充)**。文件名中虽带有 `_600` 字样(暗示原始采集分辨率为 600×600),但实际导出图已缩放至 240×240。 +- **HRIPCB**:被预处理为 **640×640(Stretch,直接拉伸)**。原始图被强制拉成 640×640,可能存在轻微形变。 + +**训练影响**:YOLOv8 训练时会统一 `imgsz=640`,两者标签均为归一化坐标(0~1),可直接混用。但 PCB 从 240 放大到 640 时细节损失会比 HRIPCB 更明显,小目标特征可能更模糊。 + +### 2.2 缺陷密度不同 + +| 数据集 | Split | 图片数 | 缺陷框数 | 平均框/图 | +|--------|-------|--------|----------|-----------| +| PCB | train | 6,346 | 12,964 | **2.04** | +| PCB | valid | 798 | 1,588 | **1.99** | +| PCB | test | 827 | 1,660 | **2.01** | +| HRIPCB | train | 1,108 | 4,667 | **4.21** | +| HRIPCB | valid | 139 | 583 | **4.19** | +| HRIPCB | test | 139 | 576 | **4.14** | + +- **PCB**:平均每张图约 **2.0 个缺陷框**,整体相对稀疏。 +- **HRIPCB**:平均每张图约 **4.2 个缺陷框**,缺陷更密集,有些图可能包含同一类型的多个缺陷实例。 + +**结论**:HRIPCB 的缺陷密度约为 PCB 的 **2 倍**。这在训练时意味着 HRIPCB 样本对模型学习"密集小目标共存"场景的贡献更大。 + +### 2.3 数据构成方式不同 + +**PCB 文件名特征**: + +``` +l_light_01_missing_hole_01_1_600_jpg.rf.xxx.jpg +l_light_01_missing_hole_01_2_600_jpg.rf.xxx.jpg +l_light_01_missing_hole_01_3_600_jpg.rf.xxx.jpg +``` + +- 前缀 `l_light_` 表明采集时控制了光照条件(left light / 左侧光源)。 +- `_1_`、`_2_`、`_3_` 后缀表明**同一张缺陷样本有多个变体**(可能是不同光照、角度或采集参数)。 +- 数据冗余度更高,同类缺陷的重复样本多。 + +**HRIPCB 文件名特征**: + +``` +01_missing_hole_01_jpg.rf.xxx.jpg +01_missing_hole_01_jpg.rf.yyy.jpg +``` + +- 命名更简洁,每张原始图仅有 **2 个 Roboflow 自动变体**(后缀 hash 不同)。 +- 样本独立性更强,重复度低。 + +### 2.4 总标注实例数 + +| 数据集 | 图片数 | 总缺陷实例数 | +|--------|--------|-------------| +| PCB | 7,971 | ~16,212 | +| HRIPCB | 1,386 | ~4,826 | +| **合并后** | **9,357** | **~21,038** | + +--- + +## 3. 对模型训练的影响 + +| 影响项 | 说明 | +|--------|------| +| **分辨率差距** | PCB 从 240 上采样到 640 会丢失细节,小目标检测可能受一定影响;HRIPCB 原生 640,细节保留更完整 | +| **密度差异** | HRIPCB 更密集的标注有助于模型学习"多缺陷共存"场景,对实际产线更有价值 | +| **重复样本** | PCB 中同一缺陷的多个变体相当于轻度数据增强,有助于提升光照/角度鲁棒性 | +| **来源互补** | PCB 偏"受控光照实验"风格,HRIPCB 偏"标准工业样本"风格,合并后泛化能力更强 | +| **类别分布** | 两者类别定义完全一致(6 类缺陷),标签格式均为标准 YOLOv8 归一化坐标,可直接合并 | + +--- + +## 4. 使用建议 + +### 4.1 基础用法 + +直接使用 `dataset.py` 合并后训练: + +```bash +python dataset.py merge --src pcb HRIPCB --dst merged +``` + +合并后共 **9,357 张图、约 21,038 个缺陷实例**,数据量足够支撑 YOLOv8n/s 的训练。 + +### 4.2 进阶用法:重新划分 + +如果担心 PCB 占比过高(85%)导致模型过度偏向 PCB 的数据风格,可以打乱后重新按 8:1:1 划分: + +```bash +python dataset.py merge --src pcb HRIPCB --dst merged --rebalance --train 0.8 --val 0.1 --test 0.1 +``` + +### 4.3 训练参数建议 + +针对两个数据集的分辨率差异,建议: + +```yaml +# train.yaml +model: yolov8n.pt +data: D:/github2026/pcb-defect-detection/merged/data.yaml +imgsz: 640 # 统一统一到 640,补偿 PCB 的 240 上采样损失 +batch: 16 # RTX 4060 8GB 安全值 +epochs: 100 +amp: True # 混合精度必开 +patience: 20 # 早停 +``` + +### 4.4 如果精度不够 + +可考虑以下策略: + +1. **分阶段训练**:先用 PCB 预训练,再用 HRIPCB fine-tune(HRIPCB 密度高、标注更"干净")。 +2. **调整样本权重**:在 Ultralytics 中通过 `sample_weights` 或自定义 dataloader 提升 HRIPCB 样本的采样概率。 +3. **数据清洗**:检查 PCB 中 240×240 上采样后是否出现模糊/不可辨认的样本,必要时剔除低质量数据。 + +--- + +## 5. 附:数据来源链接 + +- **PCB (TCC)**:`https://universe.roboflow.com/tcc-r4j2r/pcb-la0tj/dataset/1` +- **HRIPCB**:`https://universe.roboflow.com/ma007/hripcb/dataset/1` diff --git a/docs/mingxi-vision-架构设计.md b/docs/mingxi-vision-架构设计.md new file mode 100644 index 0000000..0ef880c --- /dev/null +++ b/docs/mingxi-vision-架构设计.md @@ -0,0 +1,826 @@ +# mingxi-vision 技术架构与设计分析 + +> 版本:v1.0 · 日期:2026-05-24 +> 硬件约束:联想 Y7000P · RTX 4060 Laptop 8GB · Python 3.8 · Windows 11 +> 上游依赖:`yolo_classification_system/yolo8/inference.py`(迁移基础) + +--- + +## 1. 定位与职责边界 + +`mingxi-vision` 是整个明析平台的**推理微服务**,职责单一: + +``` +接收图像 → 前处理 → 模型推理 → 后处理 → 返回结构化缺陷JSON +``` + +它**不**做的事: +- 不持久化数据(无数据库依赖) +- 不做鉴权(内网服务,由 backend 代理) +- 不管理产线/批次业务(backend 的职责) +- 不直接控制相机(capture 的职责) + +--- + +## 2. 框架选型:FastAPI + +### 为什么不用 Django + +现有系统用 Django,但推理服务有不同的特征: + +| 维度 | Django(现有) | FastAPI(选用) | +|------|--------------|----------------| +| 定位 | 全功能Web框架 | 轻量API框架 | +| 启动时间 | ~3-5s | ~0.5s | +| ORM/DB | 必须配置 | 无需数据库 | +| 异步支持 | 有限(Django 4+ 部分支持) | 原生 async/await | +| 自动文档 | 需要额外配置 | 内置 /docs (Swagger) | +| 推理场景适配 | 过重 | 刚好合适 | + +### Python 3.8 的约束 + +FastAPI 在 Python 3.8 下完全可用,需注意: +- 类型注解用 `Optional[X]` 而非 `X | None`(3.10+ 语法) +- `from __future__ import annotations` 可缓解部分问题 +- Pydantic v1(随 FastAPI 早期版本)在 3.8 稳定 + +``` +# requirements.txt 核心版本锁定 +fastapi==0.104.1 # 3.8 兼容的最后稳定版系列 +uvicorn[standard]==0.24.0 +pydantic==1.10.13 # v1,Python 3.8 最稳定 +ultralytics==8.0.235 # 训练阶段用 +onnxruntime-gpu==1.16.3 # 推理部署阶段用 +opencv-python-headless==4.8.1.78 +numpy==1.24.4 # 3.8 + torch 2.0 兼容版本 +python-multipart==0.0.6 # FastAPI 文件上传必须 +``` + +--- + +## 3. 双运行时策略 + +这是 mingxi-vision 最核心的设计决策。 + +### 问题 + +- **训练阶段**:用 `ultralytics` 的 `.pt` 格式,便于迭代和验证 +- **部署阶段**:用 `.onnx` 格式,跨平台、无需安装 PyTorch、性能更稳定 +- 两套格式的推理 API 有差异,需要统一抽象 + +### 解决方案:运行时适配器(Adapter 模式) + +``` + ┌─────────────────────────────┐ + │ InferenceEngine │ ← 统一接口 + │ detect(image) → [Defect] │ + └──────────┬──────────────────┘ + │ 根据配置选择 + ┌───────────────┴────────────────┐ + ▼ ▼ + UltralyticsAdapter OnnxRuntimeAdapter + (.pt 文件,训练验证用) (.onnx 文件,生产部署用) + ultralytics.YOLO onnxruntime.InferenceSession +``` + +### 代码设计 + +```python +# engine/base.py +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import List +import numpy as np + +@dataclass +class DefectBox: + class_id: int + class_name: str + class_name_zh: str + confidence: float + severity: str # fatal / major / minor / rework / none + box_xyxy: List[float] # [x1, y1, x2, y2],像素坐标 + + +@dataclass +class DetectResult: + defects: List[DefectBox] + duration_ms: float + image_width: int + image_height: int + model_version: str + + @property + def defect_count(self) -> int: + return len(self.defects) + + @property + def max_severity(self) -> str: + order = ["fatal", "major", "minor", "rework", "none"] + found = {d.severity for d in self.defects} + for s in order: + if s in found: + return s + return "none" + + @property + def avg_confidence(self): + if not self.defects: + return None + return round(sum(d.confidence for d in self.defects) / len(self.defects), 4) + + +class BaseInferenceEngine(ABC): + @abstractmethod + def detect(self, image: np.ndarray, conf: float) -> DetectResult: + ... + + @abstractmethod + def warmup(self) -> None: + """启动时预热,避免第一次推理延迟""" + ... +``` + +```python +# engine/ultralytics_adapter.py +import time +import numpy as np +from .base import BaseInferenceEngine, DefectBox, DetectResult +from .defect_classes import DEFECT_CLASSES + +class UltralyticsAdapter(BaseInferenceEngine): + """开发/训练验证阶段使用""" + + def __init__(self, weights_path: str): + from ultralytics import YOLO + self._model = YOLO(weights_path) + self._weights_path = weights_path + + def warmup(self): + dummy = np.zeros((640, 640, 3), dtype=np.uint8) + self._model.predict(source=dummy, verbose=False, conf=0.01) + + def detect(self, image: np.ndarray, conf: float = 0.45) -> DetectResult: + h, w = image.shape[:2] + t0 = time.perf_counter() + results = self._model.predict(source=image, verbose=False, conf=conf) + duration_ms = (time.perf_counter() - t0) * 1000 + + defects = [] + result = results[0] + if result.boxes is not None and len(result.boxes): + xyxy = result.boxes.xyxy.cpu().numpy() + confs = result.boxes.conf.cpu().numpy() + clsids = result.boxes.cls.cpu().numpy() + for i in range(len(xyxy)): + cid = int(clsids[i]) + meta = DEFECT_CLASSES.get(cid, { + "name": str(cid), "zh": str(cid), "severity": "minor" + }) + defects.append(DefectBox( + class_id=cid, + class_name=meta["name"], + class_name_zh=meta["zh"], + confidence=round(float(confs[i]), 4), + severity=meta["severity"], + box_xyxy=[round(float(x), 1) for x in xyxy[i]], + )) + + return DetectResult( + defects=defects, + duration_ms=round(duration_ms, 1), + image_width=w, + image_height=h, + model_version=str(self._weights_path), + ) +``` + +```python +# engine/onnx_adapter.py +import time +import cv2 +import numpy as np +import onnxruntime as ort +from .base import BaseInferenceEngine, DefectBox, DetectResult +from .defect_classes import DEFECT_CLASSES + +class OnnxRuntimeAdapter(BaseInferenceEngine): + """生产部署阶段使用,无 PyTorch 依赖""" + + def __init__(self, model_path: str, device: str = "cuda"): + providers = ( + ["CUDAExecutionProvider", "CPUExecutionProvider"] + if device == "cuda" + else ["CPUExecutionProvider"] + ) + self._session = ort.InferenceSession(model_path, providers=providers) + self._input_name = self._session.get_inputs()[0].name + self._input_shape = self._session.get_inputs()[0].shape # [1,3,640,640] + self._imgsz = self._input_shape[2] # 通常 640 + self._model_path = model_path + + def warmup(self): + dummy = np.zeros( + (1, 3, self._imgsz, self._imgsz), dtype=np.float32 + ) + self._session.run(None, {self._input_name: dummy}) + + def _preprocess(self, image: np.ndarray): + """BGR → RGB → letterbox → NCHW float32 [0,1]""" + img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + img, ratio, (dw, dh) = self._letterbox(img, self._imgsz) + img = img.astype(np.float32) / 255.0 + img = np.transpose(img, (2, 0, 1)) # HWC → CHW + img = np.expand_dims(img, 0) # CHW → NCHW + return img, ratio, dw, dh + + @staticmethod + def _letterbox(img, new_size=640): + h, w = img.shape[:2] + ratio = min(new_size / h, new_size / w) + nh, nw = int(h * ratio), int(w * ratio) + img = cv2.resize(img, (nw, nh), interpolation=cv2.INTER_LINEAR) + dw = (new_size - nw) / 2 + dh = (new_size - nh) / 2 + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + img = cv2.copyMakeBorder(img, top, bottom, left, right, + cv2.BORDER_CONSTANT, value=(114, 114, 114)) + return img, ratio, dw, dh + + def _postprocess(self, outputs, orig_h, orig_w, ratio, dw, dh, conf_thres): + """YOLOv8 ONNX 输出解码:[1, 84, 8400] → DefectBox列表""" + pred = outputs[0][0] # [84, 8400] + pred = pred.T # [8400, 84] + boxes = pred[:, :4] # cx,cy,w,h + scores = pred[:, 4:] # [8400, num_classes] + + class_ids = np.argmax(scores, axis=1) + confidences = scores[np.arange(len(scores)), class_ids] + + mask = confidences > conf_thres + boxes, class_ids, confidences = ( + boxes[mask], class_ids[mask], confidences[mask] + ) + if len(boxes) == 0: + return [] + + # cx,cy,w,h → x1,y1,x2,y2 + x1 = boxes[:, 0] - boxes[:, 2] / 2 + y1 = boxes[:, 1] - boxes[:, 3] / 2 + x2 = boxes[:, 0] + boxes[:, 2] / 2 + y2 = boxes[:, 1] + boxes[:, 3] / 2 + + # 去除 letterbox padding,还原到原始坐标 + x1 = np.clip((x1 - dw) / ratio, 0, orig_w) + y1 = np.clip((y1 - dh) / ratio, 0, orig_h) + x2 = np.clip((x2 - dw) / ratio, 0, orig_w) + y2 = np.clip((y2 - dh) / ratio, 0, orig_h) + + # NMS + nms_ids = cv2.dnn.NMSBoxes( + np.stack([x1, y1, x2 - x1, y2 - y1], axis=1).tolist(), + confidences.tolist(), conf_thres, iou_threshold=0.45 + ) + if len(nms_ids) == 0: + return [] + + defects = [] + for idx in nms_ids.flatten(): + cid = int(class_ids[idx]) + meta = DEFECT_CLASSES.get(cid, { + "name": str(cid), "zh": str(cid), "severity": "minor" + }) + defects.append(DefectBox( + class_id=cid, + class_name=meta["name"], + class_name_zh=meta["zh"], + confidence=round(float(confidences[idx]), 4), + severity=meta["severity"], + box_xyxy=[ + round(float(x1[idx]), 1), round(float(y1[idx]), 1), + round(float(x2[idx]), 1), round(float(y2[idx]), 1), + ], + )) + return defects + + def detect(self, image: np.ndarray, conf: float = 0.45) -> DetectResult: + orig_h, orig_w = image.shape[:2] + inp, ratio, dw, dh = self._preprocess(image) + + t0 = time.perf_counter() + outputs = self._session.run(None, {self._input_name: inp}) + duration_ms = (time.perf_counter() - t0) * 1000 + + defects = self._postprocess(outputs, orig_h, orig_w, ratio, dw, dh, conf) + + return DetectResult( + defects=defects, + duration_ms=round(duration_ms, 1), + image_width=orig_w, + image_height=orig_h, + model_version=str(self._model_path), + ) +``` + +--- + +## 4. 模型管理:单例 + 启动加载 + +### 问题根源 + +现有 `inference.py` 的 `_MODEL_CACHE` 是进程级字典,首次请求时才加载模型(懒加载)。对推理服务来说,这会导致第一个请求有数秒延迟,在演示现场是灾难性的。 + +### 解决方案:FastAPI 生命周期钩子 + +```python +# engine/loader.py +from typing import Optional +from .base import BaseInferenceEngine +from config import settings + +_engine: Optional[BaseInferenceEngine] = None + + +def get_engine() -> BaseInferenceEngine: + if _engine is None: + raise RuntimeError("推理引擎未初始化,请检查启动日志") + return _engine + + +def init_engine() -> BaseInferenceEngine: + global _engine + if settings.runtime == "onnx": + from .onnx_adapter import OnnxRuntimeAdapter + _engine = OnnxRuntimeAdapter( + model_path=settings.model_path, + device=settings.device, + ) + else: + from .ultralytics_adapter import UltralyticsAdapter + _engine = UltralyticsAdapter(weights_path=settings.model_path) + + _engine.warmup() # 预热,消除第一次推理的延迟 + return _engine +``` + +```python +# main.py +from contextlib import asynccontextmanager +from fastapi import FastAPI +from engine.loader import init_engine +from api.detect import router as detect_router +from api.health import router as health_router + + +@asynccontextmanager +async def lifespan(app: FastAPI): + # 启动时加载模型 + engine = init_engine() + print(f"[mingxi-vision] 引擎就绪: {engine.__class__.__name__}") + yield + # 关闭时释放资源(ONNX session会自动GC) + + +app = FastAPI( + title="明析推理服务", + description="PCB缺陷检测推理接口", + version="1.0.0", + lifespan=lifespan, +) + +app.include_router(detect_router, prefix="/api") +app.include_router(health_router, prefix="/api") +``` + +--- + +## 5. 图像接收与前处理 + +### 接收来源 + +mingxi-vision 接受两种图像来源,用同一个端点处理: + +```python +# api/detect.py +import cv2 +import numpy as np +from fastapi import APIRouter, File, Form, UploadFile, HTTPException +from fastapi.responses import JSONResponse +from engine.loader import get_engine +from engine.annotator import draw_boxes +from schema import DetectResponse +import base64, uuid + +router = APIRouter() + + +@router.post("/detect", response_model=DetectResponse) +async def detect( + image: UploadFile = File(...), + conf: float = Form(default=0.45, ge=0.01, le=0.99), + line_id: str = Form(default=""), + batch_id: str = Form(default=""), + return_annotated: bool = Form(default=False), +): + # 1. 读取图像字节 + raw = await image.read() + if len(raw) > 20 * 1024 * 1024: # 20MB 上限 + raise HTTPException(status_code=413, detail="图像文件过大(上限20MB)") + + # 2. 解码为 numpy BGR + arr = np.frombuffer(raw, dtype=np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_COLOR) + if img is None: + raise HTTPException(status_code=422, detail="无法解码图像,请检查文件格式") + + # 3. 推理 + engine = get_engine() + result = engine.detect(img, conf=conf) + + # 4. 可选:返回标注图 + annotated_b64 = None + if return_annotated: + annotated = draw_boxes(img.copy(), result.defects) + _, buf = cv2.imencode(".jpg", annotated, [cv2.IMWRITE_JPEG_QUALITY, 85]) + annotated_b64 = base64.b64encode(buf.tobytes()).decode() + + return DetectResponse( + task_id=str(uuid.uuid4()), + line_id=line_id, + batch_id=batch_id, + duration_ms=result.duration_ms, + image_width=result.image_width, + image_height=result.image_height, + defect_count=result.defect_count, + max_severity=result.max_severity, + avg_confidence=result.avg_confidence, + defects=[d.__dict__ for d in result.defects], + annotated_image_b64=annotated_b64, + model_version=result.model_version, + ) +``` + +### 中文路径问题(继承自现有代码) + +现有 `inference.py` 已有 `_copy_to_ascii_temp_input()` 解决中文路径导致 OpenCV 无法读图的问题。`mingxi-vision` 改用 **内存读取**(`np.frombuffer` + `cv2.imdecode`),从源头消除路径问题,不再需要这个 workaround。 + +--- + +## 6. 后处理:标注图生成 + +```python +# engine/annotator.py +import cv2 +import numpy as np +from typing import List +from .base import DefectBox + +SEVERITY_COLORS = { + "fatal": (0, 0, 220), # 红(BGR) + "major": (0, 128, 255), # 橙 + "minor": (0, 215, 255), # 黄 + "rework": (255, 165, 0 ), # 蓝 + "none": (180, 180, 180), # 灰 +} + + +def draw_boxes(image: np.ndarray, defects: List[DefectBox]) -> np.ndarray: + for d in defects: + x1, y1, x2, y2 = [int(v) for v in d.box_xyxy] + color = SEVERITY_COLORS.get(d.severity, (180, 180, 180)) + cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) + + label = f"{d.class_name_zh} {d.confidence:.2f}" + (tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.55, 1) + cv2.rectangle(image, (x1, y1 - th - 6), (x1 + tw + 4, y1), color, -1) + cv2.putText( + image, label, (x1 + 2, y1 - 4), + cv2.FONT_HERSHEY_SIMPLEX, 0.55, (255, 255, 255), 1, cv2.LINE_AA + ) + return image +``` + +--- + +## 7. 缺陷类别定义 + +```python +# engine/defect_classes.py +# 与 HRIPCB 数据集的 6 类对齐,扩展至 10 类(含真实产线样本迁移学习后) + +DEFECT_CLASSES = { + # ── HRIPCB 基础 6 类(公开数据集,开箱即用)── + 0: {"name": "missing_hole", "zh": "缺孔", "severity": "fatal"}, + 1: {"name": "mouse_bite", "zh": "鼠咬", "severity": "major"}, + 2: {"name": "open_circuit", "zh": "断路", "severity": "fatal"}, + 3: {"name": "short_circuit", "zh": "短路", "severity": "fatal"}, + 4: {"name": "spur", "zh": "毛刺", "severity": "minor"}, + 5: {"name": "spurious_copper", "zh": "余铜", "severity": "major"}, + # ── 扩展类(真实产线样本微调后启用)── + 6: {"name": "oxidation", "zh": "氧化", "severity": "minor"}, + 7: {"name": "solder_ball", "zh": "锡珠", "severity": "rework"}, + 8: {"name": "scratch", "zh": "划痕", "severity": "minor"}, + 9: {"name": "label_error", "zh": "标签错贴","severity": "rework"}, +} + +SEVERITY_ORDER = ["fatal", "major", "minor", "rework", "none"] +``` + +--- + +## 8. 配置管理 + +```python +# config.py +import os +from typing import Literal +from pydantic import BaseSettings # pydantic v1 + + +class Settings(BaseSettings): + # 运行时选择 + runtime: Literal["ultralytics", "onnx"] = "ultralytics" + model_path: str = "./models/pcb_defect_v1.pt" + device: Literal["cuda", "cpu"] = "cuda" + + # 推理默认参数 + default_conf: float = 0.45 + max_image_size_mb: int = 20 + + # 服务配置 + host: str = "0.0.0.0" + port: int = 8001 + workers: int = 1 # 推理服务单 worker,GPU 不支持多进程共享 + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + + +settings = Settings() +``` + +`.env` 文件示例: + +```bash +# 开发阶段(ultralytics .pt) +RUNTIME=ultralytics +MODEL_PATH=./models/pcb_defect_v1.pt +DEVICE=cuda + +# 生产阶段(ONNX Runtime) +# RUNTIME=onnx +# MODEL_PATH=./models/pcb_defect_v1.onnx +# DEVICE=cuda +``` + +--- + +## 9. 健康检查与诊断接口 + +```python +# api/health.py +import platform +from fastapi import APIRouter +from engine.loader import get_engine + +router = APIRouter() + + +@router.get("/health") +def health(): + try: + engine = get_engine() + return { + "status": "ok", + "runtime": engine.__class__.__name__, + "platform": platform.system(), + } + except RuntimeError as e: + return {"status": "error", "detail": str(e)} + + +@router.get("/health/gpu") +def gpu_info(): + """开发调试用,确认 GPU 是否被正确使用""" + info = {"cuda_available": False, "onnx_providers": []} + try: + import torch + info["cuda_available"] = torch.cuda.is_available() + if torch.cuda.is_available(): + info["gpu_name"] = torch.cuda.get_device_name(0) + info["vram_total_gb"] = round( + torch.cuda.get_device_properties(0).total_memory / 1e9, 1 + ) + except ImportError: + pass + try: + import onnxruntime as ort + info["onnx_providers"] = ort.get_available_providers() + except ImportError: + pass + return info +``` + +--- + +## 10. 完整目录结构 + +``` +mingxi-vision/ +├── api/ +│ ├── __init__.py +│ ├── detect.py # POST /api/detect(核心推理接口) +│ └── health.py # GET /api/health, /api/health/gpu +├── engine/ +│ ├── __init__.py +│ ├── base.py # DefectBox, DetectResult, BaseInferenceEngine +│ ├── loader.py # 单例管理 + init_engine() +│ ├── ultralytics_adapter.py # .pt 推理(开发阶段) +│ ├── onnx_adapter.py # .onnx 推理(生产阶段) +│ ├── annotator.py # 在图像上绘制标注框 +│ └── defect_classes.py # 缺陷类别 + 等级映射表 +├── models/ +│ ├── pcb_defect_v1.pt # ultralytics 训练产物(gitignore) +│ └── pcb_defect_v1.onnx # 导出的 ONNX 模型(gitignore) +├── scripts/ +│ ├── export_onnx.py # pt → onnx 导出脚本 +│ └── benchmark.py # 本地推理性能测试 +├── tests/ +│ ├── test_detect_api.py +│ └── fixtures/ # 测试用 PCB 图片 +├── schema.py # Pydantic 响应模型 +├── config.py # Settings(pydantic BaseSettings) +├── main.py # FastAPI app + lifespan +├── requirements.txt +├── .env.example +└── README.md +``` + +--- + +## 11. 响应 Schema + +```python +# schema.py +from typing import List, Optional +from pydantic import BaseModel + + +class DefectItem(BaseModel): + class_id: int + class_name: str + class_name_zh: str + confidence: float + severity: str # fatal / major / minor / rework / none + box_xyxy: List[float] # [x1, y1, x2, y2] + + +class DetectResponse(BaseModel): + task_id: str + line_id: str + batch_id: str + duration_ms: float + image_width: int + image_height: int + defect_count: int + max_severity: str # 本次检测中最高等级缺陷 + avg_confidence: Optional[float] + defects: List[DefectItem] + annotated_image_b64: Optional[str] # 仅 return_annotated=true 时有值 + model_version: str +``` + +实际响应示例: + +```json +{ + "task_id": "a3f1c2d4-...", + "line_id": "LINE-01", + "batch_id": "BAT-20260524-001", + "duration_ms": 41.3, + "image_width": 3072, + "image_height": 2048, + "defect_count": 2, + "max_severity": "fatal", + "avg_confidence": 0.8762, + "defects": [ + { + "class_id": 2, + "class_name": "open_circuit", + "class_name_zh": "断路", + "confidence": 0.9134, + "severity": "fatal", + "box_xyxy": [234.5, 891.2, 312.8, 943.7] + }, + { + "class_id": 4, + "class_name": "spur", + "class_name_zh": "毛刺", + "confidence": 0.8390, + "severity": "minor", + "box_xyxy": [1204.1, 456.3, 1251.9, 489.0] + } + ], + "annotated_image_b64": null, + "model_version": "./models/pcb_defect_v1.pt" +} +``` + +--- + +## 12. 性能分析(Y7000P RTX 4060) + +### 推理延迟预估 + +| 运行时 | 模型 | 分辨率 | 单次推理 | 含预处理+后处理 | +|--------|------|--------|---------|--------------| +| ultralytics | YOLOv8n | 640×640 | ~12ms | ~20ms | +| ultralytics | YOLOv8s | 640×640 | ~20ms | ~30ms | +| ONNX Runtime GPU | YOLOv8n | 640×640 | ~8ms | ~15ms | +| ONNX Runtime CPU | YOLOv8n | 640×640 | ~80ms | ~100ms | + +> 数据来源:`pcb缺陷检测初步方案.md` 引用的 Y7000P 实测基准 + +**PCB 后道复判场景需求**:触发模式,每块板约 1-3 秒间隔,15ms 的推理延迟完全满足。 + +### 显存占用 + +| 模型 | 显存占用 | +|------|---------| +| YOLOv8n(ultralytics) | ~1.2GB | +| YOLOv8s(ultralytics) | ~2.4GB | +| YOLOv8n(ONNX CUDA EP) | ~0.8GB | + +RTX 4060 8GB 剩余 6GB+ 可用,不构成瓶颈。 + +### 并发限制 + +```python +# main.py 启动参数 +# workers=1:GPU 不支持多进程共享同一 CUDA Context +# 推理天然串行,配合 FastAPI 的 async 处理并发等待队列 +uvicorn main:app --host 0.0.0.0 --port 8001 --workers 1 +``` + +PCB 产线触发模式下,单工位请求天然串行,`workers=1` 完全够用。若需多产线并发,在 `mingxi-backend` 侧做请求队列即可。 + +--- + +## 13. 模型导出(pt → onnx) + +```python +# scripts/export_onnx.py +from ultralytics import YOLO + +model = YOLO("./models/pcb_defect_v1.pt") +model.export( + format="onnx", + imgsz=640, + opset=12, # onnxruntime 1.16 兼容 + simplify=True, # onnx-simplifier 优化计算图 + dynamic=False, # 固定 batch=1,推理服务不需要动态 batch +) +# 产物:pcb_defect_v1.onnx +``` + +切换到 ONNX 的时机: + +``` +1. YOLOv8n 在验证集 mAP@0.5 > 0.90 → 导出 ONNX +2. 运行 scripts/benchmark.py 对比两个运行时延迟 +3. 确认输出一致后,修改 .env 的 RUNTIME=onnx +4. 重启服务,观察 /api/health 确认切换成功 +``` + +--- + +## 14. 与现有代码的对应关系 + +| 现有 `inference.py` 函数 | mingxi-vision 对应位置 | 变化 | +|------------------------|----------------------|------| +| `_MODEL_CACHE` | `engine/loader.py` 单例 | 从懒加载改为启动时加载 | +| `_get_model()` | `loader.init_engine()` | 新增 ONNX 分支 | +| `_copy_to_ascii_temp_input()` | **已删除** | 改用内存读图,无需文件路径 | +| `_parse_result()` | `ultralytics_adapter.detect()` | 增加 severity 映射 | +| `run_image_inference()` | `engine/ultralytics_adapter.py` + `engine/onnx_adapter.py` | 拆成两个运行时 | +| `run_camera_inference()` | **不迁移** | 由 `mingxi-capture` 负责 | +| `run_video_inference()` | **暂不迁移** | 此版本不需要 | +| Django `MEDIA_ROOT` 文件落盘 | **已删除** | 推理服务无状态,不落盘 | + +--- + +## 15. 关键设计决策汇总 + +| 决策 | 选择 | 理由 | +|------|------|------| +| Web 框架 | FastAPI | 轻量、无需 DB、原生 async、自动文档 | +| 模型运行时 | 双运行时(适配器模式) | 开发用 .pt 方便迭代,生产用 .onnx 稳定 | +| 模型加载时机 | 启动时加载 + warmup | 消除首次推理延迟,路演不卡顿 | +| 图像读取 | 内存读取(np.frombuffer) | 彻底消除中文路径问题 | +| 标注图返回 | 按需(return_annotated=true) | 默认不返回,减少响应体积和编码开销 | +| 并发模型 | workers=1,单进程 | GPU CUDA Context 不支持多进程共享 | +| 鉴权 | 无 | 内网服务,由 backend 代理调用 | +| 数据持久化 | 无 | 无状态推理服务,落库交给 backend | +| NMS 后处理 | ONNX 适配器自实现,ultralytics 自带 | 两路输出语义一致 | diff --git a/docs/pcb缺陷检测初步方案.md b/docs/pcb缺陷检测初步方案.md new file mode 100644 index 0000000..57e87bd --- /dev/null +++ b/docs/pcb缺陷检测初步方案.md @@ -0,0 +1,218 @@ +# PCB缺陷检测初步方案(单机开发版) + +> 硬件约束修正:仅有一台联想 Y7000P 笔记本(Intel i7-14650HX 16核 @2.20GHz,16GB RAM,预计 RTX 4060 Laptop 8GB 独显)。 +> 本方案在 v1.1 和"pcb缺陷识别开源项目.md"基础上,针对"无 Jetson、无独立服务器、仅一台笔记本"做完整重构。 +> 对齐 CLAUDE.md:Python3.8 + YOLOv8 + Vue3.0 + Django4.0。 +> 起始日期:2026-05-07 + +--- + +## 1. 硬件盘点与能力边界 + +| 组件 | 规格 | 训练能力 | 推理能力 | +|---|---|---|---| +| CPU | i7-14650HX 16C/24T @2.20GHz,睿频5.2GHz | 数据预处理 / 标注 / 辅助 | OpenVINO CPU推理可行 | +| GPU | RTX 4060 Laptop 8GB GDDR6(Y7000P 2024标配,需核实) | **YOLOv8n/s 可训练,batch≤16** | FP16 实时推理 60+ FPS | +| RAM | 16GB DDR5 | **瓶颈**,大数据集需分批加载 | 推理无压力 | +| 存储 | 1TB NVMe(标配) | 够用,注意清理缓存 | — | +| 散热 | 笔记本主动散热 | **持续满载训练时需外接散热器** | 推理负载低 | + +**结论**:这台笔记本可以**完成训练 + Demo推理 + Web开发全流程**,但 Jetson / TensorRT / DeepStream 路线需要**降级替代**。 + +### 首要动作:确认 GPU 型号 + +开机执行 `nvidia-smi`(或设备管理器)确认: +- 若为 **RTX 4060 8GB**:方案按本文执行 +- 若为 **RTX 4050 6GB**:把 `imgsz` 从 640 降到 416,`batch` 从 16 降到 8 +- 若为**核显/无独显**:只能用 CPU 训练,YOLOv8n 一轮要数小时,建议立即借/租算力 + +--- + +## 2. 方案修正总览(对比原方案) + +| 环节 | 原方案 | 修正后(单笔记本) | 修正理由 | +|---|---|---|---| +| 训练硬件 | Jetson Orin Nano | **Y7000P RTX 4060** | 无 Jetson | +| 训练模型 | YOLOv8n/s 随意 | **固定 YOLOv8n**(s 作备选) | 8GB 显存 + 16GB 内存限制 | +| 边缘部署演示 | Jetson + DeepStream + TensorRT | **笔记本 + USB工业相机 + ONNX Runtime GPU** | 节省硬件预算,聚焦算法 | +| Demo 形态 | 边缘盒子现场演示 | **笔记本直接演示 + 预录视频兜底** | 现场网络/电源风险可控 | +| 实时推理 | TensorRT FP16 | **ONNX Runtime DirectML 或 CUDA EP** | Windows 原生支持,无需交叉编译 | +| 数据标注 | 标注团队 | **本机 Label Studio / labelme** | 5人团队自标注即可 | +| 产品部署 | 云服务器 | **本机 Docker + ngrok 内网穿透** 临时演示 | 省服务器钱 | +| 生产边缘盒 | Jetson 自购 | **MVP 阶段客户采购 / 租用** | 获奖后再投硬件 | + +--- + +## 3. GitHub 项目选型(按硬件修正) + +### 主选:aaravomega/pcb-defect-detection + +https://github.com/aaravomega/pcb-defect-detection + +- YOLOv8 + Ultralytics 标准流程,与 Python3.8 技术栈一致 +- Windows 原生支持,不需 Linux / Docker +- fork 后直接改 `data.yaml` 和 `train.py` + +### 数据:HRIPCB(主)+ DeepPCB(备) + +- **HRIPCB**(Roboflow 一键导出 YOLO 格式):https://universe.roboflow.com/ma007/hripcb/dataset/3 +- **DeepPCB**(含模板图,后期差分增强用):https://github.com/tangsanli5201/DeepPCB + +### 演示方案:放弃 Deepstream,改用 ONNX Runtime + OpenCV + +- 原因:NVIDIA DeepStream 主要面向 Jetson 和 Tesla 服务器卡,笔记本 4060 用起来收益小、坑多 +- 替代:训练后的 `best.pt` → 导出 ONNX → **ONNX Runtime GPU (CUDA Execution Provider)** → OpenCV 读 USB 相机 → Vue 看板展示 +- 备选:**OpenVINO**(Intel CPU 推理,i7-14650HX 上 YOLOv8n 可跑 20-30 FPS,作为 GPU 挂掉时的兜底) + +### 挠性板扩展:Flexible-PCB-Defect-Detection + +https://github.com/Pranshuk29/Flexible-PCB-Defect-Detection + +- 仅在 MVP 阶段、成功对接梅州智科后启用 +- 不在 Demo 阶段占用训练资源 + +--- + +## 4. 训练配置(针对 8GB 显存 + 16GB 内存) + +### 4.1 环境清单(Windows 11 + WSL2 可选) + +``` +Python 3.8.x +PyTorch 2.0.1 + CUDA 11.8(Y7000P 驱动原生支持) +Ultralytics 8.x +onnxruntime-gpu 1.16+ +opencv-python 4.8+ +label-studio 或 labelme +``` + +> 不建议用 WSL2 训练:Windows 下 PyTorch CUDA 性能已够,WSL 多一层开销且调试麻烦。 + +### 4.2 训练超参数(起步版) + +```yaml +# train.yaml(Y7000P 实测可行) +model: yolov8n.pt +data: hripcb.yaml +imgsz: 640 +batch: 16 # 8GB 显存极限,若 OOM 降到 8 +epochs: 100 +device: 0 # 单 GPU +workers: 4 # 16GB 内存下别超 4,否则卡死 +amp: True # 混合精度必开,省显存 +cache: ram # 数据集 <2GB 时开 RAM 缓存加速 +patience: 20 # 早停,省电省时间 +``` + +### 4.3 训练时间预估(HRIPCB 1386 张) + +| 模型 | 单轮时间 | 100轮总时 | 显存占用 | +|---|---|---|---| +| YOLOv8n | ~45s | **约 1.5 小时** | ~4GB | +| YOLOv8s | ~80s | 约 2.5 小时 | ~6GB | +| YOLOv8m | OOM 风险 | 不推荐 | >8GB | + +**建议**:先 n 后 s,n 版本达到 mAP@0.5 > 0.9 即可上路演,s 作为备选。 + +### 4.4 散热与稳定性 + +- 训练时**外接散热底座**,温度控制在 85℃ 以内 +- 关闭 Windows 自动更新,避免训练中断 +- 每晚跑训练、白天做产品开发,错峰使用笔记本资源 + +--- + +## 5. Demo 现场展示方案(替代 Jetson) + +### 5.1 硬件清单(总预算 ≤ 2000 元) + +| 设备 | 型号建议 | 价格 | 用途 | +|---|---|---|---| +| USB 工业相机 | 海康威视 MV-CU013-A0UC 或 海康 USB 摄像头 | ~800-1500 | 实拍 PCB 样品 | +| LED 环形光源 | 工业白光环形灯 | ~200 | 保证光照一致 | +| 简易光箱 / 黑色背景板 | 自制 | ~100 | 降低杂光干扰 | +| PCB 样品 | 向本地厂讨要废板 | 0 | 演示素材 | +| 外接散热底座 | 联想/酷冷至尊 | ~200 | 训练稳定性 | + +### 5.2 演示流程 + +``` +笔记本(Y7000P) + ├─ USB 相机 → OpenCV 取流 + ├─ ONNX Runtime GPU 推理 + ├─ Django 后端写入事件 + ├─ Vue 看板实时展示(localhost) + └─ 投屏到决赛现场大屏 +``` + +### 5.3 三重兜底 + +- **A 计划**:现场实时相机 + PCB 样品演示(最理想) +- **B 计划**:预录 90 秒场景视频 + Vue 看板重放(现场网络/相机故障时启用) +- **C 计划**:纯截图 PPT(极端情况,笔记本挂掉时) + +**每个计划必须提前演练 3 次以上**。 + +--- + +## 6. 开发环境(单机全栈) + +``` +Y7000P 上同时跑: +├─ 终端1:Django runserver (8000) +├─ 终端2:Vue dev server (5173) +├─ 终端3:YOLOv8 推理服务(FastAPI 独立进程,8001) +├─ 终端4:Label Studio(8080,标注用) +└─ 后台:PostgreSQL 或 SQLite(MVP 阶段 SQLite 足够) +``` + +**资源分配**: +- 训练时段:关掉 Django/Vue/Label Studio,独占 GPU 和内存 +- 开发时段:关掉训练,16GB 内存跑全栈无压力 +- **不要同时训练和开发**,16GB 必 OOM + +--- + +## 7. 三个月执行计划(对齐 Y7000P 节奏) + +| 周 | 工作内容 | 是否占用 GPU | +|---|---|---| +| W1 | 确认 GPU 型号;装环境;fork aaravomega;下载 HRIPCB | 轻度(跑通推理) | +| W2 | YOLOv8n 在 HRIPCB 上训练完成;拿到 mAP 基准 | **整夜占用** | +| W3 | Django 后端框架 + Vue 看板骨架;接 SQLite | 否 | +| W4 | YOLOv8 导出 ONNX;FastAPI 推理服务;OpenCV 取相机流 | 轻度 | +| W5 | 买 USB 工业相机 + 环形光;搭建演示光箱;拍测试素材 | 否 | +| W6 | Demo 版 v1:相机 → 推理 → 看板 全链路打通 | 轻度 | +| W7 | 联系丰顺威达 / 梅州超捷 / 智科,签 NDA 收样本 | 否 | +| W8 | 真实样本标注(Label Studio)+ 迁移学习微调 | **整夜占用** | +| W9 | 规则引擎(批次缺陷率/追溯)+ 事件管理 + 告警 | 否 | +| W10 | 挠性板扩展(若智科签约)+ 录 90s 场景视频 | 轻度 | +| W11 | 软著申请;客户 MOU 签署;BP 定稿 | 否 | +| W12 | 决赛 Demo 联调;三重兜底演练;路演彩排 | 否 | + +--- + +## 8. 风险清单(硬件层) + +| 风险 | 概率 | 影响 | 对策 | +|---|---|---|---| +| 笔记本训练过热降频 | 高 | 训练慢 | 外接散热底座 + 限制房间温度 | +| 8GB 显存 OOM | 中 | 训练中断 | batch 降到 8;imgsz 降到 416 | +| 16GB 内存爆满 | 中 | 系统卡死 | workers 降到 2;关闭浏览器等 | +| 决赛现场笔记本故障 | 低 | **灾难** | 二号机备份(团队另一人的笔记本同步工程)+ B/C 计划 | +| GPU 驱动更新导致 CUDA 挂掉 | 低 | 训练中断 | 关闭 NVIDIA 自动更新;锁定驱动版本 | +| 真实 PCB 样本获取失败 | 中 | 只能用公开数据集 | 提前 2 周对接 2 家以上厂商分散风险 | + +--- + +## 9. 后续升级路径(晋级后) + +- **初赛通过后**:考虑租云 GPU(AutoDL / 腾讯云 GN7 一周 ~300 元)加速 YOLOv8s / m 训练 +- **获奖后**:用奖金采购 1 台 **Jetson Orin Nano 8GB**(约 3500 元)做客户演示边缘盒子,切回原方案的 DeepStream 部署路线 +- **MVP 阶段**:客户侧硬件由客户采购或租用,我方只交付**软件 + 配置服务** + +--- + +## 10. 一句话结论 + +**用好 Y7000P 这一台机器,完全够支撑 Demo 版晋级**——关键是**把训练和开发错峰安排,显存内存资源专用**。Jetson / 云服务器留到 MVP 阶段和获奖后再投入,Demo 阶段聚焦"算法精度 + 产品闭环 + 本地客户意向"三板斧即可。 diff --git a/docs/pcb缺陷检测简介.md b/docs/pcb缺陷检测简介.md new file mode 100644 index 0000000..172e09f --- /dev/null +++ b/docs/pcb缺陷检测简介.md @@ -0,0 +1,41 @@ +# PCB线路板缺陷检测项目简介 + +## 一、项目介绍 + +PCB(印刷电路板)被称为"电子产品之母",手机、电脑、汽车里都有它的身影。一块线路板上布满了细如发丝的铜线路和密密麻麻的焊点,任何一处瑕疵都可能导致整台设备故障。 + +传统的人工检测方式依赖质检员用放大镜逐片检查,效率低、眼睛疲劳后漏检率高,而且培养一名熟练质检员需要数月时间。我们的项目利用AI视觉技术——就像给机器装上一双"火眼金睛",通过工业相机自动拍摄线路板图像,再由AI算法实时识别短路、断路、缺焊、异物等各类缺陷,检测速度比人工快数十倍,且24小时不知疲倦,漏检率大幅降低。 + +本项目旨在帮助中小线路板工厂以较低成本实现智能化质检升级,提升产品良率,降低返工成本。 + +## 二、工厂调研问题清单 + +### 生产流程类 +1. 工厂目前各生产环节(曝光、蚀刻、钻孔、电镀、丝印等)的工艺流程是怎样的? +2. 质检环节安排在哪些工序之后?目前有哪些检测站点? +3. 日产量/月产量大概是多少?产线运行几班制? + +### 缺陷情况类 +4. 目前最常见的缺陷类型有哪些?各占多大比例? +5. 各类缺陷的成因是什么?主要在哪些工序产生? +6. 是否有缺陷分类的标准或规范?是否有缺陷样本图片存档? +7. 最严重、最亟待解决的缺陷类型是哪一种? + +### 现有检测方式类 +8. 目前采用人工目检还是已有AOI(自动光学检测)设备? +9. 如有AOI设备,是什么品牌型号?检测效果和痛点是什么? +10. 人工检测的漏检率和误检率大约是多少? +11. 一名质检员一天能检测多少片板? + +### 数据与合作类 +12. 是否愿意提供历史缺陷图片用于AI模型训练?能否签署数据保密协议? +13. 对AI检测的准确率期望值是多少?(如漏检率<0.5%、误检率<2%) +14. 产线上是否已有工业相机或是否方便加装? +15. 如果部署AI检测系统,希望以什么形式合作?(一次性采购、按月租赁、按检测量计费?) + +### 环境与部署类 +16. 产线环境的光照条件如何?是否有稳定的照明? +17. 检测工位是否有网络环境?内网还是外网? +18. 线路板来料的尺寸范围是多少?最小线宽/线距是多少? +19. 对检测速度的要求是什么?(如每秒检测几片) +20. 工厂目前的IT基础设施如何?是否有专人维护自动化设备? diff --git a/docs/pcb缺陷识别开源项目.md b/docs/pcb缺陷识别开源项目.md new file mode 100644 index 0000000..0a9f8b8 --- /dev/null +++ b/docs/pcb缺陷识别开源项目.md @@ -0,0 +1,131 @@ +# PCB缺陷识别开源项目调研 + +> 服务于梅州市新一代电子信息暨人工智能产业创新创业大赛"PCB/电路板AI视觉缺陷检测平台"选题。 +> 结合2025年决赛PCB获奖企业产品形态(刚性板、挠性板、铝基板、Mini LED板、PTFE高频板、OSP涂层等),筛选出覆盖"基础6缺陷 / 挠性板 / 边缘部署 / 高质量基准"四个互补切面的5个GitHub项目,均有公开数据集可直接复用。 +> 调研日期:2026-05-07 + +--- + +## 选型总览 + +| # | 项目 | 框架 | 数据集 | 覆盖切面 | 对应梅州PCB厂 | +|---|---|---|---|---|---| +| 1 | tangsanli5201/DeepPCB | 基础baseline | DeepPCB(1500对) | 6类标准缺陷 + 模板对齐 | 超捷、华达、智科(AOI后复判) | +| 2 | Ixiaohuihuihui/Tiny-Defect-Detection-for-PCB | 小目标优化 | HRIPCB(北大,1386张) | 微小缺陷 + 高分辨率 | 丰顺威达(PTFE高频板)、兴宁精进(高效散热) | +| 3 | aaravomega/pcb-defect-detection | YOLOv8 | 7971张(HRIPCB扩增) | 即插即用算法底座 | 作为MVP版核心底座 | +| 4 | clintonoduor/PCB-Defect-Detection-using-Deepstream | YOLOv5 + Jetson + TensorRT | HRIPCB | 边缘实时部署 | 所有中小PCB厂(不接受云端) | +| 5 | Pranshuk29/Flexible-PCB-Defect-Detection | YOLOv5 + FlexSim | 自建FPC挠性板数据集 | 挠性板专项 | 梅州智科(挠性印制电路板,2025三等奖) | + +--- + +## 1. tangsanli5201/DeepPCB — 基准数据集 + baseline + +- **仓库**:https://github.com/tangsanli5201/DeepPCB +- **数据集特性**: + - **1,500组图像对**:每组包含"无缺陷模板图 + 带缺陷测试图",**像素级对齐** + - 6类缺陷:open(断路)、short(短路)、mousebite(鼠咬)、spur(毛刺)、pinhole(针孔)、spurious copper(余铜) + - 标注格式:PASCAL VOC(bounding box),开箱即用 +- **适配梅州场景**:对应**梅州超捷、华达、智科**等走"AOI后复判"路线的PCB厂——有模板图可用**差分增强**,检测精度更高 +- **建议用法**:作为**初赛资料**的算法精度证据(mAP数字有行业共识),先跑通baseline再迁移到真实样本 + +## 2. Ixiaohuihuihui/Tiny-Defect-Detection-for-PCB — 微小缺陷 + 高分辨率 + +- **仓库**:https://github.com/Ixiaohuihuihui/Tiny-Defect-Detection-for-PCB +- **数据集**:**HRIPCB**(北京大学人机交互开放实验室发布) + - 1,386张合成PCB图,6类缺陷(同DeepPCB) + - **分辨率更高,缺陷尺度更小**,更接近真实AOI拍摄环境 +- **镜像下载**: + - Roboflow:https://universe.roboflow.com/ma007/hripcb/dataset/3 (一键导出YOLO/COCO格式) + - Kaggle:https://www.kaggle.com/datasets/akhatova/pcb-defects +- **适配梅州场景**:对应**丰顺威达(PTFE高频板孔工艺)、兴宁精进(高效散热板)**这类**线宽细、缺陷尺度小**的场景 +- **建议用法**:作为训练主力,HRIPCB的小目标特性能弥补DeepPCB分辨率不足的问题 + +## 3. aaravomega/pcb-defect-detection — YOLOv8 即插即用 + +- **仓库**:https://github.com/aaravomega/pcb-defect-detection +- **数据集**:**7,971张**PCB标注图,6类缺陷(HRIPCB + 数据扩增) +- **框架**:YOLOv8 + Ultralytics transfer learning +- **技术栈匹配**:与 CLAUDE.md 约定的 Python3.8 + YOLOv8 完全一致 +- **适配梅州场景**:作为**MVP版的算法底座**,YOLOv8n/s 在 Jetson Nano/Orin 上可跑实时推理 +- **建议用法**:直接 fork,把 Django4.0 后端和 Vue3.0 看板接上就是完整产品 + +## 4. clintonoduor/PCB-Defect-Detection-using-Deepstream — 边缘部署样板 + +- **仓库**:https://github.com/clintonoduor/PCB-Defect-Detection-using-Deepstream +- **数据集**:HRIPCB + YOLOv5 训练权重 +- **亮点**:**NVIDIA DeepStream + Jetson AGX** 端到端 pipeline + - 含 TensorRT 量化 + - 视频流实时推理 + - 实时可视化 +- **适配梅州场景**:**路演现场演示神器** + - 评委偏好"边缘盒子 + 摄像头 + 实时告警"三件套 + - 中小 PCB 厂不接受云端部署,边缘盒子是刚需 +- **建议用法**:作为 **Demo 版的硬件展示方案**,现场摆一台 Jetson Orin Nano + 工业相机 + PCB 样品 + +## 5. Pranshuk29/Flexible-PCB-Defect-Detection — 挠性板专项差异化 + +- **仓库**:https://github.com/Pranshuk29/Flexible-PCB-Defect-Detection +- **数据集**:自建 **FPC 挠性板**数据集 + YOLOv5 + **FlexSim 数据增强**(模拟弯折形变) +- **适配梅州场景**: + - **直接对应 2025 三等奖企业"梅州智科电路板"的挠性印制电路板产品线** + - FPC 因弯折产生的形变缺陷(折痕、铜箔裂纹、层间分离)是**通用 PCB 数据集覆盖不到**的差异化能力 +- **建议用法**:作为**本次参赛的差异化亮点** + - 在标准 6 类缺陷之外加一个"挠性板专用"能力模块 + - 与梅州智科对接签 MOU(客户意向书) + +--- + +## 备选项目(路演备选 / 答辩应对) + +| 项目 | URL | 适用场景 | +|---|---|---| +| AyaAshraf76/PCB-defect-detection | https://github.com/AyaAshraf76/PCB-defect-detection | YOLOv8 + Roboflow 数据,教学级 | +| Hazrat-Ali9/Deep-Learning-AOI-for-PCBs | https://github.com/Hazrat-Ali9/Deep-Learning-AOI-for-PCBs-Real-Time-YOLO-Detection-of-Missing-Holes-Mouse-Bites-Shorts-and-Spurs | 实时 AOI 场景,补充参考 | +| EzekiasOkuPevi/PCB-Defect-Detection-Using-Deep-Learning | https://github.com/EzekiasOkuPevi/PCB-Defect-Detection-Using-Deep-Learning | YOLOv8 vs YOLOv10 对比,答辩用 | +| SiemonCha/pcb-defect-detection | https://github.com/SiemonCha/pcb-defect-detection | 生产级 pipeline,工程参考 | +| utkarsh-ankit/Defect-Detection-of-PCB | https://github.com/utkarsh-ankit/Defect-Detection-of-PCB | MobileNets 轻量化方案 | + +--- + +## 整合推进建议(对齐 v1.1 的 Demo 版→MVP 版分档) + +### Demo 版(1.5 个月,路演可用) + +1. 拉取 **项目1 DeepPCB** + **项目2 HRIPCB** 数据集合并训练 +2. 用 **项目3 aaravomega/pcb-defect-detection** 的 YOLOv8 底座做迁移学习 +3. 用 **项目4 Deepstream** 方案在 Jetson 上做实时演示 +4. 产出:现场可演示的边缘盒子 + 标准 mAP 基准数字 + +### MVP 版(3 个月,客户可交付) + +1. 接入 **1 家梅州本地 PCB 厂**真实产线样本,微调项目3的模型 +2. 用 **项目5 Flexible-PCB** 的 FPC 方案扩展挠性板能力,对接梅州智科 +3. Django4.0 + Vue3.0 产品化:用户系统 / 规则引擎 / 告警回放 / 追溯看板 +4. 产出:客户 MOU、软著证书、真实产线验证数据 + +### 路演包装话术 + +> "基于北大 HRIPCB 学术数据集 + 真实梅州产线样本双源训练,面向梅州本地 PCB 产业集群的 AI 视觉质检平台。" + +**学术可信度**(北大数据集)**+ 本地化落地**(真实产线)**双背书**,契合 2025 公告"项目展示完成度"与"自主知识产权"考察点。 + +--- + +## 版权与合规提示 + +- **DeepPCB、HRIPCB** 均以学术用途发布 +- 商业化部署前需在对应论文 / README 中确认授权条款 +- 路演阶段使用无碍,但要提前准备自有数据集方案用于答辩应对 +- 建议:**尽早启动真实样本采集**,降低对学术数据集的依赖 + +--- + +## 参考资料 + +- [pcb-defect-detection · GitHub Topics](https://github.com/topics/pcb-defect-detection) +- [HRIPCB on Roboflow Universe](https://universe.roboflow.com/ma007/hripcb/dataset/3) +- [PCB Defects dataset on Kaggle](https://www.kaggle.com/datasets/akhatova/pcb-defects) +- [PCB-YOLOV8X: a network for detecting micro-sized defects on PCB surfaces (Nature, 2026)](https://www.nature.com/articles/s41598-026-46089-6) +- [An Open Source Enhancement Algorithm for PCB Defect Detection Based on YOLOv8 (arXiv 2025)](https://arxiv.org/html/2507.02963v1) +- [Defect detection of printed circuit board assembly based on YOLOv5 (Nature, 2024)](https://www.nature.com/articles/s41598-024-70176-1) +- [PCB Electronic Component Soldering Defect Detection Using YOLO11 (PMC, 2025)](https://pmc.ncbi.nlm.nih.gov/articles/PMC12158347/) diff --git a/docs/pcb调研问题.md b/docs/pcb调研问题.md new file mode 100644 index 0000000..f987bfd --- /dev/null +++ b/docs/pcb调研问题.md @@ -0,0 +1,38 @@ +# 简介 +* 手机、电脑、汽车里都有PCB印刷电路板。 +* 一块线路板上布满了细如发丝的铜线路和密密麻麻的焊点,任何一处瑕疵都可能导致整台设备故障。 +* 传统的人工检测方式依赖质检员用放大镜逐片检查,效率低、眼睛疲劳后漏检率高,而且培养一名熟练质检员需要数月时间。 +* 我们的项目利用AI视觉技术,通过工业相机自动拍摄线路板图像,再由AI算法实时识别短路、断路、缺焊、异物等各类缺陷,检测速度比人工快数十倍,且24小时不知疲倦,漏检率大幅降低。 +* 搭配管理平台,随时查看记录和统计缺陷,生成数据报告. +* 本项目帮助中小线路板工厂以较低成本实现智能化质检升级,提升产品良率,降低返工成本。 + +#调研问题: + +##生产流程类 + +1. 工厂质检环节安排在哪些工序之后? +2. 日产量/月产量大概是多少?产线运行几班制? + +## 缺陷情况类 +1. 目前最常见的缺陷类型有哪些?各占多大比例? +2. 各类缺陷的成因是什么?主要在哪些工序产生? +3. 是否有缺陷分类的标准或规范?是否有缺陷样本图片存档? +4. 最严重、最亟待解决的缺陷类型是哪一种? + +## 现有检测方式类 +1. 目前采用人工目检还是已有AOI(自动光学检测)设备? +2. 如有AOI设备,是什么品牌型号?检测效果和痛点是什么? +3. 人工检测的漏检率和误检率大约是多少? +4. 一名质检员一天能检测多少片板? + +## 数据与合作类 +1. 对AI检测的准确率期望值是多少?(如漏检率<0.5%、误检率<2%) +2. 如果部署AI检测系统,希望以什么形式合作?(一次性采购、按月租赁、按检测量计费?) + + +## 环境与部署类 +1. 产线环境的光照条件如何?是否有稳定的照明? +2. 检测工位是否有网络环境?内网还是外网? +3. 线路板来料的尺寸范围是多少?最小线宽/线距是多少? +4. 对检测速度的要求是什么?(如每秒检测几片) +5. 工厂目前的IT基础设施如何?是否有专人维护自动化设备? \ No newline at end of file diff --git a/docs/pcb调研问题.pdf b/docs/pcb调研问题.pdf new file mode 100644 index 0000000..7d85ec0 Binary files /dev/null and b/docs/pcb调研问题.pdf differ diff --git a/docs/明析平台-软件重构设计文档.md b/docs/明析平台-软件重构设计文档.md new file mode 100644 index 0000000..3637aa0 --- /dev/null +++ b/docs/明析平台-软件重构设计文档.md @@ -0,0 +1,757 @@ +# 明析平台 软件重构设计文档 + +> 版本:v2.0 · 日期:2026-05-24 +> 项目:基于机器视觉的图像识别技术应用平台——明析 +> 参赛:梅州市2026年新一代电子信息暨人工智能产业创新创业大赛 · 初创企业(创客)组 + +--- + +## 1. 重构背景 + +### 1.1 现有代码概况 + +当前仓库 `yolo_classification_system` 是一套**通用YOLO推理系统**,实现了: + +| 模块 | 现状 | +|------|------| +| 后端 | Django 4 + DRF,JWT鉴权,支持图片/视频/摄像头三种推理模式 | +| 推理 | `inference.py` 封装 ultralytics YOLO,模型缓存,结果落库 | +| 数据模型 | `UserProfile`、`YoloResult`、`SceneNews`、`SystemLog`、`YoloStatsDaily` | +| 前端 | Vue 3 + Vite,开发/生产环境分离,API代理配置完整 | +| 演示模型 | 驾驶员疲劳检测(`driver-drowsiness-detection/best.pt`) | + +### 1.2 重构目标 + +将通用系统改造为**PCB线路板缺陷检测专用平台(明析)**,在不改动客户现有硬件的前提下,通过算法叠加实现AI视觉质检能力升级。 + +--- + +## 2. 系统物理架构 + +### 2.1 两台机器部署 + +``` +┌─────────────────────────────────┐ 局域网 ┌──────────────────────────────────────┐ +│ 前置机(工业PC) │ ─────────────→ │ 推理服务器(Linux+GPU) │ +│ │ │ │ +│ 相机 ──USB3──→ mingxi-capture │ │ mingxi-vision :8001 (FastAPI) │ +│ (PyQt5桌面程序) │ │ mingxi-backend :8000 (Django) │ +│ Win7 SP1+ 工业机 │ │ mingxi-frontend :80 (Vue3) │ +└─────────────────────────────────┘ └──────────────────────────────────────┘ +``` + +| 角色 | 机器 | 操作系统 | 运行软件 | +|------|------|---------|---------| +| 前置机 | 工厂现有工业PC(USB3.0) | Windows 7 SP1 及以上 | mingxi-capture.exe | +| 推理服务器 | 团队配置(RTX 4060 或以上) | Linux | mingxi-vision + mingxi-backend + mingxi-frontend | + +### 2.2 数据流 + +``` +操作工(点击按钮)或 PLC触发信号 + │ + ▼ + mingxi-capture(前置机) + │ + ├─① 同步 POST 图像 ──────────────→ mingxi-vision(推理服务器:8001) + │ │ 推理完成 + │ ←── 返回标注图+缺陷列表+结论 ──────┘ + │ + ├─ 立即在桌面程序展示结果(操作工可见) + │ · 合格 / 不合格 结论 + │ · 标注了缺陷位置的图像 + │ · 每个缺陷的类型、等级、置信度 + │ + └─② 异步队列 POST 结果 ──────────→ mingxi-backend(:8000) + │ 存入 SQLite + 若失败 → 本地SQLite重试队列 │ + ▼ + 管理员/组长/厂长 + 通过浏览器查看 + (短轮询,1-2秒延迟) +``` + +### 2.3 端口分配 + +| 服务 | 端口 | 调用方 | +|------|------|-------| +| mingxi-vision | 8001 | mingxi-capture(同步推理) | +| mingxi-backend | 8000 | mingxi-capture(存档)、浏览器前端 | +| mingxi-frontend | 80 | 浏览器 | + +--- + +## 3. 子项目拆分方案 + +### 3.1 项目总览 + +``` +mingxi-capture/ Python 3.8 · PyQt5 · Windows桌面程序(前置机运行) +mingxi-vision/ Python 3.8 · FastAPI · PCB缺陷推理服务(推理服务器运行) +mingxi-backend/ Python 3.8 · Django 4 · 业务后端(推理服务器运行) +mingxi-frontend/ Vue 3.0 · 管理后台(推理服务器运行,浏览器访问) +``` + +### 3.2 代码迁移决策 + +| 现有文件/模块 | 处置方式 | 说明 | +|-------------|---------|------| +| `yolo8/models.py` → `UserProfile` | **直接复用** | JWT鉴权体系完整,扩展 role 字段 | +| `yolo8/models.py` → `SystemLog` | **直接复用** | 日志结构通用 | +| `yolo8/jwt_utils.py` | **直接复用** | token版本机制保留 | +| `yolo8/models.py` → `YoloResult` | **重构为** `DefectResult` | 增加PCB专用字段:缺陷等级、产线 | +| `yolo8/models.py` → `SceneNews` | **删除** | 与PCB业务无关 | +| `yolo8/models.py` → `YoloStatsDaily` | **重构为** `ProductionStat` | 改为产线维度统计 | +| `yolo8/inference.py` → `run_image_inference` | **迁移至** `mingxi-vision` | 推理服务核心,增加ONNX支持 | +| `yolo8/inference.py` → `run_camera_inference` | **删除** | 由 `mingxi-capture` 海康SDK替代 | +| `yolo8/inference.py` → `_copy_to_ascii_temp_input` | **删除** | 改为内存读图,彻底消除中文路径问题 | +| `yolo8/views.py` → 鉴权相关视图 | **直接复用** | `auth_*`、`user_*` 无需改动 | +| `yolo8/views.py` → `yolo_task_image` | **重构为** `detect_pcb` | 简化,接收capture推送 | +| `frontend/` | **重构** | 删除通用YOLO页面,改为管理后台 | + +--- + +## 4. mingxi-capture(前置采集程序) + +### 4.1 定位 + +运行在**前置机**(工厂工业PC)上的 Windows 原生桌面程序。操作工唯一的交互界面,负责连接相机、触发检测、展示结果,并将结果异步上报至后台。 + +### 4.2 技术栈 + +``` +语言:Python 3.8 +GUI:PyQt5(支持 Windows 7 SP1 及以上,系统托盘、对话框完整支持) +相机:MvImport(海康威视MVS Python SDK,随MVS安装包提供) +本地存储:SQLite(通过 Python 内置 sqlite3) +网络:requests(同步调用vision)+ threading(异步队列推送backend) +打包:PyInstaller → 单文件 .exe 或目录,客户解压即用 +最低系统:Windows 7 SP1 x64 +``` + +### 4.3 目录结构 + +``` +mingxi-capture/ +├── camera/ +│ ├── hik_camera.py # 海康相机封装(MvImport,Phase 2接入) +│ └── mock_camera.py # 模拟模式(读本地图片文件夹,Demo/开发用) +├── ui/ +│ ├── main_window.py # 主窗口:触发按钮 + 图像展示 + 缺陷列表 +│ ├── config_dialog.py # 配置弹窗:服务器地址、端口、相机参数 +│ └── tray_icon.py # 系统托盘图标:显示/隐藏主窗口、退出 +├── core/ +│ ├── capture_worker.py # 拍图+调推理(在QThread中执行,不阻塞UI) +│ ├── upload_queue.py # 异步上报队列(本地SQLite缓存+重试) +│ └── settings.py # 读写 config.ini 配置文件 +├── assets/ +│ └── tray_icon.png # 托盘图标 +├── config.ini # 默认配置(首次运行生成) +├── queue.db # 本地重试队列(SQLite,运行时生成) +├── main.py # 程序入口 +├── requirements.txt +└── mingxi-capture.spec # PyInstaller打包配置 +``` + +### 4.4 主窗口功能 + +``` +┌─────────────────────────────────────────┐ +│ 明析采集程序 [最小化到托盘] [×] │ +├─────────────┬───────────────────────────┤ +│ │ ┌───────────────────────┐│ +│ [手动检测] │ │ ││ +│ │ │ 标注图显示区域 ││ +│ 状态: 就绪 │ │ (检测后显示) ││ +│ │ │ ││ +│ 结论: │ └───────────────────────┘│ +│ ██ 不合格 │ │ +│ │ 缺陷列表: │ +│ 共 3 处 │ 类型 等级 置信度 │ +│ 最高: 致命 │ 断路 致命 0.94 │ +│ │ 短路 致命 0.88 │ +│ │ 毛刺 轻微 0.72 │ +└─────────────┴───────────────────────────┘ +``` + +### 4.5 配置弹窗(系统托盘右键→设置) + +``` +推理服务地址: [192.168.1.100] 端口: [8001] +后台服务地址: [192.168.1.100] 端口: [8000] +相机序列号: [自动检测 ▼] +模拟模式: [✓] 启用 图片目录: [C:\test_images\ 浏览] +置信度阈值: [0.45] +[保存] [取消] +``` + +配置持久化至 `config.ini`,程序启动时自动读取。 + +### 4.6 异步上报队列 + +```python +# core/upload_queue.py 逻辑 + +# 1. capture_worker 推理成功后,将结果插入本地 SQLite queue.db +# 2. 后台线程每 5 秒扫描一次 queue.db 中状态为 pending 的记录 +# 3. 尝试 POST 到 mingxi-backend +# 成功 → 标记为 sent +# 失败 → retry_count + 1,超过 10 次标记为 failed(不再重试) +# 4. 队列表结构: +# id, image_base64, result_json, created_at, status, retry_count, last_error +``` + +### 4.7 mock_camera 模拟模式 + +Phase 1(路演)无真实相机时,从配置目录中按序读取 `.jpg`/`.png` 文件,接口与 `hik_camera.py` 完全一致,上层代码无感知切换。 + +### 4.8 打包部署 + +```bash +pyinstaller mingxi-capture.spec +# 输出:dist/mingxi-capture/(目录模式)或 dist/mingxi-capture.exe(单文件) +# 客户端:解压后双击 mingxi-capture.exe 即可运行 +# 随安装包附带:海康 MVS Runtime DLL(如需相机功能) +``` + +### 4.9 触发模式(阶段支持) + +| 触发方式 | Phase 1 | Phase 2 | +|---------|---------|---------| +| 手动点击按钮 | ✅ | ✅ | +| PLC/传感器信号(串口/数字IO) | — | ✅ | +| 定时自动(固定频率) | — | ✅ | + +--- + +## 5. mingxi-vision(推理服务) + +### 5.1 职责 + +- 接收图像(来自 `mingxi-capture`) +- 调用明析平台(YOLOv8/ONNX)执行PCB缺陷检测 +- 返回缺陷列表(位置、类别、置信度、等级)+ 标注图(可选) +- 支持模型热重载(管理员通过后台切换模型时调用) + +### 5.2 技术栈 + +``` +语言:Python 3.8 +框架:FastAPI + uvicorn(workers=1,单进程,GPU不跨进程共享) +推理:ultralytics YOLOv8(开发阶段)/ ONNX Runtime(生产部署) +并发:asyncio.Lock(推理串行化,防止GPU冲突) +GPU:CUDA 11.x + cuDNN +``` + +### 5.3 并发处理:推理锁 + +```python +# engine/loader.py +import asyncio + +_inference_lock = asyncio.Lock() +_engine: Optional[BaseInferenceEngine] = None + +def get_inference_lock() -> asyncio.Lock: + return _inference_lock + +# api/detect.py +async def detect(image: UploadFile, conf: float = 0.45, ...): + raw = await image.read() + img = cv2.imdecode(np.frombuffer(raw, np.uint8), cv2.IMREAD_COLOR) + + async with get_inference_lock(): # 请求自动排队,GPU串行执行 + result = engine.detect(img, conf) + + return build_response(result) +``` + +- 并发请求不会崩溃,自动排队等待 +- RTX 4060,YOLOv8s,PCB图:约 20~40ms/张 → 25~50 fps +- Windows / Linux 行为完全一致(asyncio 事件循环原语,无OS依赖) + +### 5.4 模型热重载接口 + +``` +POST /api/model/reload +Body: { "model_path": "/opt/mingxi/models/pcb_v2.onnx" } +Response: { "status": "ok", "model_version": "pcb_v2", "warmup_ms": 312 } +``` + +热重载流程: +1. 管理员在浏览器上传新模型并点击"切换" +2. `mingxi-backend` 保存文件、更新数据库,调用此接口 +3. `mingxi-vision` 获取推理锁(等待当前推理完成),卸载旧模型,加载新模型,执行 warmup +4. 释放锁,返回成功 + +### 5.5 目录结构 + +``` +mingxi-vision/ +├── api/ +│ ├── detect.py # POST /api/detect +│ ├── model.py # POST /api/model/reload +│ └── health.py # GET /api/health, /api/health/gpu +├── engine/ +│ ├── base.py # DefectBox, DetectResult, BaseInferenceEngine +│ ├── loader.py # 单例 + asyncio.Lock + init_engine() +│ ├── ultralytics_adapter.py +│ ├── onnx_adapter.py +│ ├── annotator.py # 标注图生成(按severity着色) +│ └── defect_classes.py # HRIPCB 6类 + 扩展4类 +├── models/ # .pt 和 .onnx 文件(gitignored) +├── scripts/ +│ ├── export_onnx.py # pt → onnx 导出脚本 +│ └── benchmark.py +├── tests/ +├── schema.py # Pydantic 响应模型 +├── config.py # BaseSettings(读 .env) +├── main.py # FastAPI lifespan + app +└── requirements.txt +``` + +### 5.6 推理接口 + +``` +POST /api/detect +Content-Type: multipart/form-data +Fields: + image: <图像文件> + conf: float (default: 0.45) + return_annotated: bool (default: false) + +Response 200: +{ + "task_id": "uuid", + "duration_ms": 38, + "verdict": "fail", // pass / fail + "defect_count": 2, + "max_severity": "fatal", + "avg_confidence": 0.89, + "defects": [ + { + "class_id": 2, + "class_name": "open_circuit", + "class_name_zh": "断路", + "confidence": 0.94, + "severity": "fatal", + "box_xyxy": [120, 45, 198, 123] + } + ], + "annotated_image_base64": "..." // 仅 return_annotated=true 时返回 +} +``` + +### 5.7 缺陷类别与等级映射 + +```python +DEFECT_CLASSES = { + # HRIPCB 数据集原始6类 + 0: {"name": "missing_hole", "zh": "缺孔", "severity": "fatal"}, + 1: {"name": "mouse_bite", "zh": "鼠咬", "severity": "major"}, + 2: {"name": "open_circuit", "zh": "断路", "severity": "fatal"}, + 3: {"name": "short_circuit", "zh": "短路", "severity": "fatal"}, + 4: {"name": "spur", "zh": "毛刺", "severity": "minor"}, + 5: {"name": "spurious_copper", "zh": "余铜", "severity": "major"}, + # 扩展类(Phase 2 标注后训练) + 6: {"name": "oxidation", "zh": "氧化", "severity": "minor"}, + 7: {"name": "solder_ball", "zh": "锡珠", "severity": "rework"}, + 8: {"name": "scratch", "zh": "划痕", "severity": "minor"}, + 9: {"name": "label_error", "zh": "标签错贴","severity": "rework"}, +} +``` + +--- + +## 6. mingxi-backend(业务后端) + +### 6.1 职责 + +- 接收 `mingxi-capture` 推送的检测结果,持久化至 SQLite +- 提供 REST API 给浏览器管理后台 +- 用户管理、三级权限控制 +- 模型文件管理(上传、备份、切换、触发vision热重载) +- 系统参数配置 + +### 6.2 技术栈 + +``` +语言:Python 3.8 +框架:Django 4.0 + django-rest-framework +数据库:SQLite(内网单服务器部署,无高并发写入,SQLite足够) +认证:JWT(从现有系统直接复用) +``` + +> 初期不引入 Celery/Redis,保持部署简单。告警推送(Phase 2)再评估是否引入。 + +### 6.3 用户权限设计 + +| 角色 | 检测记录可见范围 | 其他权限 | +|------|---------------|---------| +| 操作工 | 仅自己触发的记录 | 无 | +| 组长 | 本组所有成员的记录 | 查看本组统计 | +| 管理员 | 全部记录 | 用户管理、系统配置、模型管理、查看所有统计 | + +```python +# UserProfile 扩展 +class UserProfile(models.Model): + user = models.OneToOneField(User) + role = models.CharField(choices=[ + ("operator", "操作工"), + ("leader", "组长"), + ("admin", "管理员"), + ], default="operator") + group = models.ForeignKey("WorkGroup", null=True) # 操作工和组长属于某个工组 + +class WorkGroup(models.Model): + name = models.CharField(max_length=100) + leader = models.ForeignKey(UserProfile, null=True, related_name="led_group") +``` + +### 6.4 模型管理设计 + +```python +class ModelRegistry(models.Model): + """模型版本注册表""" + name = models.CharField(max_length=100) # 文件名(含扩展名) + runtime = models.CharField(choices=["pt", "onnx"]) + file_path = models.CharField(max_length=500) # 服务器本地路径 + file_size = models.IntegerField() # 字节数 + is_active = models.BooleanField(default=False) # 当前生效模型 + uploaded_by = models.ForeignKey(UserProfile) + uploaded_at = models.DateTimeField(auto_now_add=True) + notes = models.TextField(blank=True) +``` + +**模型管理规则:** +- 同时只有一个 `is_active=True` +- 最多保留 10 个版本,超出时自动删除最早上传的非活跃版本及其文件 +- 切换模型时:更新 `is_active` → 调用 `POST http://localhost:8001/api/model/reload` + +### 6.5 管理员可配置参数 + +| 参数类别 | 具体参数 | +|---------|---------| +| 推理参数 | 置信度阈值、IOU阈值、图像输入尺寸 | +| 模型管理 | 上传模型、切换活跃模型、查看备份列表 | +| 产线配置 | 产线名称、前置机IP(仅记录,不主动通信) | +| 用户管理 | 新增/停用账号、分配角色、分配工组 | +| 告警规则 | Phase 2,预留接口 | + +### 6.6 数据模型设计 + +```python +class DefectResult(models.Model): + """单次检测记录""" + operator = models.ForeignKey(UserProfile, null=True) + line_id = models.CharField(max_length=50, blank=True) + source_image = models.ImageField(upload_to="originals/") + annotated_image = models.ImageField(upload_to="annotated/", null=True) + verdict = models.CharField(choices=["pass", "fail"]) + defect_count = models.IntegerField(default=0) + max_severity = models.CharField(choices=["none","rework","minor","major","fatal"]) + detections_json = models.TextField() # 完整缺陷列表JSON + avg_confidence = models.FloatField() + duration_ms = models.IntegerField() + model_version = models.CharField(max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + + +class ProductionStat(models.Model): + """每日产线统计(聚合)""" + stat_date = models.DateField() + line_id = models.CharField(max_length=50) + total_count = models.IntegerField(default=0) + pass_count = models.IntegerField(default=0) + fail_count = models.IntegerField(default=0) + defect_dist = models.TextField() # 各缺陷类型数量JSON + + +class SysConfig(models.Model): + """系统参数键值存储""" + key = models.CharField(max_length=100, unique=True) + value = models.TextField() + updated_at = models.DateTimeField(auto_now=True) +``` + +### 6.7 API 接口设计 + +``` +# 认证(直接复用现有代码) +POST /api/auth/login +POST /api/auth/refresh +POST /api/auth/logout +GET /api/user/me + +# 检测结果(capture推送入口) +POST /api/detect/result/ # capture 上报推理结果 +GET /api/detect/results/ # 列表(按角色自动过滤) +GET /api/detect/results/{id}/ + +# 统计 +GET /api/stats/overview/ # 今日合格率、缺陷总数 +GET /api/stats/trend/ # 近N天趋势 +GET /api/stats/defect-dist/ # 缺陷类型分布 + +# 模型管理(管理员) +GET /api/admin/models/ # 模型列表(最多10条) +POST /api/admin/models/upload/ # 上传新模型 +POST /api/admin/models/{id}/activate/ # 切换活跃模型(触发vision热重载) +DELETE /api/admin/models/{id}/ # 手动删除某个备份 + +# 系统配置(管理员) +GET /api/admin/config/ +PATCH /api/admin/config/ + +# 用户管理(管理员) +GET /api/admin/users/ +POST /api/admin/users/ +PATCH /api/admin/users/{id}/ +GET /api/admin/groups/ +POST /api/admin/groups/ + +# 系统日志(直接复用) +GET /api/admin/logs/ +``` + +--- + +## 7. mingxi-frontend(管理后台) + +### 7.1 定位 + +**纯管理后台**,供组长、厂长、管理员通过浏览器使用。操作工不通过浏览器操作(操作工使用前置机桌面程序)。 + +### 7.2 技术栈 + +``` +框架:Vue 3 + Vite + TypeScript(保持现有配置不变) +UI:Element Plus(复用现有) +图表:ECharts(统计报表) +实时:短轮询(每1秒请求一次最新记录,满足1-2秒延迟要求,无需WebSocket) +``` + +> 短轮询而非 WebSocket:部署简单,Django 无需 Channels,延迟满足要求。 + +### 7.3 页面规划 + +| 路由 | 页面 | 可见角色 | 现有/新增 | +|------|------|---------|---------| +| `/login` | 登录 | 全部 | 复用 | +| `/dashboard` | 实时监控看板 | 组长、管理员 | **新增** | +| `/history` | 检测历史记录 | 全部(按权限过滤) | **新增** | +| `/stats` | 统计报表 | 组长、管理员 | **新增** | +| `/admin/models` | 模型管理 | 管理员 | **新增** | +| `/admin/config` | 系统配置 | 管理员 | **新增** | +| `/admin/users` | 用户管理 | 管理员 | 复用改造 | + +### 7.4 实时监控看板(/dashboard) + +- 最新检测结果卡片(标注图缩略图 + 结论) +- 今日合格率仪表盘 +- 缺陷类型分布饼图 +- 近10条记录时间线 +- 每1秒轮询 `/api/detect/results/?limit=1&ordering=-created_at` + +### 7.5 需删除的现有页面 + +``` +SceneNews 相关页面 +通用YOLO视频/摄像头检测页面 +驾驶员疲劳检测相关组件 +``` + +--- + +## 8. 系统间通信 + +### 8.1 完整通信图 + +``` +前置机(Windows) 推理服务器(Linux) +┌──────────────────────┐ ┌──────────────────────┐ +│ mingxi-capture │ │ mingxi-vision │ +│ │──① POST─────→│ /api/detect │ +│ QThread推理线程 │←─ 结果返回──│ asyncio.Lock串行 │ +│ │ └──────────────────────┘ +│ 主线程展示结果 │ +│ │ ┌──────────────────────┐ +│ upload_queue线程 │──② 异步────→│ mingxi-backend │ +│ (失败则重试) │ │ /api/detect/result │ +└──────────────────────┘ │ │ + │ SQLite存档 │ + └──────────┬───────────┘ + │ REST API + ┌──────────▼───────────┐ + │ mingxi-frontend │ + │ 浏览器短轮询 │ + └──────────────────────┘ + 管理员/组长/厂长 浏览器访问 +``` + +### 8.2 关键通信约定 + +| 通信路径 | 协议 | 格式 | 备注 | +|---------|------|------|------| +| capture → vision | HTTP POST | multipart/form-data(图像二进制) | 同步,等待结果 | +| vision → capture | HTTP Response | JSON(含 base64 标注图) | 一次请求一次响应 | +| capture → backend | HTTP POST | JSON(推理结果) | 异步,本地队列保障 | +| browser → backend | HTTP REST | JSON | 短轮询 + 增删改查 | +| backend → vision(热重载) | HTTP POST | JSON | 仅管理员切换模型时触发 | + +### 8.3 前置机配置两个地址 + +前置机桌面程序配置界面中填写: +- **推理服务地址**:`http://192.168.x.x:8001`(vision) +- **后台服务地址**:`http://192.168.x.x:8000`(backend) + +两个服务通常在同一台服务器上,填写相同IP、不同端口。 + +--- + +## 9. 硬件集成(相机配置) + +### 9.1 推荐型号 + +| 阶段 | 型号 | 分辨率 | 接口 | 用途 | +|------|------|--------|------|------| +| Demo/POC | MV-CS060-10GM | 600万像素 | USB3.0 | 算法验证,接工业PC | +| 产线部署 | MV-CA060-10GM | 600万像素 | GigE | 稳定产线,线长100m | +| 大板检测 | MV-CA120-10GM | 1200万像素 | GigE | 视野≥200mm的PCB | + +### 9.2 分辨率选型计算 + +``` +视野:100mm × 75mm(单次拍摄区域) +最小缺陷:0.1mm(针孔、断路) +像素尺寸 ≤ 0.1mm ÷ 3 = 0.033mm/pixel +所需分辨率:100 ÷ 0.033 ≈ 3030 pixels(水平) +结论:600万像素(3072×2048)满足需求 ✓ +``` + +### 9.3 配套清单(单工位 Demo 版) + +| 器材 | 型号/规格 | 估价 | +|------|----------|------| +| 工业相机 | MV-CS060-10GM | 1800-2500元 | +| 镜头 | 16mm C口定焦(1/1.8"靶面) | 500-800元 | +| LED环形光源 | 同轴/低角度,直径120mm | 400-600元 | +| USB3.0线缆 | ≤3m,锁扣式 | 80-150元 | +| 简易支架光箱 | 铝型材,可调高度 | 200-400元 | +| **合计** | | **约 3000-4450元** | + +--- + +## 10. 开发阶段划分 + +### Phase 1:Demo版(目标:2026年6月中旬决赛前) + +**路演方式:** 预先准备好的PCB图片,模拟模式演示完整流程,约5分钟。 + +**核心展示:** 操作工点击→检测→标注图展示→管理后台历史记录。 + +``` +P0(必须完成,路演核心): + [ ] mingxi-vision:图片推理API + asyncio.Lock + 启动warmup + [ ] mingxi-capture:PyQt5桌面程序,Mock模式,结果展示界面 + [ ] mingxi-backend:接收capture推送,DefectResult落库,基础REST API + [ ] mingxi-frontend:登录 + 检测历史列表 + 详情页 + [ ] mingxi-backend:三级权限(操作工/组长/管理员) + +P1(有时间做,加分项): + [ ] mingxi-frontend:实时监控看板(短轮询) + [ ] mingxi-backend:模型管理(上传/备份/切换) + [ ] mingxi-frontend:统计报表页 + [ ] mingxi-capture:系统托盘图标 +``` + +### Phase 2:POC版(目标:2026年Q3,接入真实相机) + +``` + [ ] mingxi-capture:接入海康MVS SDK,对接 MV-CS060-10GM + [ ] mingxi-capture:PLC触发接口(串口/数字IO) + [ ] mingxi-vision:ONNX Runtime部署(export_onnx.py导出) + [ ] mingxi-vision:模型热重载接口完善 + [ ] mingxi-backend:告警规则引擎(连续不良数、缺陷率阈值) + [ ] 完成1家PCB厂POC试用 +``` + +### Phase 3:产线版(目标:2026年Q4,首单签约) + +``` + [ ] 多相机支持(多条产线并发采集) + [ ] 模型迁移学习(基于客户真实样本微调) + [ ] 告警推送(企业微信/短信) + [ ] MES/ERP对接接口 + [ ] 边缘部署探索(Jetson Orin,脱离大型服务器) + [ ] 软件著作权申请 +``` + +--- + +## 11. 开发环境搭建 + +### 11.1 各项目启动命令 + +```bash +# mingxi-vision(推理服务器,Linux) +cd mingxi-vision +pip install -r requirements.txt +uvicorn main:app --host 0.0.0.0 --port 8001 --workers 1 + +# mingxi-backend(推理服务器,Linux) +cd mingxi-backend +pip install -r requirements.txt +python manage.py migrate +python manage.py runserver 0.0.0.0:8000 + +# mingxi-frontend(推理服务器,Linux) +cd mingxi-frontend +npm install +npm run build # 生产:dist/ 由 nginx 托管 +npm run dev # 开发:localhost:5173 + +# mingxi-capture(前置机,Windows,开发阶段) +cd mingxi-capture +pip install -r requirements.txt +python main.py # 启动桌面程序,自动进入Mock模式(若配置了图片目录) +``` + +### 11.2 环境变量 + +```bash +# mingxi-vision/.env +MODEL_PATH=./models/pcb_defect_v1.pt +RUNTIME=ultralytics # 或 onnx +DEVICE=cuda # 或 cpu +CONF_THRESHOLD=0.45 + +# mingxi-backend/.env +SECRET_KEY=... +DATABASE_PATH=./db.sqlite3 +VISION_SERVICE_URL=http://127.0.0.1:8001 +CORS_ALLOWED_ORIGINS=http://localhost:5173 +MODEL_STORAGE_DIR=/opt/mingxi/models +MODEL_MAX_BACKUPS=10 +``` + +### 11.3 开发联调注意事项 + +- `mingxi-capture` 在 Windows 开发机上运行,配置 vision/backend 为开发机局域网IP +- `mingxi-vision` 和 `mingxi-backend` 建议在同一台机器(或WSL2)上启动 +- SQLite 文件在 `mingxi-backend/` 目录下,无需额外数据库服务 + +--- + +## 12. 参考资料 + +| 资料 | 路径/来源 | +|------|---------| +| 创业技术书 | `梅州创新创业大赛/创业技术书v1.3.docx` | +| 明析vision架构详细设计 | `梅州创新创业大赛/mingxi-vision-架构设计.md` | +| 现有后端代码 | `yolo_classification_system/` | +| PCB缺陷检测调研 | `梅州创新创业大赛/pcb缺陷检测初步方案.md` | +| 海康MVS SDK | 随MVS安装包提供,路径:`C:\Program Files (x86)\MVS\Development\` | +| HRIPCB数据集 | 公开学术数据集,CC BY 4.0,6类缺陷,10,000+样本 | +| PyQt5文档 | https://doc.qt.io/qtforpython-5/ | +| PyInstaller文档 | https://pyinstaller.org/en/stable/ | diff --git a/mingxi-backend/apps/__init__.py b/mingxi-backend/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/auth/__init__.py b/mingxi-backend/apps/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/auth/models.py b/mingxi-backend/apps/auth/models.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/auth/views.py b/mingxi-backend/apps/auth/views.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/detection/__init__.py b/mingxi-backend/apps/detection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/detection/models.py b/mingxi-backend/apps/detection/models.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/detection/views.py b/mingxi-backend/apps/detection/views.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/stats/__init__.py b/mingxi-backend/apps/stats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/stats/models.py b/mingxi-backend/apps/stats/models.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/stats/views.py b/mingxi-backend/apps/stats/views.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/system/__init__.py b/mingxi-backend/apps/system/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/system/models.py b/mingxi-backend/apps/system/models.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/apps/system/views.py b/mingxi-backend/apps/system/views.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/config/__init__.py b/mingxi-backend/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/config/settings.py b/mingxi-backend/config/settings.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/config/urls.py b/mingxi-backend/config/urls.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/config/wsgi.py b/mingxi-backend/config/wsgi.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/manage.py b/mingxi-backend/manage.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-backend/requirements.txt b/mingxi-backend/requirements.txt new file mode 100644 index 0000000..4efc725 --- /dev/null +++ b/mingxi-backend/requirements.txt @@ -0,0 +1,7 @@ +Django==4.1.13 +djangorestframework==3.14.0 +django-cors-headers==4.3.1 +PyJWT==2.8.0 +python-dotenv==1.0.0 +Pillow==10.2.0 +requests==2.31.0 diff --git a/mingxi-capture/camera/__init__.py b/mingxi-capture/camera/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/camera/hik_camera.py b/mingxi-capture/camera/hik_camera.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/camera/mock_camera.py b/mingxi-capture/camera/mock_camera.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/core/__init__.py b/mingxi-capture/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/core/capture_worker.py b/mingxi-capture/core/capture_worker.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/core/settings.py b/mingxi-capture/core/settings.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/core/upload_queue.py b/mingxi-capture/core/upload_queue.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/main.py b/mingxi-capture/main.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/requirements.txt b/mingxi-capture/requirements.txt new file mode 100644 index 0000000..4fdf990 --- /dev/null +++ b/mingxi-capture/requirements.txt @@ -0,0 +1,5 @@ +PyQt5==5.15.10 +requests==2.31.0 +opencv-python==4.8.1.78 +numpy==1.24.4 +pyinstaller==6.3.0 diff --git a/mingxi-capture/ui/__init__.py b/mingxi-capture/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/ui/config_dialog.py b/mingxi-capture/ui/config_dialog.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/ui/main_window.py b/mingxi-capture/ui/main_window.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-capture/ui/tray_icon.py b/mingxi-capture/ui/tray_icon.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/public/.gitkeep b/mingxi-frontend/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/src/api/.gitkeep b/mingxi-frontend/src/api/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/src/components/.gitkeep b/mingxi-frontend/src/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/src/router/.gitkeep b/mingxi-frontend/src/router/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/src/stores/.gitkeep b/mingxi-frontend/src/stores/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-frontend/src/views/.gitkeep b/mingxi-frontend/src/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/api/__init__.py b/mingxi-vision/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/api/detect.py b/mingxi-vision/api/detect.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/api/health.py b/mingxi-vision/api/health.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/api/model.py b/mingxi-vision/api/model.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/config.py b/mingxi-vision/config.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/__init__.py b/mingxi-vision/engine/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/annotator.py b/mingxi-vision/engine/annotator.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/base.py b/mingxi-vision/engine/base.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/defect_classes.py b/mingxi-vision/engine/defect_classes.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/loader.py b/mingxi-vision/engine/loader.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/onnx_adapter.py b/mingxi-vision/engine/onnx_adapter.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/engine/ultralytics_adapter.py b/mingxi-vision/engine/ultralytics_adapter.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/main.py b/mingxi-vision/main.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/requirements.txt b/mingxi-vision/requirements.txt new file mode 100644 index 0000000..6fc356b --- /dev/null +++ b/mingxi-vision/requirements.txt @@ -0,0 +1,9 @@ +fastapi==0.104.1 +uvicorn[standard]==0.24.0 +pydantic==1.10.13 +ultralytics==8.0.235 +onnxruntime-gpu==1.16.3 +opencv-python-headless==4.8.1.78 +numpy==1.24.4 +python-multipart==0.0.6 +python-dotenv==1.0.0 diff --git a/mingxi-vision/schema.py b/mingxi-vision/schema.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/scripts/benchmark.py b/mingxi-vision/scripts/benchmark.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/scripts/export_onnx.py b/mingxi-vision/scripts/export_onnx.py new file mode 100644 index 0000000..e69de29 diff --git a/mingxi-vision/tests/.gitkeep b/mingxi-vision/tests/.gitkeep new file mode 100644 index 0000000..e69de29