电子厂PCB板焊点缺陷检测(卷积神经网络CNN)

业务痛点:某电子厂(年产PCB板100万块,含焊点5000万个)存在三大问题:

  • 人工检测低效:依赖技工目检,每块板检测耗时2分钟,日均产能仅240块(需求500块),漏检率15%(导致售后返工成本年超800万元)
  • 缺陷类型复杂:需识别虚焊(30%)、连锡(25%)、漏焊(20%)、偏移(15%)、多余焊(10%)5类缺陷,人工易混淆相似缺陷(如虚焊与偏移)
  • 质量追溯困难:人工记录缺陷位置不精确,无法定位产线设备问题(如贴片机偏移导致批量缺陷)

算法团队:图像预处理(去噪/裁剪)、数据增强(旋转/翻转)、CNN模型构建(ResNet迁移学习)、模型训练与评估、模型存储(MinIO)

业务团队:API网关、缺陷检测服务(调用CNN模型)、质检系统集成(缺陷标注/统计分析)、分拣控制系统(PLC联动)、监控告警

CNN算法原理与场景结合点

CNN(卷积神经网络)是专为图像设计的深度学习模型,通过局部感知(卷积核提取局部特征)、权值共享(减少参数)、层次化特征提取(浅层边缘→中层纹理→深层语义),实现高效图像理解

  • 卷积层(Convolutional Layer):用滑动卷积核(如3×3)提取局部特征(如焊点边缘、锡膏形状)
  • 池化层(Pooling Layer):降维(如最大池化保留显著特征),增强平移不变性
  • 激活函数(ReLU):引入非线性,缓解梯度消失
  • 全连接层(FC Layer):整合高层特征,输出分类/定位结果

开发工具和工具链

算法团队

  • 语言:Python 3.9(模型构建/训练)、C++(TensorRT加速)
  • 深度学习框架:PyTorch 2.0(模型定义/训练)、TorchVision 0.15(数据增强)、TensorRT 8.6(推理加速)
  • 图像处理:OpenCV 4.8(去噪/裁剪)、Albumentations 1.3(高级数据增强)
  • 数据处理:Pandas 2.0(标注文件解析)、NumPy 1.24(数值计算)
  • 实验跟踪:MLflow 2.8(记录超参数/指标/模型)、Weights & Biases(可视化训练曲线)
  • 版本控制:git@github.com:pcb-factory/algorithm-defect-detection.git

业务团队

  • 语言:Go 1.20(高性能API)、Java 17(质检系统集成)
  • 服务框架:FastAPI 0.104(检测API)、Spring Boot 3.1(质检系统后端)
  • 前端:React 18(产线终端可视化)、ECharts 5.4(缺陷统计图表)
  • 数据库:PostgreSQL 15(存储检测结果/缺陷记录)、Redis 7.0(缓存热点模型)
  • 版本控制:git@github.com:pcb-factory/business-defect-detection.git

数据准备与特征变化

(1)原数据结构(图像+标注数据,来自产线)

原始数据包括PCB板高清图像(产线摄像头采集)、缺陷标注(人工标注工具生成)、设备参数(贴片机日志),存储于数据湖(MinIO),含噪声(灰尘/反光)、尺寸不一、标注缺失等问题。

① PCB图像数据(pcb_images,MinIO存储)

  • 格式:JPG/PNG,分辨率4096×2160(原始)、1024×768(压缩备份)
  • 命名规范:PCB_ID_SN.jpg(如PCB_20231001_S001.jpg,SN为序列号)
  • 示例:PCB_20231001_S001.jpg(含虚焊、连锡缺陷)

② 缺陷标注文件(defect_labels.csv,人工标注)

(2)数据清洗(详细代码,算法团队负责)

目标:去除模糊图像、修正标注错误、统一图像格式

代码文件:data_processing/image_cleaning.py

