【MindSpore学习打卡】应用实践-计算机视觉-FCN图像语义分割-基于MindSpore实现FCN-8s进行图像语义分割的教程

news2024/11/22 20:12:36

图像语义分割是计算机视觉领域中的一个重要任务,它旨在对图像中的每个像素进行分类,从而实现对图像内容的详细理解。在众多图像语义分割算法中,全卷积网络(Fully Convolutional Networks, FCN)因其端到端的训练方式和高效的像素级预测能力而备受关注。本教程将带领你使用MindSpore实现FCN-8s模型,进行图像语义分割任务。通过该教程,你将学习数据预处理、网络构建、模型训练、评估和推理的完整流程。

全卷积网络(Fully Convolutional Networks,FCN)是UC Berkeley的Jonathan Long等人于2015年在论文《Fully Convolutional Networks for Semantic Segmentation》中提出的用于图像语义分割的一种框架。FCN是首个端到端(end to end)进行像素级(pixel level)预测的全卷积网络。

FCN架构

语义分割简介

语义分割(semantic segmentation)是图像处理和机器视觉技术中关于图像理解的重要一环,常被应用于人脸识别、物体检测、医学影像、卫星图像分析、自动驾驶感知等领域。语义分割的目的是对图像中每个像素点进行分类。与普通的分类任务只输出某个类别不同,语义分割任务输出与输入大小相同的图像,输出图像的每个像素对应了输入图像每个像素的类别。

语义分割实例

模型简介

FCN主要用于图像分割领域,是一种端到端的分割方法。通过进行像素级的预测直接得出与原图大小相等的label map。因FCN丢弃全连接层替换为全卷积层,网络所有层均为卷积层,故称为全卷积网络。

全卷积神经网络主要使用以下三种技术:

  1. 卷积化(Convolutional)
    使用VGG-16作为FCN的backbone。VGG-16的输入为224*224的RGB图像,输出为1000个预测值。VGG-16中共有三个全连接层,全连接层也可视为带有覆盖整个区域的卷积。将全连接层转换为卷积层能使网络输出由一维非空间输出变为二维矩阵,利用输出能生成输入图片映射的heatmap。

    卷积化

  2. 上采样(Upsample)
    在卷积过程的卷积操作和池化操作会使得特征图的尺寸变小,为得到原图的大小的稠密图像预测,需要对得到的特征图进行上采样操作。使用双线性插值的参数来初始化上采样逆卷积的参数,后通过反向传播来学习非线性上采样。

    上采样

  3. 跳跃结构(Skip Layer)
    利用上采样技巧对最后一层的特征图进行上采样得到原图大小的分割是步长为32像素的预测,称之为FCN-32s。由于最后一层的特征图太小,损失过多细节,采用skips结构将更具有全局信息的最后一层预测和更浅层的预测结合,使预测结果获取更多的局部细节。

    跳跃结构

网络特点

  1. 不含全连接层(fc)的全卷积(fully conv)网络,可适应任意尺寸输入。
  2. 增大数据尺寸的反卷积(deconv)层,能够输出精细的结果。
  3. 结合不同深度层结果的跳级(skip)结构,同时确保鲁棒性和精确性。

数据处理

数据预处理和标准化

  • 为什么要标准化数据? 标准化数据有助于加速模型的收敛速度,并且可以防止数值过大或过小导致的数值不稳定问题。
  • 为什么要进行数据增强? 数据增强(如随机裁剪、翻转等)可以增加数据的多样性,从而提高模型的泛化能力,减少过拟合。

下载并解压数据集:

from download import download

url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/dataset_fcn8s.tar"
download(url, "./dataset", kind="tar", replace=True)

数据预处理

由于PASCAL VOC 2012数据集中图像的分辨率大多不一致,无法放在一个tensor中,故输入前需做标准化处理。

数据加载

将PASCAL VOC 2012数据集与SDB数据集进行混合。

import numpy as np
import cv2
import mindspore.dataset as ds

