✅博主简介:擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导,毕业论文、期刊论文经验交流。
✅成品或者定制,扫描文章底部微信二维码。
(1) 基于改进UNet网络的熔池图像语义分割与形貌提取方法
激光熔覆过程中熔池的形貌特征包含丰富的工艺信息,准确提取熔池的轮廓、面积、长度和宽度等几何参数对于评估熔覆质量具有重要意义。传统的图像分割方法如阈值分割、边缘检测等在处理熔池图像时面临诸多挑战,熔池边界模糊、背景干扰强烈、光照不均匀等因素导致分割精度难以满足工程应用需求。本研究提出了基于改进UNet网络的熔池图像语义分割方法,UNet网络采用编码器解码器结构,编码器通过连续的卷积和池化操作逐步提取图像的深层语义特征,解码器通过上采样和跳跃连接恢复图像的空间分辨率,实现像素级的精确分割。针对熔池图像的特点,本研究对UNet网络进行了改进优化,在编码器中引入残差连接加深网络层数,增强特征提取能力;在解码器中采用注意力机制对跳跃连接的特征进行加权融合,突出熔池区域的关键特征;在损失函数中结合交叉熵损失和Dice损失,解决熔池与背景类别不平衡的问题。通过激光熔覆实验采集大量熔池图像,人工标注熔池区域制作语义分割数据集,对改进的UNet网络进行训练和验证。实验结果表明改进UNet网络的分割准确率达到百分之九十八点五二,显著优于传统分割方法和原始UNet网络。基于分割结果,采用连通域分析和轮廓提取算法自动计算熔池的长度、宽度和面积等形貌参数,与人工测量结果对比,平均误差控制在百分之十五以内,验证了方法的有效性和可靠性。
(2) 基于改进YOLOv5网络的熔池状态实时识别与检测系统开发
熔池状态的实时识别对于激光熔覆过程的在线监控和质量控制至关重要。本研究根据熔覆层宽度与熔池面积的对应关系,将熔池状态划分为三类,分别为正常熔融状态、不完全熔融状态和过度熔融状态,其中正常熔融状态对应最佳的熔覆工艺参数,能够获得质量优良的熔覆层。本研究提出了基于改进YOLOv5网络的熔池状态实时识别方法,YOLOv5是一种单阶段目标检测网络,能够在一次前向传播中同时完成目标定位和分类,具有检测速度快、精度高的优点。针对熔池图像的特点,本研究对YOLOv5网络进行了针对性改进,在骨干网络中引入坐标注意力模块,增强网络对熔池空间位置信息的感知能力;在特征金字塔网络中采用双向特征融合策略,加强多尺度特征的交互;在检测头中增加小目标检测分支,提高对小尺寸熔池的检测能力。利用前述形貌提取方法获得的熔池参数对采集的熔池图像进行状态标注,构建目标检测数据集,对改进的YOLOv5网络进行训练。实验结果表明改进YOLOv5网络的识别准确率达到百分之九十六点二三,检测速度满足实时性要求。基于该网络开发了熔池检测系统,将图像分割、形貌提取和状态识别功能进行模块化封装,提供友好的图形用户界面,支持图像文件导入和实时视频流处理,为熔池形貌与状态的研究提供了便捷的软件工具。
(3) 基于离焦量调控的熔池状态闭环控制方法
激光熔覆过程中,离焦量是影响熔池状态的关键工艺参数之一,通过调节离焦量可以改变激光光斑的功率密度分布,进而影响熔池的温度场和流场特性。本研究搭建了基于离焦量调控的熔池状态闭环控制系统,系统由工业相机、图像处理单元、控制器和调焦机构组成。工业相机实时采集熔覆过程中的熔池图像,图像处理单元运行训练好的YOLOv5目标检测网络对熔池状态进行实时识别,将识别结果作为反馈信号输入控制器,控制器根据预设的控制策略计算调焦量,驱动调焦机构调整激光头的离焦量。通过系统的激光熔覆实验,研究了离焦量、熔池状态和熔池面积三者之间的定量关系,建立了离焦量调节的控制规则。
import numpy as np import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.utils.data import DataLoader, Dataset import cv2 class DoubleConv(nn.Module): def __init__(self, in_channels, out_channels): super(DoubleConv, self).__init__() self.conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) def forward(self, x): return self.conv(x) class AttentionGate(nn.Module): def __init__(self, F_g, F_l, F_int): super(AttentionGate, self).__init__() self.W_g = nn.Sequential(nn.Conv2d(F_g, F_int, kernel_size=1), nn.BatchNorm2d(F_int)) self.W_x = nn.Sequential(nn.Conv2d(F_l, F_int, kernel_size=1), nn.BatchNorm2d(F_int)) self.psi = nn.Sequential(nn.Conv2d(F_int, 1, kernel_size=1), nn.BatchNorm2d(1), nn.Sigmoid()) self.relu = nn.ReLU(inplace=True) def forward(self, g, x): g1 = self.W_g(g) x1 = self.W_x(x) psi = self.relu(g1 + x1) psi = self.psi(psi) return x * psi class ImprovedUNet(nn.Module): def __init__(self, in_channels=3, out_channels=2): super(ImprovedUNet, self).__init__() self.encoder1 = DoubleConv(in_channels, 64) self.encoder2 = DoubleConv(64, 128) self.encoder3 = DoubleConv(128, 256) self.encoder4 = DoubleConv(256, 512) self.bottleneck = DoubleConv(512, 1024) self.upconv4 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2) self.attention4 = AttentionGate(512, 512, 256) self.decoder4 = DoubleConv(1024, 512) self.upconv3 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2) self.attention3 = AttentionGate(256, 256, 128) self.decoder3 = DoubleConv(512, 256) self.upconv2 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2) self.attention2 = AttentionGate(128, 128, 64) self.decoder2 = DoubleConv(256, 128) self.upconv1 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2) self.attention1 = AttentionGate(64, 64, 32) self.decoder1 = DoubleConv(128, 64) self.final_conv = nn.Conv2d(64, out_channels, kernel_size=1) self.pool = nn.MaxPool2d(kernel_size=2, stride=2) def forward(self, x): e1 = self.encoder1(x) e2 = self.encoder2(self.pool(e1)) e3 = self.encoder3(self.pool(e2)) e4 = self.encoder4(self.pool(e3)) b = self.bottleneck(self.pool(e4)) d4 = self.upconv4(b) e4 = self.attention4(d4, e4) d4 = self.decoder4(torch.cat([d4, e4], dim=1)) d3 = self.upconv3(d4) e3 = self.attention3(d3, e3) d3 = self.decoder3(torch.cat([d3, e3], dim=1)) d2 = self.upconv2(d3) e2 = self.attention2(d2, e2) d2 = self.decoder2(torch.cat([d2, e2], dim=1)) d1 = self.upconv1(d2) e1 = self.attention1(d1, e1) d1 = self.decoder1(torch.cat([d1, e1], dim=1)) return self.final_conv(d1) class DiceLoss(nn.Module): def __init__(self, smooth=1.0): super(DiceLoss, self).__init__() self.smooth = smooth def forward(self, predictions, targets): predictions = F.softmax(predictions, dim=1)[:, 1, :, :] intersection = (predictions * targets).sum() dice = (2. * intersection + self.smooth) / (predictions.sum() + targets.sum() + self.smooth) return 1 - dice class CombinedLoss(nn.Module): def __init__(self, alpha=0.5): super(CombinedLoss, self).__init__() self.alpha = alpha self.ce_loss = nn.CrossEntropyLoss() self.dice_loss = DiceLoss() def forward(self, predictions, targets): ce = self.ce_loss(predictions, targets) dice = self.dice_loss(predictions, targets) return self.alpha * ce + (1 - self.alpha) * dice class CoordAttention(nn.Module): def __init__(self, in_channels, reduction=32): super(CoordAttention, self).__init__() self.pool_h = nn.AdaptiveAvgPool2d((None, 1)) self.pool_w = nn.AdaptiveAvgPool2d((1, None)) mid_channels = max(8, in_channels // reduction) self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1) self.bn1 = nn.BatchNorm2d(mid_channels) self.conv_h = nn.Conv2d(mid_channels, in_channels, kernel_size=1) self.conv_w = nn.Conv2d(mid_channels, in_channels, kernel_size=1) def forward(self, x): identity = x n, c, h, w = x.size() x_h = self.pool_h(x) x_w = self.pool_w(x).permute(0, 1, 3, 2) y = torch.cat([x_h, x_w], dim=2) y = F.relu(self.bn1(self.conv1(y))) x_h, x_w = torch.split(y, [h, w], dim=2) x_w = x_w.permute(0, 1, 3, 2) a_h = torch.sigmoid(self.conv_h(x_h)) a_w = torch.sigmoid(self.conv_w(x_w)) return identity * a_w * a_h class YOLOv5Backbone(nn.Module): def __init__(self, in_channels=3): super(YOLOv5Backbone, self).__init__() self.stem = nn.Sequential(nn.Conv2d(in_channels, 32, 6, 2, 2), nn.BatchNorm2d(32), nn.SiLU()) self.stage1 = self._make_stage(32, 64, 1) self.coord_att1 = CoordAttention(64) self.stage2 = self._make_stage(64, 128, 2) self.coord_att2 = CoordAttention(128) self.stage3 = self._make_stage(128, 256, 3) self.coord_att3 = CoordAttention(256) self.stage4 = self._make_stage(256, 512, 1) def _make_stage(self, in_ch, out_ch, num_blocks): layers = [nn.Conv2d(in_ch, out_ch, 3, 2, 1), nn.BatchNorm2d(out_ch), nn.SiLU()] for _ in range(num_blocks): layers.extend([nn.Conv2d(out_ch, out_ch, 3, 1, 1), nn.BatchNorm2d(out_ch), nn.SiLU()]) return nn.Sequential(*layers) def forward(self, x): x = self.stem(x) c1 = self.coord_att1(self.stage1(x)) c2 = self.coord_att2(self.stage2(c1)) c3 = self.coord_att3(self.stage3(c2)) c4 = self.stage4(c3) return c2, c3, c4 class MeltPoolDetector(nn.Module): def __init__(self, num_classes=3): super(MeltPoolDetector, self).__init__() self.backbone = YOLOv5Backbone() self.detect_head = nn.Sequential( nn.Conv2d(512, 256, 1), nn.BatchNorm2d(256), nn.SiLU(), nn.Conv2d(256, num_classes + 5, 1) ) def forward(self, x): _, _, features = self.backbone(x) return self.detect_head(features) class MeltPoolMorphologyExtractor: def __init__(self): pass def extract_morphology(self, segmentation_mask): contours, _ = cv2.findContours(segmentation_mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(contours) == 0: return None largest_contour = max(contours, key=cv2.contourArea) area = cv2.contourArea(largest_contour) rect = cv2.minAreaRect(largest_contour) width, height = rect[1] length = max(width, height) width = min(width, height) return {'area': area, 'length': length, 'width': width, 'contour': largest_contour} class DefocusController: def __init__(self, initial_defocus=0.0): self.defocus = initial_defocus self.defocus_step = 0.5 self.min_defocus = -5.0 self.max_defocus = 5.0 def update(self, pool_state): if pool_state == 'incomplete_fusion': self.defocus = max(self.min_defocus, self.defocus - self.defocus_step) elif pool_state == 'over_fusion': self.defocus = min(self.max_defocus, self.defocus + self.defocus_step) return self.defocus def train_segmentation_model(model, train_loader, val_loader, epochs, learning_rate): optimizer = optim.Adam(model.parameters(), lr=learning_rate) criterion = CombinedLoss(alpha=0.5) scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs) for epoch in range(epochs): model.train() for images, masks in train_loader: optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, masks) loss.backward() optimizer.step() scheduler.step() return model if __name__ == "__main__": segmentation_model = ImprovedUNet(in_channels=3, out_channels=2) detection_model = MeltPoolDetector(num_classes=3) morphology_extractor = MeltPoolMorphologyExtractor() defocus_controller = DefocusController(initial_defocus=0.0) dummy_image = torch.randn(1, 3, 256, 256) seg_output = segmentation_model(dummy_image) det_output = detection_model(dummy_image)如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