python 复制代码
import cv2
import os
import pandas as pd
import numpy as np
from PIL import Image
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def clean_image(image_dir:str,label_path:str,output_dir:str)->pd.DataFrame:
	"""清洗PCB图像:去模糊、统一格式、修正标注"""
	# 1.创建输出目录
	os.makedirs(output_dir,exist_ok=True)

	# 2.加载标注文件
	labels_df = pd.read_csv(label_path)
	valid_image = []

	for idx,row in labels_df.iterrows():
		img_path = os.path.join(image_dir,row["image_path"])
		if not os.path.exists(img_path):
			logger.warning(f"图像不存在:{img_path},跳过")
			continue
		
		# 3.读取图像并检查清晰度(拉普拉斯方差<100视为模糊)
		img = cv2.imread(img_path)
		if img is None:
			logger.warning(f"图像读取失败:{img_path},跳过")
			continue
		gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
		laplacian_var = cv2.Laplacian(gray,cv2.CV_64F).var()
		if laplacian_var < 100:
			logger.warning(f"图像模糊(方差={laplacian_var}):{img_path},跳过")  
            continue 
		
		# 4.统一格式(Resize到1024*768,转为RGB)
		img_resized = cv2.resize(img,(1024,768))
		img_rgb = cv2.cvtColor(img_resized,cv2.COLOR_BGR2RGB)

		# 保存清洗后图像
		output_path = os.path.join(output_dir,row["image_path"])
		cv2.imwrite(output_path,cv2.cvtColor(img_rgb,cv2.COLOR_RGB2BGR))# OpenCV默认BGR  

		# 5.修正标注
		h,w = img_resized.shape[:2]
		x,y,bw,bh = row["bbox_x"],row["bbox_y"],row["bbox_w"],row["bbox_h"]
		x = max(0,min(x,w-1))
		y = max(0,min(h-1))
		bw = min(bw,w-x)
		bh = min(bh,h-y)
		valid_images.append({
			"image_path": output_path, "defect_type": row["defect_type"],  
            "bbox_x": x, "bbox_y": y, "bbox_w": bw, "bbox_h": bh, "is_defective": row["is_defective"] 
		})	

	# 6.保存清洗后标注
	cleaned_labels = pd.DataFrame(valid_images)
	cleaned_label_path = os.path.join(output_dir,"cleaned_labels.csv")
	cleaned_labels.to_csv(cleaned_label_path,index=False)
	logger.info(f"清洗完成:有效图像{len(cleaned_labels)}张,保存至{output_dir}")  
    return cleaned_labels 

if __name__ == "__main__":
	# 路径配置(MinIO挂载目录)
	image_dir = "/mnt/minio/raw/pcb_images"
	label_path = "/mnt/minio/raw/defect_labels.csv"
	output_dir = "/mnt/minio/cleaned/pcb_images"
	clean_image(image_dir,label_path,output_dir)

(3)特征工程与特征数据生成(明确feature_path/label_path)

将清洗后图像转换为CNN可输入的标准化数据集,核心是数据增强(扩充样本)、归一化(像素值→0-1)、通道调整(RGB→3通道)

  • 数据增强:针对小样本缺陷(如虚焊样本少),采用旋转(±15°)、水平翻转、亮度调整(±20%)、高斯噪声(σ=0.01)扩充样本
  • 特征标准化:像素值归一化(除以255)、均值方差归一化(ImageNet均值[0.485, 0.456, 0.406],方差[0.229, 0.224, 0.225])
  • 特征数据存储:feature_path指向预处理后的图像数据集(按train/val/test划分,含增强后图像),label_path指向标注文件(含图像路径、缺陷类型、边界框)

代码文件:feature_engineering/image_preprocessor.py(预处理)、feature_engineering/data_augmentation.py(增强)、feature_engineering/generate_feature_data.py(特征数据生成)

① 数据增强(data_augmentation.py)

python 复制代码
import albumentations as A
import cv2
import os
import pandas as pd
import logging

logging.basicConfig(level=logging.INFO)  
logger = logging.getLogger(__name__)  

def augment_image(image,transform):
	"""对单张图像应用增强变换"""
	return transform(image=image)["image"]

