# PCB_Detection **Repository Path**: cenkai233/PCB_Detection ## Basic Information - **Project Name**: PCB_Detection - **Description**: 检测板子微型元器件和配对 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-05-14 - **Last Updated**: 2025-05-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## PCB_Dection ## 项目背景 解决PCB板小型元器件定位和组合问题,数据来源于矢量图,需要针对大尺寸图像提炼小目标进行检测分析。 ## 项目难点 1. 如果要走目标识别的路线,需要进行矢量图格式转换,除了开源库进行快速转换外,该方案有一个缺陷就是精度不够高,针对某一部分可能会出现精度丢失。 2. 小目标如电容、电感等元器件是类似两个小矩形组合排列得到的,如果是使用标注的标准,包括图像要提取这么小一个特征难度很大。 3. 小目标里面不仅有形如矩形的目标还有圆形的目标,其承担的角色不同,如何区分。 4. 为了保证转换后的图片不失真,转换后图片若要保持近似的清晰度图片的像素值过高,一般YOLO输入的图片需要转换为640*640进行识别,而原始图像可能会有6000+ * 6000+像素的可能,大小差距过大,很难提炼目标。 5. 尝试进行图像分割后对其进行识别,图像分割的过程需要参考**YOLT(You Only Look Twice)**的思路进行图像分割,这部分第一版代码过于老旧,参考意义比较小,需要自己进行调试和思想迁移。 ## 解决方案 - 本项目设计的过程中将使用svg图像解析融合视觉识别定位完成元器件的识别: - svg图像解析主要处理的问题包括电容电阻等及其微小的元器件的识别和匹配 - 视觉识别定位主要采用YOLO或者Tensorflow模型识别大型的元器件 ## svg图像解析定位 主要的尝试思路如下所示: 1. 使用官方开源库对svg图片直接转换为png图片做处理 **===>(×)** 转换过程中像素信息丢失、模糊、会有重影 2. 可以注意到甲方发送的svg矢量图片中规格的大小以pt为单位(1pt=1/64英寸),我直接渲染出来图像的像素过高,目标识别一般输入的图像尺寸最好不要超过1920*1080,尺寸是它的好几倍,因此需要做分割?但是考虑分割后小目标识别丢失,转换使用算法解决配对和识别问题。 **===>(×)** 3. 最终思路直接使用svg文本格式的信息对图像进行提取:文本信息可以帮助提取以下内容(样例) ```xml # 画布的基本设置 # 矩形绘制 # 圆形绘制 ``` 根据上述内容做相关代码解析可以得到以下结果(我只保留小矩形部分进行配对): 原图像: ![image-20250516162639590](./markdown_images/image-20250516162639590.png) 只保留小矩形的图像: ![image-20250516162736537](./markdown_images/image-20250516162736537.png) 根据上述内容将提取到的所有矩形存储起来,并且按照我设置好的结构体存放: ```python ## 自己定义识别矩形的结构体 class Rec_rectangle: def __init__(self, center_x, center_y, x_length, y_length): self.center_x = center_x self.center_y = center_y self.x_length = x_length self.y_length = y_length def __repr__(self): return f"Rec_rectangle(center = ({self.center_x:.2f},{self.center_y:.2f}), x_length = {self.x_length:.2f}, y_length = {self.y_length})" ``` 存放后需要对上述矩形配对寻找一定规律: 1. 配对的矩形长宽大小近似相等(误差非常小)===> 分为几个不同尺寸类别 2. 矩形长边的垂直朝向一般为配对的方向(因此搜索优先等级最高方向固定) 3. 搜索到的一定是沿着该搜索方向最近的一个(也意味着某一个坐标值(x或y)会相等) 4. 假设3条件不成立,那就沿着垂直方向另外一个方向进行搜索 5. 中途我们可能遇到长和宽相等的图形为正方形,关于正方形的搜索方法即为往2个不同垂直方向找最近并且长宽相等的元器件作为最优匹配 **优化操作** 上述的搜索过程需要进行剪枝操作,可以先把所有的矩形按照某一个长宽为一类分类(舍弃小数点),接着按照从左上到右下顺序排列,后续比较花费比较次数会少很多。如果不这么做另外一种思路就是用空间换时间,创建一个和svg一样大的表来存放数据做对比,便于垂直取数。 匹配后的结果如下所示: ![image-20250516162811638](./markdown_images/image-20250516162811638.png) 其中可以发现配对的正确率比较高基本上能达到90%以上,同时我将此内容的文本格式保留起来 ![image-20250516163513204](./markdown_images/image-20250516163513204.png) ## 视觉定位识别 - 通过svg图片解析,按照等画布(pt格式转换)的大小(添加清晰度dpi值)还原图像为png ```python width_match = re.search(r'width="([\d.]+)(?:pt|px)?"', content) height_match = re.search(r'height="([\d.]+)(?:pt|px)?"', content) fig_width, fig_height = 10, 10 if width_match and height_match: fig_width = float(width_match.group(1)) fig_height = float(height_match.group(1)) ``` 抓包svg文件文字中的长宽做匹配创建等英寸大小的图片(方便后面转换回来) ```python tree = ET.parse(svg_file) root = tree.getroot() for elem in root.iter('{http://www.w3.org/2000/svg}path'): d = elem.attrib.get('d', '') style = elem.attrib.get('style', "") fill_color = parse_rgb(style) path_data = d.split() verts = [] codes = [] i = 0 while i < len(path_data): cmd = path_data[i] if cmd == 'M': x, y = float(path_data[i + 1]), float(path_data[i + 2]) verts.append((x, y)) codes.append(MplPath.MOVETO) i += 3 elif cmd == 'L': x, y = float(path_data[i + 1]), float(path_data[i + 2]) verts.append((x, y)) codes.append(MplPath.LINETO) i += 3 elif cmd == 'C': x1, y1 = float(path_data[i + 1]), float(path_data[i + 2]) x2, y2 = float(path_data[i + 3]), float(path_data[i + 4]) x3, y3 = float(path_data[i + 5]), float(path_data[i + 6]) verts.extend([(x1, y1), (x2, y2), (x3, y3)]) codes.extend([MplPath.CURVE4] * 3) i += 7 elif cmd in ['Z', 'z']: verts.append((0, 0)) codes.append(MplPath.CLOSEPOLY) i += 1 else: i += 1 # 避免死循环,跳过未知命令 if verts: mpl_path = MplPath(verts, codes) patch = PathPatch(mpl_path, facecolor=fill_color, edgecolor='none') ax.add_patch(patch) ``` 针对上述内容为抓包文字的线条提取,这里我们绘画整张图片,把所有的东西渲染上去;最后调整dpi大小让图片清晰。 原svg图和转换图图示如下所示: ![image-20250516162639590](./markdown_images/image-20250516162639590-1747384870279-1.png) ![image-20250516164020504](./markdown_images/image-20250516164020504.png) 从上述可以看出转换后的图片已经基本一致,就是图片尺寸过大用目标检测模型检测困难(一般检测大小为640*640)直接检测效果肯定很差。 - 因为小目标已经检测完,只需要对大件进行检测操作(标注精确、旋转标注) 首先需要制作相关数据集,这里采取的数据集制作策略如下: 1. 将原图像直接放入标注文件中进行标注 2. 标注后仿照dota数据集分割的形式将数据集分割成小尺寸的数据集 讲人话的说法就是把一张图像对应的一个数据文件转换为n个图像对应n个数据集文件,下图为分割前后的图像对比: image-20250516164556514 image-20250516164640332 此时写一分标签分割的文件也对标签做相应的分割,这样后续训练的时候也要用分割大小的窗口进行检测。 - 大目标模型训练,得到新模型(可能需要做图像分割) 这里使用的是YOLT模型,使用YOLTv8开源框架改进版本对其进行处理,配置好相关文件,将我们的模型进行训练。我这里使用的是YOLO11对我的标注数据进行训练。最终配好相关YOLTv8环境进行预测,预测结果如下所示: ![image-20250516164956878](./markdown_images/image-20250516164956878.png) 然后把该文件夹所有的识别结果进行导出处理: ![image-20250519135612686](./markdown_images/image-20250519135612686.png) 导出结果之后发现结果为归一化的结果,结果的格式为:类别--中心点x--中心点y--长--宽--置信度 因此我将其关键的信息进行提取: 首先获取原图像尺寸,当时转换的过程中为:原svg图像长、宽获取,设置相关dpi=10(经过测试会比较清晰)得到新的png图像。 假设原svg图像为400pt*600pt,那么新图png的像素值为4000 * 6000像素,因此在转换回去的过程中获取原图像的像素,然后根据dpi的比例进行除法操作就可以得到我要的svg图中的准确结果。导出的结果如下图所示: ![image-20250519135951596](./markdown_images/image-20250519135951596.png) 上图中包含了所有检测的信息,并且是按照svg数值大小进行规范格式。此时关于检测图形类别识别和定位完成。