(1)数据集简介
PKU-Market-PCB 印刷电路板 (PCB) 瑕疵数据集是一个公共合成 PCB 数据集,包含 1,386 张图像,具有 6 种缺陷(漏孔、鼠咬、开路、短路、杂散、杂铜),可用于图像检测、分类和配准任务。
图1 原图
(2)数据集下载
北京大学智能机器人开放实验室https://robotics.pkusz.edu.cn/resources/dataset/pcb_cnn数据集_数据集-飞桨AI Studio星河社区
https://aistudio.baidu.com/datasetdetail/320762 其中,第一种方法是百度云下载(速度慢),第二种方法是飞桨(速度快,格式是适合YOLO的)-----推荐第2种下载方式。
图2 下载结果
图3 解压原件
图4 (a)images文件夹内容;(b)pcb_cocoanno文件夹内容
(3)数据集转换(json格式转换)
步骤1:前期数据分析,对数据做进一步了解。(此步骤可省略)【其中train.json文件地址为图4中的文件地址】
import json
from collections import defaultdict
import matplotlib.pyplot as plt
# 修改1
with open("E:\\datasets\\PCB\\PCB_DATASET\\Annotations\\train.json") as f:
data = json.load(f)
imgs = {}
for img in data['images']:
imgs[img['id']] = {
'h': img['height'],
'w': img['width'],
'area': img['height'] * img['width'],
}
hw_ratios = []
area_ratios = []
label_count = defaultdict(int)
for anno in data['annotations']:
hw_ratios.append(anno['bbox'][3]/anno['bbox'][2])
area_ratios.append(anno['area']/imgs[anno['image_id']]['area'])
label_count[anno['category_id']] += 1
print(label_count, len(data['annotations']) / len(data['images']))
plt.hist(hw_ratios, bins=100, range=[0, 2])
plt.show()
plt.hist(area_ratios, bins=100, range=[0, 0.005])
plt.show()
'''
结果如下:
(defaultdict(int, {3: 399, 5: 416, 2: 435, 6: 447, 4: 412, 1: 418}),
4.261382799325464)
1、从标签来看,总共6个类别,如果加上背景类,总共7个类别;
2、各类别之间的框数量相对较平均,不需要调整默认的损失函数。(如果类别之间相差较大,建议调整损失函数,如BalancedL1Loss);
3、平均每张图的框数量在4张左右,属于比较稀疏的检测;
4、真实框的宽高比,可以看到大部分集中在1.0左右,但也有部分在0.5-1之间,少部分在1.25-2.0之间;
5、真实框在原图的大小比例,可以看到大部分框只占到了原图的0.1%,甚至更小,因此基本都是很小的目标。
'''
步骤2:转换代码(将图4中的train.json和val.json文件夹的代码转换为标签,转换前建立相应的路径结构。如图5所示)
图5 数据集
其中images是存放图片的,labels存放对应图片的标签的。
代码:
import json
import os
# 注意运行2次,train/val
# 修改1 json存储地址
json_path = "D:\\project\\yolov5\\yolov5-5.0\\yolov5-5.0-1\\data\\pcb\\pcb_cocoanno\\val.json"
# # 修改2,保存位置yolo存储地址
yolo_paths = "D:\\project\\yolov5\\yolov5-5.0\\yolov5-5.0-1\\dataset\\labels\\val2017"
with open(json_path) as f:
data = json.load(f)
imgs = {}
for img in data['images']:
imgs[img['id']] = {
'h': img['height'],
'w': img['width'],
'file_name': img['file_name'],
}
tmp = ''
for anno in data['annotations']:
print(imgs[anno['image_id']]['file_name'])
if imgs[anno['image_id']] != tmp:
txt_path = os.path.join(yolo_paths, imgs[anno['image_id']]['file_name'].split('.')[0] + '.txt')
txt_file = open(txt_path, 'w')
# xywh --> xywh(归一化)
bbox = [anno['bbox'][0] / imgs[anno['image_id']]['w'],
anno['bbox'][1] / imgs[anno['image_id']]['h'],
anno['bbox'][2] / imgs[anno['image_id']]['w'],
anno['bbox'][3] / imgs[anno['image_id']]['h']]
cls_id = anno['category_id']
# 保存
txt_file.write(str(cls_id) + ' ' + " ".join([str(a) for a in bbox]) + "\n") # 生成格式0 cx,cy,w,h
tmp = imgs[anno['image_id']]
else:
# xywh --> xywh(归一化)
bbox = [anno['bbox'][0] / imgs[anno['image_id']]['w'],
anno['bbox'][1] / imgs[anno['image_id']]['h'],
anno['bbox'][2] / imgs[anno['image_id']]['w'],
anno['bbox'][3] / imgs[anno['image_id']]['h']]
cls_id = anno['category_id']
# 保存
txt_file.write(str(cls_id) + ' ' + " ".join([str(a) for a in bbox]) + "\n") # 生成格式0 cx,cy,w,h
注释:
json_path指的是图4中文件val.json的地址。
json_paths指的是图5中,labels文件夹下,val文件夹的地址。
此代码运行2次,分别将train.json和val.json文件代码进行转换。
步骤3:生成训练集和验证集
注意:由于已有train2017和val2017的labels文件夹,直接按名字移动图像到对应文件夹即可。
代码:
import os
import shutil
Images_path = 'E:\\datasets\\PCB\\PCB_DATASET\\images' # 源图路径
train_labels = 'E:\\datasets\\PCB\\PCB_DATASET\\labels\\train2017' # train标签路径
val_labels = 'E:\\datasets\\PCB\\PCB_DATASET\\labels\\val2017' # val标签路径
train_images = 'E:\\datasets\\PCB\\PCB_DATASET\\images\\train2017' # 保存train图像路径
val_images = 'E:\\datasets\\PCB\\PCB_DATASET\\images\\val2017' # 保存val图像路径
# 判断文件夹是否存在,不存在即创建
if not os.path.exists(train_images):
os.mkdir(train_images)
if not os.path.exists(val_images):
os.mkdir(val_images)
# 按照标签名移动对应图像
for label_name in os.listdir(train_labels):
img_name = label_name[:-3] + 'jpg' # txt2jpg
shutil.move(os.path.join(Images_path, img_name), os.path.join(train_images, img_name))
for label_name in os.listdir(val_labels):
img_name = label_name[:-3] + 'jpg' # txt2jpg
shutil.move(os.path.join(Images_path, img_name), os.path.join(val_images, img_name))
到此,数据集已经制作好,包括images(train2017与val2017)和labels(train2017与val2017)文件夹!
4 模型训练及可视化
4.1 创建数据集yaml文件
注意:路径一定填对,类别与id一定要对应!!!
创建ultralytics\cfg\datasets\PCB.yaml文件,内容如下:
path: E:\\datasets\\PCB\\VOCdevkit\\VOC2007 # dataset root dir
train: images/train2017 # train images (relative to 'path') 4 images
val: images/val2017 # val images (relative to 'path') 4 images
# Classes for DOTA 1.0
names:
0: missing_hole
1: mouse_bite
2: open_circuit
3: short
4: spur
5: spurious_copper
视频参考:
6-PCB电路板缺陷检测_模型训练_哔哩哔哩_bilibili
资料参考:
飞桨PaddlePaddle-源于产业实践的开源深度学习平台
接下来,以fast rcnn为例进行演示
代码:
在此路径下,新建一个目录,名为work.