def augment_dataset(cleaned_labels:pd.DataFrame,output_dir:str,augment_factor: int = 3)->pd.DataFrame:
	"""数据集增强:对缺陷样本(is_defective=1)扩充augment_factor倍"""
	os.makedirs(output_dir,exist_ok=True)
	autmented_labels = []
	
	# 定义增强管道(针对焊点缺陷特点:小目标、局部特征)
	transform = A.Compose([
		A.RandomRotate90(p=0.5),  
        A.HorizontalFlip(p=0.5),  
        A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.5),  
        A.GaussNoise(var_limit=(0.01, 0.05), p=0.3),  
        A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, p=0.5)  # 小角度旋转
	],bbox_params=A.BboxParams(format="pascal_voc", label_fields=["class_labels"]))
	
	for idx,row in cleaned_labels,iterrows():
		img_path = row["image_path"]
		img = cv2.imread(img_path)
		img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # 转为RGB
		bboxed = [[row["bbox_x"], row["bbox_y"], row["bbox_x"]+row["bbox_w"], row["bbox_y"]+row["bbox_h"]]]  # pascal_voc格式
		class_labels = [row["defect_type"]]

		# 原始样本保留  
        augmented_labels.append(row)  
        cv2.imwrite(os.path.join(output_dir, os.path.basename(img_path)), cv2.cvtColor(img, cv2.COLOR_RGB2BGR))

		# 对缺陷样本增强  
        if row["is_defective"] == 1:  
            for _ in range(augment_factor-1):  # 总样本数=1+(augment_factor-1)=augment_factor  
                augmented = augment_image(img, transform)  
                aug_img_path = os.path.join(output_dir, f"aug_{idx}_{_}.jpg")  
                cv2.imwrite(aug_img_path, cv2.cvtColor(augmented, cv2.COLOR_RGB2BGR))  
                # 增强后边界框(简化处理:假设增强不改变bbox相对位置,实际需用transform同步变换)  
                augmented_labels.append({  
                    "image_path": aug_img_path, "defect_type": row["defect_type"],  
                    "bbox_x": row["bbox_x"], "bbox_y": row["bbox_y"],  
                    "bbox_w": row["bbox_w"], "bbox_h": row["bbox_h"], "is_defective": 1  
                })  

    # 保存增强后标注  
    augmented_df = pd.DataFrame(augmented_labels)  
    logger.info(f"数据增强完成:原始{len(cleaned_labels)}张,增强后{augmented_df['image_path'].nunique()}张")  
    return augmented_df

② 特征数据生成(generate_feature_data.py,明确feature_path/label_path)

python 复制代码
import pandas as pd  
import os  
from data_augmentation import augment_dataset  
import logging  

logging.basicConfig(level=logging.INFO)  
logger = logging.getLogger(__name__)  

def generate_feature_data(cleaned_label_path: str, output_dir: str) -> tuple:  
    """生成特征数据集(feature_path)和标注文件(label_path)"""  
    # 1. 加载清洗后标注  
    cleaned_labels = pd.read_csv(cleaned_label_path)  
    # 2. 数据增强(扩充缺陷样本3倍)  
    augmented_labels = augment_dataset(cleaned_labels, output_dir, augment_factor=3)  
    # 3. 划分数据集(train:val:test=7:2:1)  
    from sklearn.model_selection import train_test_split  
    train_df, test_val_df = train_test_split(augmented_labels, test_size=0.3, random_state=42)  
    val_df, test_df = train_test_split(test_val_df, test_size=0.33, random_state=42)  # 0.3 * 0.33≈0.1  

    # 4. 定义文件路径(算法团队存储位置)  
    feature_path = {  # 特征数据集路径(按划分存储)  
        "train": os.path.join(output_dir, "train"),  
        "val": os.path.join(output_dir, "val"),  
        "test": os.path.join(output_dir, "test")  
    }  
    label_path = {  # 标注文件路径(按划分存储)  
        "train": os.path.join(output_dir, "train_labels.csv"),  
        "val": os.path.join(output_dir, "val_labels.csv"),  
        "test": os.path.join(output_dir, "test_labels.csv")  
    }  

    # 5. 保存划分后数据  
    train_df.to_csv(label_path["train"], index=False)  
    val_df.to_csv(label_path["val"], index=False)  
    test_df.to_csv(label_path["test"], index=False)  
    logger.info(f"""  
    【算法团队特征数据存储说明】  
    - feature_path: {feature_path}  
      存储内容:预处理+增强后的图像数据集(按train/val/test子目录存储),图像格式JPG,尺寸1024×768,RGB通道  
      示例:train/PCB_20231001_S001.jpg(原始)、train/aug_0_0.jpg(增强后)  

    - label_path: {label_path}  
      存储内容:划分后的标注文件(CSV格式),含列:  
        image_path(图像路径)、defect_type(缺陷类型:虚焊/连锡/漏焊/偏移/多余焊/正常)、  
        bbox_x/y/w/h(边界框,仅缺陷样本有值)、is_defective(1=缺陷,0=正常)  
      示例(train_labels.csv前2行):\n{train_df.head(2)}  
    """)  

    return feature_path, label_path, train_df, val_df, test_df