class SegDataset:
    def __init__(self,
                 image_mean,
                 image_std,
                 data_file='',
                 batch_size=32,
                 crop_size=512,
                 max_scale=2.0,
                 min_scale=0.5,
                 ignore_label=255,
                 num_classes=21,
                 num_readers=2,
                 num_parallel_calls=4):

        self.data_file = data_file
        self.batch_size = batch_size
        self.crop_size = crop_size
        self.image_mean = np.array(image_mean, dtype=np.float32)
        self.image_std = np.array(image_std, dtype=np.float32)
        self.max_scale = max_scale
        self.min_scale = min_scale
        self.ignore_label = ignore_label
        self.num_classes = num_classes
        self.num_readers = num_readers
        self.num_parallel_calls = num_parallel_calls
        max_scale > min_scale

    def preprocess_dataset(self, image, label):
        image_out = cv2.imdecode(np.frombuffer(image, dtype=np.uint8), cv2.IMREAD_COLOR)
        label_out = cv2.imdecode(np.frombuffer(label, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
        sc = np.random.uniform(self.min_scale, self.max_scale)
        new_h, new_w = int(sc * image_out.shape[0]), int(sc * image_out.shape[1])
        image_out = cv2.resize(image_out, (new_w, new_h), interpolation=cv2.INTER_CUBIC)
        label_out = cv2.resize(label_out, (new_w, new_h), interpolation=cv2.INTER_NEAREST)

        image_out = (image_out - self.image_mean) / self.image_std
        out_h, out_w = max(new_h, self.crop_size), max(new_w, self.crop_size)
        pad_h, pad_w = out_h - new_h, out_w - new_w
        if pad_h > 0 or pad_w > 0:
            image_out = cv2.copyMakeBorder(image_out, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT, value=0)
            label_out = cv2.copyMakeBorder(label_out, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT, value=self.ignore_label)
        offset_h = np.random.randint(0, out_h - self.crop_size + 1)
        offset_w = np.random.randint(0, out_w - self.crop_size + 1)
        image_out = image_out[offset_h: offset_h + self.crop_size, offset_w: offset_w + self.crop_size, :]
        label_out = label_out[offset_h: offset_h + self.crop_size, offset_w: offset_w+self.crop_size]
        if np.random.uniform(0.0, 1.0) > 0.5:
            image_out = image_out[:, ::-1, :]
            label_out = label_out[:, ::-1]
        image_out = image_out.transpose((2, 0, 1))
        image_out = image_out.copy()
        label_out = label_out.copy()
        label_out = label_out.astype("int32")
        return image_out, label_out

    def get_dataset(self):
        ds.config.set_numa_enable(True)
        dataset = ds.MindDataset(self.data_file, columns_list=["data", "label"],
                                 shuffle=True, num_parallel_workers=self.num_readers)
        transforms_list = self.preprocess_dataset
        dataset = dataset.map(operations=transforms_list, input_columns=["data", "label"],
                              output_columns=["data", "label"],
                              num_parallel_workers=self.num_parallel_calls)
        dataset = dataset.shuffle(buffer_size=self.batch_size * 10)
        dataset = dataset.batch(self.batch_size, drop_remainder=True)
        return dataset


# 定义创建数据集的参数
IMAGE_MEAN = [103.53, 116.28, 123.675]
IMAGE_STD = [57.375, 57.120, 58.395]
DATA_FILE = "dataset/dataset_fcn8s/mindname.mindrecord"

# 定义模型训练参数
train_batch_size = 4
crop_size = 512
min_scale = 0.5
max_scale = 2.0
ignore_label = 255
num_classes = 21

# 实例化Dataset
dataset = SegDataset(image_mean=IMAGE_MEAN,
                     image_std=IMAGE_STD,
                     data_file=DATA_FILE,
                     batch_size=train_batch_size,
                     crop_size=crop_size,
                     max_scale=max_scale,
                     min_scale=min_scale,
                     ignore_label=ignore_label,
                     num_classes=num_classes,
                     num_readers=2,
                     num_parallel_calls=4)

dataset = dataset.get_dataset()

训练集可视化

运行以下代码观察载入的数据集图片(数据处理过程中已做归一化处理)。

import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize=(16, 8))

# 对训练集中的数据进行展示
for i in range(1, 9):
    plt.subplot(2, 4, i)
    show_data = next(dataset.create_dict_iterator())
    show_images = show_data["data"].asnumpy()
    show_images = np.clip(show_images, 0, 1)
# 将图片转换HWC格式后进行展示
    plt.imshow(show_images[0].transpose(1, 2, 0))
    plt.axis("off")
    plt.subplots_adjust(wspace=0.05, hspace=0)
plt.show()

网络构建

网络流程

FCN网络的流程如下图所示:

  1. 输入图像image,经过pool1池化后,尺寸变为原始尺寸的1/2。
  2. 经过pool2池化,尺寸变为原始尺寸的1/4。
  3. 接着经过pool3、pool4、pool5池化,大小分别变为原始尺寸的1/8、1/16、1/32。
  4. 经过conv6-7卷积,输出的尺寸依然是原图的1/32。
  5. FCN-32s是最后使用反卷积,使得输出图像大小与输入图像相同。
  6. FCN-16s是将conv7的输出进行反卷积,使其尺寸扩大两倍至原图的1/16,并将其与pool4输出的特征图进行融合,后通过反卷积扩大到原始尺寸。
  7. FCN-8s是将conv7的输出进行反卷积扩大4倍,将pool4输出的特征图反卷积扩大2倍,并将pool3输出特征图拿出,三者融合后通反卷积扩大到原始尺寸。

FCN网络流程

使用以下代码构建FCN-8s网络。

import mindspore.nn as nn

class FCN8s(nn.Cell):
    def __init__(self, n_class):
        super().__init__()
        self.n_class = n_class
        self.conv1 = nn.SequentialCell(
            nn.Conv2d(in_channels=3, out_channels=64,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.Conv2d(in_channels=64, out_channels=64,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(64),
            nn.ReLU()
        )
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.SequentialCell(
            nn.Conv2d(in_channels=64, out_channels=128,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.Conv2d(in_channels=128, out_channels=128,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(128),
            nn.ReLU()
        )
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv3 = nn.SequentialCell(
            nn.Conv2d(in_channels=128, out_channels=256,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(256),
            nn.ReLU()
        )
        self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv4 = nn.SequentialCell(
            nn.Conv2d(in_channels=256, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU()
        )
        self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv5 = nn.SequentialCell(
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512,
                      kernel_size=3, weight_init='xavier_uniform'),
            nn.BatchNorm2d(512),
            nn.ReLU()
        )
        self.pool5 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv6 = nn.SequentialCell(
            nn.Conv2d(in_channels=512, out_channels=4096,
                      kernel_size=7, weight_init='xavier_uniform'),
            nn.BatchNorm2d(4096),
            nn.ReLU(),
        )
        self.conv7 = nn.SequentialCell(
            nn.Conv2d(in_channels=4096, out_channels=4096,
                      kernel_size=1, weight_init='xavier_uniform'),
            nn.BatchNorm2d(4096),
            nn.ReLU(),
        )
        self.score_fr = nn.Conv2d(in_channels=4096, out_channels=self.n_class,
                                  kernel_size=1, weight_init='xavier_uniform')
        self.upscore2 = nn.Conv2dTranspose(in_channels=self.n_class, out_channels=self.n_class,
                                           kernel_size=4, stride=2, weight_init='xavier_uniform')
        self.score_pool4 = nn.Conv2d(in_channels=512, out_channels=self.n_class,
                                     kernel_size=1, weight_init='xavier_uniform')
        self.upscore_pool4 = nn.Conv2dTranspose(in_channels=self.n_class, out_channels=self.n_class,
                                                kernel_size=4, stride=2, weight_init='xavier_uniform')
        self.score_pool3 = nn.Conv2d(in_channels=256, out_channels=self.n_class,
                                     kernel_size=1, weight_init='xavier_uniform')
        self.upscore8 = nn.Conv2dTranspose(in_channels=self.n_class, out_channels=self.n_class,
                                           kernel_size=16, stride=8, weight_init='xavier_uniform')

    def construct(self, x):
        x1 = self.conv1(x)
        p1 = self.pool1(x1)
        x2 = self.conv2(p1)
        p2 = self.pool2(x2)
        x3 = self.conv3(p2)
        p3 = self.pool3(x3)
        x4 = self.conv4(p3)
        p4 = self.pool4(x4)
        x5 = self.conv5(p4)
        p5 = self.pool5(x5)
        x6 = self.conv6(p5)
        x7 = self.conv7(x6)
        sf = self.score_fr(x7)
        u2 = self.upscore2(sf)
        s4 = self.score_pool4(p4)
        f4 = s4 + u2
        u4 = self.upscore_pool4(f4)
        s3 = self.score_pool3(p3)
        f3 = s3 + u4
        out = self.upscore8(f3)
        return out

训练准备

导入VGG-16部分预训练权重

加载预训练的VGG-16权重

  • 为什么要使用预训练模型? 使用预训练模型可以利用在大规模数据集上预训练的权重,从而加速训练过程,并且在数据量较小时,预训练模型可以提供更好的初始权重,提升模型性能。

FCN使用VGG-16作为骨干网络,用于实现图像编码。使用下面代码导入VGG-16预训练模型的部分预训练权重。

from download import download
from mindspore import load_checkpoint, load_param_into_net

url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/fcn8s_vgg16.ckpt"
download(url, "./fcn8s_vgg16.ckpt", kind="file", replace=True)

# 加载预训练模型的参数
param_dict = load_checkpoint("fcn8s_vgg16.ckpt")

# 创建FCN8s网络实例
net = FCN8s(n_class=21)

# 加载参数到网络中
load_param_into_net(net, param_dict)

定义损失函数和优化器

  • 为什么选择交叉熵损失函数? 交叉熵损失函数适用于多分类任务,它可以衡量模型输出的概率分布与真实分布之间的差异,是图像语义分割任务中常用的损失函数。
  • 为什么选择Adam优化器? Adam优化器结合了动量和RMSProp的优点,具有较快的收敛速度和较好的鲁棒性,是深度学习中常用的优化器。

使用交叉熵损失函数(Cross Entropy Loss)和Adam优化器。

import mindspore.nn as nn
import mindspore.ops as ops

class CrossEntropyLoss(nn.Cell):
    def __init__(self, num_classes, ignore_label=255):
        super(CrossEntropyLoss, self).__init__()
        self.num_classes = num_classes
        self.ignore_label = ignore_label
        self.one_hot = ops.OneHot()
        self.on_value = ops.OnesLike()(1.0)
        self.off_value = ops.ZerosLike()(0.0)
        self.ce = ops.SoftmaxCrossEntropyWithLogits()

    def construct(self, logits, labels):
        labels = ops.Reshape()(labels, (-1,))
        valid_mask = ops.NotEqual()(labels, self.ignore_label)
        labels = ops.MaskedSelect()(labels, valid_mask)
        logits = ops.Reshape()(logits, (-1, self.num_classes))
        logits = ops.MaskedSelect()(logits, valid_mask)
        logits = ops.Reshape()(logits, (-1, self.num_classes))
        one_hot_labels = self.one_hot(labels, self.num_classes, self.on_value, self.off_value)
        loss = self.ce(logits, one_hot_labels)
        return loss.mean()

loss_fn = CrossEntropyLoss(num_classes=21)
optimizer = nn.Adam(net.trainable_params(), learning_rate=0.001)

定义训练函数

from mindspore import Model, context
from mindspore.train.callback import LossMonitor, TimeMonitor

context.set_context(mode=context.GRAPH_MODE, device_target="CPU")

# 创建模型
model = Model(net, loss_fn=loss_fn, optimizer=optimizer, metrics={"accuracy"})

# 训练模型
epoch_size = 10
model.train(epoch_size, dataset, callbacks=[LossMonitor(), TimeMonitor()], dataset_sink_mode=False)

模型评估

为什么使用mIoU作为评估指标? mIoU(Mean Intersection over Union)是语义分割任务中的常用评估指标,它可以衡量预测结果与真实标签的重叠程度,反映模型的分割性能。

定义评估函数

from mindspore import Tensor
import numpy as np

def evaluate_model(model, dataset):
    model.set_train(False)
    total_inter, total_union = 0, 0
    for data in dataset.create_dict_iterator():
        image, label = data["data"], data["label"]
        pred = model.predict(image)
        pred = ops.ArgMaxWithValue(axis=1)(pred)[0].asnumpy()
        label = label.asnumpy()
        inter = np.logical_and(pred == label, label != 255)
        union = np.logical_or(pred == label, label != 255)
        total_inter += np.sum(inter)
        total_union += np.sum(union)
    return total_inter / total_union

# 评估模型
miou = evaluate_model(model, dataset)
print("Mean Intersection over Union (mIoU):", miou)

模型推理

定义推理函数

def infer(model, image):
    model.set_train(False)
    pred = model.predict(image)
    pred = ops.ArgMaxWithValue(axis=1)(pred)[0].asnumpy()
    return pred

# 推理示例
image = next(dataset.create_dict_iterator())["data"]
pred = infer(model, image)

# 可视化结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Input Image")
plt.imshow(image[0].asnumpy().transpose(1, 2, 0))
plt.axis("off")

plt.subplot(1, 2, 2)
plt.title("Predicted Segmentation")
plt.imshow(pred[0])
plt.axis("off")

plt.show()

[外链图片转存中…(img-IzGdBwQG-1719545128292)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1888293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git使用中遇到的问题(随时更新)

问题1.先创建本地库,后拉取远程仓库时上传失败的问题怎么解决? 操作主要步骤: step1 设置远程仓库地址: $ git remote add origin gitgitee.com:yourAccount/reponamexxx.git step2 推送到远程仓库: $ git push -u origin "master&qu…

API接口测试/Swgger-ui未授权访问

目录 API接口 接口文档 接口测试的方法 单流程 多流程 Swgger-ui未授权访问 在之间的一次面试中面试官问到了API接口测试,我回答的不好,因为自己确实不太会,后面才下去学习了,这里复习和练习一下 API接口 API(…

DevOps:开发与运维的无缝融合

目录 前言1. DevOps的起源与概念1.1 DevOps的起源1.2 DevOps的定义 2. DevOps的核心实践2.1 持续集成2.2 持续交付2.3 自动化 3. DevOps工具链3.1 版本控制系统3.2 持续集成工具3.3 配置管理工具3.4 容器化与编排工具3.5 监控和日志工具 4. DevOps的实际应用4.1 案例分析&#…

【技巧分享】对接多平台:高效接入淘宝、抖音、京东、拼多多等电商平台API的实战策略

当电商商家想要自研电商管理系统,或是线下ERP厂商想要开发电商业务管理功能,需要对接电商平台API,但电商平台众多,各类平台API接口也需要花费大量的时间和精力去对接,如何快速接入多个电商平台API呢?点三来…

FormMaking表单设计器V3.8发布,数据表格上线,支持多选、多级表头、列模板自定义、操作列、分页等设置

介绍 FormMaking 是基于Vue的可视化表单设计器,赋能企业实现可视化低代码开发模式;帮助开发者从传统枯燥的表单代码中解放出来,更多关注业务,快速提高效率,节省研发成本。 目前已经在OA系统、考试系统、报表系统、流程…

docker push 推送镜像到阿里云仓库

1.登陆阿里云 镜像服务,跟着指引操作就行 创建个人实例,创建命名空间、镜像仓库,绑定代码源头 2.将镜像推送到Registry $ docker login --username*** registry.cn-beijing.aliyuncs.com $ docker tag [ImageId] registry.cn-beijing.aliy…

AI商品图生成定制技术公司

AI绘画模型训练、定制服务公司案例分析— 触站AI,塑造智能设计新纪元 第一:触站AI的创新之路 触站AI的崛起标志着AI技术在艺术与设计领域应用的一个新高度。作为一家专注于企业AI图像领域的技术解决方案服务公司,触站AI以其前沿的技术和定制…

数字化精益生产系统--SRM供应商关系管理

SRM供应商关系管理,全称为Supplier Relationship Management(供应商关系管理)系统,是一种专门用于管理采购供应链和供应商关系的软件系统。该系统通过集成各个环节的采购活动,帮助企业实现采购流程的自动化、标准化和优…

AI智能体|AI打工我躺平!使用扣子Coze智能体自动生成和发布文章到微信公众号(一)

大家好,我是无界生长,国内最大AI付费社群“AI破局俱乐部”初创合伙人。这是我的第 44 篇原创文章——《AI智能体|AI打工我躺平!使用扣子Coze智能体自动生成和发布文章到微信公众号(一)》 AI智能体&#xf…

课程设计——基于FPGA的双向移位寄存器

基于FPGA的双向移位寄存器 摘 要 本文使用verilog HDL语言设计双向移位寄存器,使电路受外部信号控制,实现数字信号的双向移位等功能,其电路设计模块主要分为三个部分,分别为接受判断控制信号的组合逻辑电路部分、实现存储、运算…

系统安全保证措施方案(word原件)

一、身份鉴别 二、访问控制 三、通信完整性、保密性 四、抗抵赖 五、数据完整性 六、数据保密性 七、应用安全支撑系统设计 软件资料获取及全资料学习获取:本文末个人名片或进主页。

2024年江西省研究生数学建模竞赛C题聚变反应堆设计论文和代码分析

经过不懈的努力,2024年江西省研究生数学建模竞赛C题聚变反应堆设计论文和代码已完成,代码为C题全部问题的代码,论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解(问题1模型的建立和求解、问题2模型的建立…

金融科技在反洗钱领域的创新应用

随着金融市场的不断发展和全球化趋势的加速,洗钱活动日益猖獗,给金融机构和社会经济安全带来了严重威胁。为了有效应对这一挑战,金融科技在反洗钱领域的应用逐渐崭露头角,为打击洗钱活动提供了强有力的技术支持。本文将从多个角度…

UG NX二次开发(C#)-根据草图创建拉伸特征(UFun+NXOpen)

文章目录 1、前言2、在UG NX中创建草图,然后创建拉伸特征3、基于UFun函数的实现4、基于NXOpen的实现代码1、前言 UG NX是基于特征的三维建模软件,其中拉伸特征是一个很重要的特征,有读者问如何根据草图创建拉伸特征,我在这篇博客中讲述一下草图创建拉伸特征的UG NX二次开发…

学习springAOP

第三章 Spring AOP 第一节 AOP 简介 1. 概念 AOP全称为Aspect Oriented Programming,表示面向切面编程。何为切面呢? 由此可以得出,切面是一种将那些与业务无关,但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的…

Linux 64位系统运行32位程序

1、原理分析 Linux 64位系统运行32位程序的原理主要涉及到系统架构的兼容性、库文件的支持以及特定的运行环境设置。 1.1 系统架构兼容性 x64与x86的区别: x86是Intel于1985年推出的32位指令集架构,后被AMD、VIA等厂商广泛采用。x64(也称为…

AI需求强劲推动韩国六月芯片出口创历史新高

据路透社7月1日报道,韩国产业通商资源部最新数据显示,韩国出口连续第九个月增长,六月份海外对芯片的持续且增强的需求将芯片出口额推至历史高位。这一出口增长势头同时带动韩国制造业采购经理指数(PMI)攀升至两年多以来…

SpringBoot实战(二十八)集成 Collabora Online 实现在线编辑

目录 一、什么是 Collabora Online?二、Docker 下载并启动 CODE2.1 拉取镜像2.2 启动镜像2.3 访问界面2.4 补充:nextcloud 的镜像启动三、SpringBoot 实现 WOPI 服务3.1 什么是WOPI?3.2 Spring Boot 简单实现3.3 另一种实现方式3.4 总结四、补充:coolwsd.xml 核心配置介绍c…

类型“{}”上不存在属性“xxxx”。ts(2339)

解决:类型“{}”上不存在属性“xxxx”和非类型化函数调用不能接受类型参数等问题。 问题发现 今天一个学生,发我一张图(如下)。 他从远端拉取到本地(自家电脑)后打开的代码视图,一大堆抛红。问…

s5.日志服务

日志服务 1. rsyslog 系统日志服务2.常见日志文件3. 启用网络日志服务4. 利用 MySQL 存储日志信息5. 日志管理工具 journalctl6. Logrotate 日志转储 1. rsyslog 系统日志服务 rsyslog是CentOS 6 以后版本的系统管理服务.它提供了高性能,出色的安全性和模块化设计。…