FPC检测是导师交给的第一个横向落地项目 是实际为公司提供缺陷检测方案 作为第一次实战 希望能把这一路上的挫折和困难记录下来 后面避免重复犯错
项目的总流程概览
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
┌──────────────────┐ │ 测试图片 (NG/OK) │ └────────┬─────────┘ │ ▼ ┌──────────────────────────────────────┐ │ Stage 1: CPR检索 (基于Bank) │ │ DenseNet + K-means + 直方图匹配 │ └──────────────────────────────────────┘ │ ┌────────────────┴────────────────┐ │ 在ROI的Bank中找Top-5相似OK图片 │ └────────────────┬────────────────┘ │ ┌────────────────────┴────────────────────┐ │ │ ▼ ▼ ┌──────────────────────┐ ┌─────────────────────────┐ │ 测试图片特征提取 │ │ Bank图片特征提取 │ │ (ResNet50 layer2+3) │ │ (ResNet50 layer2+3) │ └──────────────────────┘ └─────────────────────────┘ │ │ ▼ ▼ ┌──────────────────────┐ ┌─────────────────────────┐ │ PatchCore多层特征融合 │ │ PatchCore多层特征融合 │ │ train_patchcore_ │ │ train_patchcore_ │ │ residual.py │ │ residual.py │ └──────────────────────┘ └───────────────────────── │ │ │ (B, 1024, 32, 32) │ (B, 1024, 32, 32) │ │ └──────────────────┬────────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ Stage 2: 残差计算 │ │ residual = test_feat - bank_feat │ └──────────────────────────────────────┘ │ ┌────────────────┴────────────────┐ │ 输出: 残差特征 (1, 1024, 32, 32) │ └────────────────┬────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ Stage 3: Swin Transformer分类 │ │ train_patchcore_residual.py │ │ 8层Transformer Encoder │ └──────────────────────────────────────┘ │ ┌────────────────┴────────────────┐ │ 输出: OK (0) / NG (1) │ │ │ └─────────────────────────────────┘
|
1.数据集的预处理
这部分大致可以分成以下几步:
- 利用sift重定位算法截取目标ROI
- 利用随机柏林噪音制造缺陷
- padding填灰
最后的数据集结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| data/ ├── 18062-图像2-ROI0/ │ ├── bank/ │ │ └── good/ │ │ ├── img/ # 正常样本图片 (.jpg) │ │ └── label/ # 标注文件 (.png) │ ├── test/ │ │ ├── good/ │ │ │ ├── img/ │ │ │ ├── label/ │ │ │ └── residual/ # 残差图 │ │ └── ng/ # 异常样本 │ │ ├── img/ │ │ ├── label/ │ │ └── residual/ │ └── train/ │ ├── good/ │ │ ├── img/ │ │ ├── label/ │ │ └── residual/ │ └── ng/ │ ├── img/ │ ├── label/ │ └── residual/
|
①sift重定位截取ROI
首先搞清楚我们的任务目标,原始数据集中是对整个FPC电子元件进行电子拍照,如果把整张图片都放进模型去识别,则会浪费很多资源。因为有很多无关的信息,所以我们应该单独把容易出现缺陷的部位抽离出来。 但是数据集中有这么多的图片,总不可能人工一个一个的去标注,因此就引入了sift重定位技术,仅仅需要几张拥有ROI标注的图片,我们就可以对整个数据集进行ROI截取
1.阶段一 关键点检测和描述符计算
1 2 3
| kp1, des1 = sift.detectAndCompute(gray_template, None) kp2, des2 = sift.detectAndCompute(gray_target, None)
|
kp 表示检测到的关键点位置 是一个 对象列表
des表示每个关键点的特征描述符
关键点是什么?
sift算法会找到图像中稳定,显著的点(比如角点和边缘点)
KeyPoint 对象包含什么
kp[0].pt # (x, y) 像素坐标
kp[0].size # 关键点邻域直径
kp[0].angle # 方向(0-360°)
kp[0].response # 响应强度(越强越好)
kp[0].octave # 金字塔层级
描述符是什么?
描述符是对关键点周围区域的数学指纹:
关键点周围 16×16 区域:
┌─────────────────┐
│ · · · · · · │ ← 计算梯度方向
│ \ | / · · │
│ · · · · · · │ ↓
│ / | \ · · │ 统计 8 方向直方图
│ · · · · · · │ ↓
└─────────────────┘ 生成 128 维向量
作用是用来匹配不同图像中的同一个点
同一个物理点,他们的描述符相似,则匹配成功
2.特征匹配和筛选
其实说白了就是根据不同点的描述符来找最相似的坐标 然后这个匹配的过程可以用最暴力的方法 针对每一个点都去遍历des2的每一个描述符。实际代码中我们使用FLANN匹配器,可以加快这个匹配过程,我不是很想去细说这个算法,就把它当作一个加速的黑盒吧
1 2 3 4 5 6
| FLANN_INDEX_KDTREE = 1 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2)
|
然后是筛选出优秀的匹配点 针对每一个des1点,我们都要去寻找TOP-2的相似点,分别是最近邻和次近邻 然后我们还要确保最近邻比次近邻匹配点要好30% 我们才认定这是一个好的匹配点
1 2 3 4 5
| good_matches = [] for m, n in matches: if m.distance < 0.7 * n.distance: good_matches.append(m)
|
3.利用匹配点计算单应性矩阵H
其实这里单独理解起来很简单 就是计算出模板图片和目标图片的变换矩阵后 针对模板的ROI坐标进行一个变换 既可以到达目标图片的ROI位置 最后再是一下透视变换校正的优化
2.CPR检索寻找最近邻图片
3.Patchcore多层特征融合和残差计算