代码

算法团队

text 复制代码
algorithm-defect-detection/  
├── data_processing/                # 数据清洗(图像去模糊/格式统一)  
│   ├── image_cleaning.py            # 清洗代码(含详细注释)  
│   └── requirements.txt             # 依赖:opencv-python, pandas, pillow  
├── feature_engineering/            # 特征工程(增强/归一化)  
│   ├── image_preprocessor.py        # 图像归一化/通道调整  
│   ├── data_augmentation.py         # 数据增强(Albumentations)  
│   ├── generate_feature_data.py     # 特征数据生成(含feature_path/label_path说明)  
│   └── requirements.txt             # 依赖:albumentations, scikit-learn  
├── model_training/                 # CNN模型训练(核心)  
│   ├── cnn_model.py                  # CNN模型定义(ResNet迁移学习)  
│   ├── train_cnn.py                  # 训练入口(损失函数/优化器/早停)  
│   ├── evaluate_model.py             # 评估(准确率/召回率/mAP)  
│   └── cnn_params.yaml               # 调参记录(lr=0.001, batch_size=32)  
├── model_storage/                  # 模型存储(MinIO)  
│   ├── save_model.py                 # 保存模型(.pt格式)  
│   └── load_model.py                 # 加载模型(推理用)  
└── mlflow_tracking/                # MLflow实验跟踪  
    └── run_cnn_experiment.py         # 记录超参数/指标/模型

(1)算法团队:CNN模型构建与训练(model_training/cnn_model.py,含原理注释)

重点解析:基于ResNet-18迁移学习,冻结浅层特征,微调深层适配焊点缺陷,输出5类缺陷分类结果

python 复制代码
import torch
import torch.nn as nn
from torchivision.models import Resnet18_Weights
import torch.nn.functional as F
import logging

logging.basicConfig(level=logging.INFO)  
logger = logging.getLogger(__name__)  

class PCBDefectCNN(nn.Module):
	"""基于ResNet-18的PCB焊点缺陷检测CNN模型"""
	def __init__(self,num_classes=6,pretrained=True):
		"""
		:param num_classes: 缺陷类别数(5类缺陷+1类正常=6)  
        :param pretrained: 是否加载ImageNet预训练权重(迁移学习) 
		"""
		super(PCBDefectCNN,self).__init__()
		#加载预训练ResNet-18
		self.base_model = resnet18(weights=ResNet18_Weights.DEFAULT if pretrained else None)
		# 冻结浅层特征(前4层卷积,保留通用边缘/纹理提取能力)
		for param in list(self.base_model.parameters())[:-10]: # 冻结除最后2层外的参数
			param.requires_grad = False

		# 替换最后一层全连接层(适配6类分类)
		in_features = self.base_model.fc.in_features
		self.base_model.fc = nn.Sequential(
			nn.Linear(in_features,256),#中间层降维
			nn.ReLU(),
			nn.Dropout(0.5),#防止过拟合
			nn.Linear() # 输出6类概率
		)
		logger.info(f"CNN模型初始化完成:num_classes={num_classes},pretrained={pretrained}")

	def forward(self,x):
		"""前向传播:输入图像张量->输出类别概率"""
		# 卷积层提取特征(前层->:边缘-纹理-缺陷语义)
		x = self.base_model.conv1(x) # 卷积层1(7×7核,输出64通道)
		x = self.base_model.bn1(x) # 批归一化
		x = self.base_model.relu(x) # ReLU激活
		x = self.base_model.maxpool(x) # 最大池化
		# 残差块(Residual Block)提取高层特征(如焊点形状/锡膏分布)
		x = self.base_model.layer1(x) # 残差块1(输出64通道)
		x = self.base_model.layer2(x) # 残差块2(输出128通道)
		x = self.base_model.layer3(x) # 残差块3(输出256通道)
		x = self.base_model.layer4(x) # 残差块4(输出512通道)
		# 全局平局池化(将512×7×7→512×1×1) 
		x = self.base_model.avgpool(x)
		x = torch.flatten(x,1) # 展平为一维向量(512维)
		#全连接层输出分类概率
		x = self.base_model.fc(x) #输出6类logits

		return x

# 示例:模型训练配置(损失函数+优化器)
def get_loss_optimizer(model,lr=0.001,weight_decay=1e-4):
	"""获取损失函数(交叉熵)和优化器(AdamW)"""
	criterion = nn.CrossEntropyLoss(weight=torch.tensor([1.0, 2.0, 2.0, 2.0, 2.0, 1.0]))# 缺陷类权重更高(防漏检)  
	optimizer = torch.optim.AdamW(model.parameters(),lr=lr,weight_decay=weight_decay)
	return criterion, optimizer

(2)算法团队:模型训练与评估(model_training/train_cnn.py)

python 复制代码
import torch
from torch.utils.data import DataLoader,Dataset
from torchvision import transforms
import pandas as pd
from cnn_model import PCBDefectCNN,get_loss_optimizer
from PIL import Image
import mlflow
import logging

logging.basicConfig(level=logging.INFO)  
logger = logging.getLogger(__name__)  

# 自定义数据集(加载图像+标注)
class PCBDataset(Dataset):
	def __init__(self,label_path,transform=None):
		self.df = pd.read_csv(label_path)
		self.transform = transform
		self.classes = ["正常", "虚焊", "连锡", "漏焊", "偏移", "多余焊"] # 6类
	
	def __len__(self):
		return len(self.df)	

	def __getitem__(self,idx):
		row = self.df.iloc[idx]
		img = Image.open(row["image_path"]).convert("RGB") # 加载RGB图像
		label = self.classes.index(row["defect_type"])if row["is_defective"] == 1 else 0  # 正常类索引0  
		if self.transform:
			img = self.transform(img)
		return img,label
	
	def train_cnn(train_label_path: str, val_label_path: str, epochs=50, batch_size=32):
		"""训练CNN模型"""  
		# 1.数据预处理(归一化+Resize)
		transform = transforms.Compose([
			transforms.Resize((224,224)),# ResNet输入尺寸
			transforms.ToTensor(),
			transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]) # ImageNet归一化  
		])

		# 2.加载数据集
		train_dataset = PCBDataset(train_label_path,transform=trainsform)
		val_dataset = PCBDataset(val_label_path,transform=transform)
		train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
		val_loader = DataLoader(val_dataset,batch_size=batch_size,shuffle=False)

		# 3.初始化模型、损失函数、优化器
		device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
		model = PCBDefectCNN(num_classes=6,pretrained=True).to(device)
		criterion,optimizer = get_loss_optimizer(model,lr=0.001)

		# 4.循环训练(含早停)
		best_val_acc = 0.0
		for epoch in range(epochs):
			model.train()
			train_loss = 0.0
			for imgs,labels in train_loader:
				imgs,labels = imgs.to(device),labels.to(device)
				optimizer.zero_grad()
				outputs = model(imgs)
				loss = criterion(outputs,labels)
				loss.backward()
				optimizer.step()
				train_loss += loss.item() * imgs.size(0)
			train_loss /= len(train_dataset)

			# 验证集评估
			model.eval()
			val_correct = 0
			with torch.no_grad():
				for imgs,labels in val_loader:
					imgs,labels = imgs.to(device),labels.to(device)
					outputs = model(imgs)
					_,preds = torch.max(outputs,1)
					val_correct += (preds == labels).sum().item()
			
			# 记录MLflow实验
			with mlflow.start_run(run_name=f"cnn_epoch_{epoch}"):
				mlflow.log_metric("train_loss", train_loss, step=epoch)
				mlflow.log_metric("val_acc", val_acc, step=epoch)
				if val_acc > best_val_acc:
					best_val_acc = val_acc
					torch.save(model.state_dict(),"model/pcb_defect_cnn_best.pt") # 保存最佳模型  
					mlflow.log_artifact("model/pcb_defect_cnn_best.pt")
			
			logger.info(f"Epoch {epoch+1}/{epochs}, Train Loss: {train_loss:.4f}, Val Acc: {val_acc:.4f}")		
		
		logger.info(f"训练完成,最佳验证准确率:{best_val_acc:.4f}")  
    	return model

if __name__ == "__main__":
	train_label_path = "/mnt/minio/processed/train_labels.csv"  
	val_label_path = "/mnt/minio/processed/val_labels.csv" 
	train_cnn(train_label_path,val_label_path,epochs=50,batch_size=32)

算法团队服务:模型训练任务(Ray集群Job)、MinIO模型存储(持久化卷挂载)

业务团队

text 复制代码
business-defect-detection/  
├── api_gateway/                    # API网关(Kong配置)  
├── defect_detection_service/      # 缺陷检测服务(Go)  
│   ├── main.go                     # FastAPI风格Go服务(调用CNN模型)  
│   ├── model_loader.go              # 加载MinIO模型(.pt→TensorRT引擎)  
│   └── Dockerfile                  # 容器化配置  
├── quality_inspection_system/      # 质检系统(Java+React)  
│   ├── backend/                    # Spring Boot后端(缺陷统计/根因分析)  
│   ├── frontend/                   # React前端(产线终端可视化)  
│   └── sql/                        # PostgreSQL表结构(检测结果/缺陷记录)  
├── sorting_control_system/         # 分拣控制系统(PLC联动)  
└── monitoring/                     # 监控告警(Prometheus+Grafana)

代码文件:defect_detection_service/main.go(Go语言API服务)

go 复制代码
package main  

import (  
	"encoding/json"  
	"fmt"  
	"image"  
	_ "image/jpeg"  
	"log"  
	"net/http"  
	"os"  

	"gorgonia.org/tensor"  // 伪代码:张量处理库  
	"path/to/torchscript" // 伪代码:PyTorch模型加载库  
)  

// 请求/响应结构体  
type DefectRequest struct {  
	ImagePath string `json:"image_path"` // 产线图像路径(或Base64编码)  
}  

type DefectResponse struct {  
	ImagePath    string `json:"image_path"`  
	DefectType   string `json:"defect_type"` // 缺陷类型(如"虚焊")  
	Confidence   float64 `json:"confidence"` // 置信度(0-1)  
	Bbox         []int  `json:"bbox"`        // 边界框[x,y,w,h]  
	IsDefective  bool   `json:"is_defective"`  
}  

// 全局变量:加载CNN模型  
var model *torchscript.Model  

func init() {  
	// 加载算法团队训练的模型(MinIO路径)  
	modelPath := "s3://pcb-factory-models/pcb_defect_cnn_best.pt"  
	loadedModel, err := torchscript.Load(modelPath)  
	if err != nil {  
		log.Fatalf("模型加载失败:%v", err)  
	}  
	model = loadedModel  
	log.Println("CNN模型加载成功")  
}  

// 缺陷检测API处理函数  
func detectDefectHandler(w http.ResponseWriter, r *http.Request) {  
	var req DefectRequest  
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {  
		http.Error(w, "无效请求", http.StatusBadRequest)  
		return  
	}  

	// 1. 读取图像并预处理(Resize到224×224,归一化)  
	file, err := os.Open(req.ImagePath)  
	if err != nil {  
		http.Error(w, "图像读取失败", http.StatusInternalServerError)  
		return  
	}  
	defer file.Close()  
	img, _, err := image.Decode(file)  
	if err != nil {  
		http.Error(w, "图像解码失败", http.StatusInternalServerError)  
		return  
	}  
	// 预处理(简化:实际用OpenCV实现Resize+归一化)  
	inputTensor := preprocessImage(img) // 输出3×224×224张量  

	// 2. 模型推理(调用CNN)  
	output, err := model.Forward(inputTensor)  
	if err != nil {  
		http.Error(w, "模型推理失败", http.StatusInternalServerError)  
		return  
	}  

	// 3. 解析结果(取最大概率类别)  
	probs := output.Data().([]float32) // 6类概率  
	maxProb := 0.0  
	classIdx := 0  
	for i, p := range probs {  
		if p > maxProb {  
			maxProb = p  
			classIdx = i  
		}  
	}  
	defectTypes := []string{"正常", "虚焊", "连锡", "漏焊", "偏移", "多余焊"}  
	resp := DefectResponse{  
		ImagePath:   req.ImagePath,  
		DefectType:  defectTypes[classIdx],  
		Confidence:  float64(maxProb),  
		IsDefective: classIdx != 0, // 0=正常  
	}  

	// 4. 返回响应  
	w.Header().Set("Content-Type", "application/json")  
	json.NewEncoder(w).Encode(resp)  
}  

func main() {  
	http.HandleFunc("/api/detect-defect", detectDefectHandler)  
	log.Println("缺陷检测服务启动,监听端口8080")  
	log.Fatal(http.ListenAndServe(":8080", nil))  
}

业务团队服务:缺陷检测API(Go服务,Deployment部署,4副本)、质检系统(Java服务,2副本)、分拣控制系统(Edge端部署)

部署后应用流程

Step 1:产线图像采集与上传

产线摄像头(500万像素)拍摄PCB板图像(4096×2160),通过Kafka实时传输至数据湖(MinIO),文件名含板ID与序列号(如PCB_20231001_S001.jpg)

Step 2:实时缺陷检测

质检系统调用缺陷检测API(POST /api/detect-defect),传入图像路径;服务加载CNN模型,预处理后推理,返回缺陷类型、置信度、边界框

Step 3:结果反馈与分拣

产线终端(React前端)实时显示检测结果:绿色(正常)/红色(缺陷+类型),分拣控制系统(PLC)根据is_defective信号自动剔除缺陷板

Step 4:监控与迭代

监控系统跟踪漏检率,若连续3天漏检率>2%,触发Airflow调度算法团队重训模型(补充新缺陷样本+调整权重);每月生成《缺陷分析报告》,定位产线根因(如贴片机压力异常导致连锡)

相关推荐
Tadas-Gao2 小时前
缸中之脑:大模型架构的智能幻象与演进困局
人工智能·深度学习·机器学习·架构·大模型·llm
中金快讯2 小时前
新视野混合净值波动有几何?贝莱德基金回撤控制策略是否命中关键?
人工智能
楚兴2 小时前
MacBook M1 安装 OpenClaw 完整指南
人工智能·后端
23遇见2 小时前
探索CANN:开源AI计算底座的关键组件与技术思想
人工智能
jl48638212 小时前
变比测试仪显示屏的“标杆“配置!如何兼顾30000小时寿命与六角矢量图精准显示?
人工智能·经验分享·嵌入式硬件·物联网·人机交互
2301_818730562 小时前
transformer(上)
人工智能·深度学习·transformer
木枷2 小时前
Online Process Reward Learning for Agentic Reinforcement Learning
人工智能·深度学习·机器学习
m0_563745112 小时前
误差卡尔曼滤波在VINS-mono中的应用
人工智能·机器学习
恣逍信点2 小时前
《凌微经 · 理悖相涵》第六章 理悖相涵——关系构型之模因
人工智能·科技·程序人生·生活·交友·哲学