深度学习从入门到精通——图像分割实战DeeplabV3
DeeplabV3算法
- 参数配置
- 关于数据集的配置
- 训练集参数
- 数据预处理模块
- DataSet构建模块
- 测试一下数据集
- 去正则化
- 模型加载模块
- DeepLABV3+
参数配置
关于数据集的配置
parser = argparse.ArgumentParser()# Datset Optionsparser.add_argument("--data_root", type=str, default=r'D:/',help="path to Dataset")parser.add_argument("--dataset", type=str, default='voc',choices=['voc', 'cityscapes'], help='Name of dataset')parser.add_argument("--num_classes", type=int, default=None,help="num classes (default: None)")# Deeplab Options# 选择模型的架构,特征提取模块分为moiblienet或者resnet50parser.add_argument("--model", type=str, default='deeplabv3plus_resnet50',choices=['deeplabv3_resnet50', 'deeplabv3plus_resnet50','deeplabv3_resnet101', 'deeplabv3plus_resnet101','deeplabv3_mobilenet', 'deeplabv3plus_mobilenet'], help='model name')parser.add_argument("--separable_conv", action='store_true', default=False,help="apply separable conv to decoder and aspp")parser.add_argument("--output_stride", type=int, default=16, choices=[8, 16])
训练集参数
# Train Options# 制作测试parser.add_argument("--test_only", action='store_true', default=False)parser.add_argument("--save_val_results", action='store_true', default=False,help="save segmentation results to \"./results\"")parser.add_argument("--total_itrs", type=int, default=60e3,help="epoch number (default: 30k)")# 学习率parser.add_argument("--lr", type=float, default=0.01,help="learning rate (default: 0.01)")parser.add_argument("--lr_policy", type=str, default='poly', choices=['poly', 'step'],help="learning rate scheduler policy")parser.add_argument("--step_size", type=int, default=10000)parser.add_argument("--crop_val", action='store_true', default=False,help='crop validation (default: False)')parser.add_argument("--batch_size", type=int, default=8,help='batch size (default: 16)')parser.add_argument("--val_batch_size", type=int, default=4,help='batch size for validation (default: 4)')parser.add_argument("--crop_size", type=int, default=513)# 预训练权重路径parser.add_argument("--ckpt", default="./checkpoint/best_deeplabv3_resnet50_voc_os16.pth", type=str,help="restore from checkpoint")parser.add_argument("--continue_training", action='store_true', default=True)parser.add_argument("--loss_type", type=str, default='cross_entropy',choices=['cross_entropy', 'focal_loss'], help="loss type (default: False)")parser.add_argument("--gpu_id", type=str, default='0',help="GPU ID")# 正则化参数parser.add_argument("--weight_decay", type=float, default=1e-4,help='weight decay (default: 1e-4)')parser.add_argument("--random_seed", type=int, default=1,help="random seed (default: 1)")parser.add_argument("--print_interval", type=int, default=10,help="print interval of loss (default: 10)")parser.add_argument("--val_interval", type=int, default=100,help="epoch interval for eval (default: 100)")parser.add_argument("--download", action='store_true', default=False,help="download datasets")
数据预处理模块
分别针对训练集、验证集、测试集做三种数据增强变换
def get_dataset(opts):""" Dataset And Augmentation"""if opts.dataset == 'voc':train_transform = et.ExtCompose([#et.ExtResize(size=opts.crop_size),et.ExtRandomScale((0.5, 2.0)),et.ExtRandomCrop(size=(opts.crop_size, opts.crop_size), pad_if_needed=True),et.ExtRandomHorizontalFlip(),et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),])if opts.crop_val:val_transform = et.ExtCompose([et.ExtResize(opts.crop_size),et.ExtCenterCrop(opts.crop_size),et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),])else:val_transform = et.ExtCompose([et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),])train_dst = VOCSegmentation(root=opts.data_root, year=opts.year,image_set='train', download=opts.download, transform=train_transform)val_dst = VOCSegmentation(root=opts.data_root, year=opts.year,image_set='val', download=False, transform=val_transform)if opts.dataset == 'cityscapes':train_transform = et.ExtCompose([#et.ExtResize( 512 ),et.ExtRandomCrop(size=(opts.crop_size, opts.crop_size)),et.ExtColorJitter( brightness=0.5, contrast=0.5, saturation=0.5 ),et.ExtRandomHorizontalFlip(),et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),])val_transform = et.ExtCompose([#et.ExtResize( 512 ),et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),])train_dst = Cityscapes(root=opts.data_root,split='train', transform=train_transform)val_dst = Cityscapes(root=opts.data_root,split='val', transform=val_transform)return train_dst, val_dst
DataSet构建模块
def voc_cmap(N=256, normalized=False):def bitget(byteval, idx):return ((byteval & (1 << idx)) != 0)dtype = 'float32' if normalized else 'uint8'cmap = np.zeros((N, 3), dtype=dtype)for i in range(N):r = g = b = 0c = ifor j in range(8):r = r | (bitget(c, 0) << 7-j)g = g | (bitget(c, 1) << 7-j)b = b | (bitget(c, 2) << 7-j)c = c >> 3cmap[i] = np.array([r, g, b])cmap = cmap/255 if normalized else cmapreturn cmap
class VOCSegmentation(data.Dataset):"""`Pascal VOC <http://host.robots.ox.ac.uk/pascal/VOC/>`_ Segmentation Dataset.Args:root (string): Root directory of the VOC Dataset.year (string, optional): The dataset year, supports years 2007 to 2012.image_set (string, optional): Select the image_set to use, ``train``, ``trainval`` or ``val``download (bool, optional): If true, downloads the dataset from the internet andputs it in root directory. If dataset is already downloaded, it is notdownloaded again.transform (callable, optional): A function/transform that takes in an PIL imageand returns a transformed version. E.g, ``transforms.RandomCrop``"""cmap = voc_cmap()def __init__(self,root,year='2012',image_set='train',download=False,transform=None):is_aug=Falseif year=='2012_aug':is_aug = Trueyear = '2012'self.root = os.path.expanduser(root)self.year = yearself.url = DATASET_YEAR_DICT[year]['url']self.filename = DATASET_YEAR_DICT[year]['filename']self.md5 = DATASET_YEAR_DICT[year]['md5']self.transform = transformself.image_set = image_setbase_dir = DATASET_YEAR_DICT[year]['base_dir']voc_root = os.path.join(self.root, base_dir)image_dir = os.path.join(voc_root, 'JPEGImages')if download:download_extract(self.url, self.root, self.filename, self.md5)if not os.path.isdir(voc_root):raise RuntimeError('Dataset not found or corrupted.' +' You can use download=True to download it')if is_aug and image_set=='train':mask_dir = os.path.join(voc_root, 'SegmentationClassAug')assert os.path.exists(mask_dir), "SegmentationClassAug not found, please refer to README.md and prepare it manually"split_f = os.path.join( self.root, 'train_aug.txt')#'./datasets/data/train_aug.txt'else:mask_dir = os.path.join(voc_root, 'SegmentationClass')splits_dir = os.path.join(voc_root, 'ImageSets/Segmentation')split_f = os.path.join(splits_dir, image_set.rstrip('\n') + '.txt')if not os.path.exists(split_f):raise ValueError('Wrong image_set entered! Please use image_set="train" ''or image_set="trainval" or image_set="val"')with open(os.path.join(split_f), "r") as f:file_names = [x.strip() for x in f.readlines()]self.images = [os.path.join(image_dir, x + ".jpg") for x in file_names]self.masks = [os.path.join(mask_dir, x + ".png") for x in file_names]assert (len(self.images) == len(self.masks))def __getitem__(self, index):"""Args:index (int): IndexReturns:tuple: (image, target) where target is the image segmentation."""img = Image.open(self.images[index]).convert('RGB')target = Image.open(self.masks[index])if self.transform is not None:img, target = self.transform(img, target)return img, targetdef __len__(self):return len(self.images)@classmethoddef decode_target(cls, mask):"""decode semantic mask to RGB image"""return cls.cmap[mask]
测试一下数据集
import numpy as npfrom datasets import VOCSegmentation
from utils import ext_transforms as et
import cv2
train_transform = et.ExtCompose([# et.ExtResize(size=opts.crop_size),et.ExtRandomScale((0.5, 2.0)),et.ExtRandomCrop(size=(224, 224), pad_if_needed=True),et.ExtRandomHorizontalFlip(),et.ExtToTensor(),et.ExtNormalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),
])
data = VOCSegmentation(root=r"D:/", year="2012", image_set='train', download=False, transform=train_transform)if __name__ == '__main__':print(data[0][0].shape)print(data[0][1].shape)res = data.decode_target(data[0][1])cv2.imshow("Res",np.array(res))cv2.waitKey(0)
去正则化
class Denormalize(object):def __init__(self, mean, std):mean = np.array(mean)std = np.array(std)self._mean = -mean/stdself._std = 1/stddef __call__(self, tensor):if isinstance(tensor, np.ndarray):return (tensor - self._mean.reshape(-1,1,1)) / self._std.reshape(-1,1,1)return normalize(tensor, self._mean, self._std)
模型加载模块
# Set up modelmodel_map = {'deeplabv3_resnet50': network.deeplabv3_resnet50,'deeplabv3plus_resnet50': network.deeplabv3plus_resnet50,'deeplabv3_resnet101': network.deeplabv3_resnet101,'deeplabv3plus_resnet101': network.deeplabv3plus_resnet101,'deeplabv3_mobilenet': network.deeplabv3_mobilenet,'deeplabv3plus_mobilenet': network.deeplabv3plus_mobilenet}model = model_map[opts.model](num_classes=opts.num_classes, output_stride=opts.output_stride)def deeplabv3_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):"""Constructs a DeepLabV3 model with a ResNet-50 backbone.Args:num_classes (int): number of classes.output_stride (int): output stride for deeplab.pretrained_backbone (bool): If True, use the pretrained backbone."""return _load_model('deeplabv3', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)def deeplabv3_resnet101(num_classes=21, output_stride=8, pretrained_backbone=True):"""Constructs a DeepLabV3 model with a ResNet-101 backbone.Args:num_classes (int): number of classes.output_stride (int): output stride for deeplab.pretrained_backbone (bool): If True, use the pretrained backbone."""return _load_model('deeplabv3', 'resnet101', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)def deeplabv3_mobilenet(num_classes=21, output_stride=8, pretrained_backbone=True, **kwargs):"""Constructs a DeepLabV3 model with a MobileNetv2 backbone.Args:num_classes (int): number of classes.output_stride (int): output stride for deeplab.pretrained_backbone (bool): If True, use the pretrained backbone."""return _load_model('deeplabv3', 'mobilenetv2', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)# Deeplab v3+def deeplabv3plus_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):"""Constructs a DeepLabV3 model with a ResNet-50 backbone.Args:num_classes (int): number of classes.output_stride (int): output stride for deeplab.pretrained_backbone (bool): If True, use the pretrained backbone."""return _load_model('deeplabv3plus', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
加载模块
def _load_model(arch_type, backbone, num_classes, output_stride, pretrained_backbone):if backbone=='mobilenetv2':model = _segm_mobilenet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)elif backbone.startswith('resnet'):model = _segm_resnet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)else:raise NotImplementedErrorreturn modeldef _segm_resnet(name, backbone_name, num_classes, output_stride, pretrained_backbone):if output_stride==8:replace_stride_with_dilation=[False, True, True]aspp_dilate = [12, 24, 36]else:replace_stride_with_dilation=[False, False, True]aspp_dilate = [6, 12, 18]backbone = resnet.__dict__[backbone_name](pretrained=pretrained_backbone,replace_stride_with_dilation=replace_stride_with_dilation)inplanes = 2048low_level_planes = 256if name=='deeplabv3plus':return_layers = {'layer4': 'out', 'layer1': 'low_level'}#classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)elif name=='deeplabv3':return_layers = {'layer4': 'out'}classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)#提取网络的第几层输出结果并给一个别名backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)model = DeepLabV3(backbone, classifier)return model
DeepLABV3+
class DeepLabHeadV3Plus(nn.Module):def __init__(self, in_channels, low_level_channels, num_classes, aspp_dilate=[12, 24, 36]):super(DeepLabHeadV3Plus, self).__init__()self.project = nn.Sequential( nn.Conv2d(low_level_channels, 48, 1, bias=False),nn.BatchNorm2d(48),nn.ReLU(inplace=True),)self.aspp = ASPP(in_channels, aspp_dilate)self.classifier = nn.Sequential(nn.Conv2d(304, 256, 3, padding=(1,1), bias=False),nn.BatchNorm2d(256),nn.ReLU(inplace=True),nn.Conv2d(256, num_classes, 1))self._init_weight()def forward(self, feature):#print(feature.shape)low_level_feature = self.project( feature['low_level'] )#return_layers = {'layer4': 'out', 'layer1': 'low_level'}#print(low_level_feature.shape)output_feature = self.aspp(feature['out'])#print(output_feature.shape)output_feature = F.interpolate(output_feature, size=low_level_feature.shape[2:], mode='bilinear', align_corners=False)#print(output_feature.shape)return self.classifier( torch.cat( [ low_level_feature, output_feature ], dim=1 ) )def _init_weight(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight)elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)
其中,空洞融合ASPP模块
class ASPP(nn.Module):def __init__(self, in_channels, atrous_rates):super(ASPP, self).__init__()out_channels = 256modules = []modules.append(nn.Sequential(nn.Conv2d(in_channels, out_channels, 1, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True)))rate1, rate2, rate3 = tuple(atrous_rates)modules.append(ASPPConv(in_channels, out_channels, rate1))modules.append(ASPPConv(in_channels, out_channels, rate2))modules.append(ASPPConv(in_channels, out_channels, rate3))modules.append(ASPPPooling(in_channels, out_channels))self.convs = nn.ModuleList(modules)self.project = nn.Sequential(nn.Conv2d(5 * out_channels, out_channels, 1, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True),nn.Dropout(0.1),)def forward(self, x):res = []for conv in self.convs:#print(conv(x).shape)res.append(conv(x))res = torch.cat(res, dim=1)return self.project(res)
卷积转深度可分离卷积
def convert_to_separable_conv(module):new_module = moduleif isinstance(module, nn.Conv2d) and module.kernel_size[0]>1:new_module = AtrousSeparableConvolution(module.in_channels,module.out_channels, module.kernel_size,module.stride,module.padding,module.dilation,module.bias)for name, child in module.named_children():new_module.add_module(name, convert_to_separable_conv(child))return new_module
class AtrousSeparableConvolution(nn.Module):""" Atrous Separable Convolution"""def __init__(self, in_channels, out_channels, kernel_size,stride=1, padding=0, dilation=1, bias=True):super(AtrousSeparableConvolution, self).__init__()self.body = nn.Sequential(# Separable Convnn.Conv2d( in_channels, in_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=in_channels ),# PointWise Convnn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=bias),)self._init_weight()def forward(self, x):return self.body(x)def _init_weight(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight)elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)
参考代码 --------
链接: https://pan.baidu.com/s/1E6CD5NQjbKeITacH9VjxAw?pwd=jqgk 提取码: jqgk
–来自百度网盘超级会员v6的分享
相关文章:

深度学习从入门到精通——图像分割实战DeeplabV3
DeeplabV3算法 参数配置关于数据集的配置训练集参数 数据预处理模块DataSet构建模块测试一下数据集去正则化模型加载模块DeepLABV3 参数配置 关于数据集的配置 parser argparse.ArgumentParser()# Datset Optionsparser.add_argument("--data_root", typestr, defa…...

STM32-笔记5-按键点灯(中断方法)
1、复制03-流水灯项目,重命名06-按键点灯(中断法) 在\Drivers\BSP目录下创建一个文件夹exti,在该文件夹下,创建两个文件exti.c和exti.h文件,并且把这两个文件加载到项目中,打开项目工程文件 加载…...

C++ 只出现一次的数字 - 力扣(LeetCode)
点击链接即可查看题目:136. 只出现一次的数字 - 力扣(LeetCode) 一、题目 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间…...

C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
什么是享元模式? 享元模式是一个非常实用的结构型设计模式,它的主要目的是节省内存,尤其在需要创建大量相似对象时。 通俗解释: 想象我们在写一本书,每个字母都需要表示出来。如果每个字母都单独用对象表示ÿ…...

android EditText密码自动填充适配
android上的密码(其实不仅仅是密码,可以是用户名也可以是邮箱)自动填充,是需要考虑适配的。 官方文档:https://developer.android.com/identity/autofill/autofill-optimize?hlzh-cn 什么是自动填充 手机厂商一般会…...

LeetCode 刷题笔记
LeetCode 刷题笔记 1. 20241218 (1)2447 std::gcd是C17引入的一个函数,用于计算两个整数的最大公因数。位于<numeric>头文件中。 #include <iostream> #include <numeric> // std::gcdint main() {int a 36;int b 60…...

【Java基础面试题034】Java泛型擦除是什么?
回答重点 泛型擦除指的是Java编译器在编译时将所有泛型信息删除的过程,以确保与Java1.4及之前的版本保持兼容 泛型参数在运行时会被替换为其上界(通常是Object),这样一来在运行时无法获取泛型的实际类型。 作用:泛型…...

使用ssh命令远程登录服务器的两种便捷方式:简化ssh命令、创建bat文件
1. 简化ssh命令 使用记事本打开该路径C:\Users\<你的用户名>\.ssh\下的config文件,粘贴以下代码: Host myserverHostName 192.168.1.1(这里换成你的ip地址)User your_username(这里换成你的用户名)Port 22保存文件后现在在cmd中直接输入ssh myserv…...

access数据库代做/mysql代做/Sql server数据库代做辅导设计服务
针对Access数据库、MySQL以及SQL Server数据库的代做和辅导设计服务,以下是一些关键信息和建议: 一、服务概述 这些服务通常包括数据库的设计、创建、优化、维护以及相关的编程和查询编写等。无论是Access这样的桌面关系数据库管理系统(RDB…...

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书正式赛题
第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书-A 目录 一、竞赛阶段 二、竞赛任务书内容 (一)拓扑图 (二)模块A 基础设施设置与安全加固(200分) (三)B模块安全事件响应/网络安全数据取证/…...

Android学习(五)-Kotlin编程语言-面向对象中的 继承-构造函数-接口三模块学习
首先,我们需要定义一个 Person 类: open class Person {var name ""var age 0fun eat() {println("$name is eating.")} } 注意,Person 类前面加上了 open 关键字,表示这个类可以被继承。在 Kotlin 中&am…...

滑动窗口 + 算法复习
维护一个满足条件的窗口大小,然后进行双指针移动 1.最长子串 题目链接:1.最长子串 - 蓝桥云课 #include<bits/stdc.h> #define int long long using namespace std; string s; int k; signed main() {int max_len0,left0;cin>>s>>k;…...

贪心算法 greedy
文章目录 参考贪心算法[Leetcode455 分发饼干](https://leetcode.cn/problems/assign-cookies/description/)分析题解 [Leetcode135 分发糖果](https://leetcode.cn/problems/assign-cookies/description/)分析题解 leetcode435无重叠区间分析题解 参考 https://github.com/ch…...

基于python的家教预约网站-家教信息平台系统
标题:基于 Python 的家教预约网站-家教信息平台系统 内容:1.摘要 本文介绍了一个基于 Python 的家教预约网站-家教信息平台系统。该系统旨在为学生和家长提供一个方便、高效的家教预约平台,同时也为家教老师提供一个展示自己教学能力和经验的机会。本文详细介绍了系…...

基于深度学习多图像融合的屏幕缺陷检测方案
公司项目,已申请专利。 深度学习作为新兴技术在图像领域蓬勃发展,因其自主学习图像数据特征的性能避免了人工设计算法的繁琐,精准的检测性能、高效的检测效率以及对各种不同类型的图像任务都有比较好的泛化性能,使得深度学习技术在…...

MySQL基础笔记(三)
在此特别感谢尚硅谷-康师傅的MySQL精品教程 获取更好的阅读体验请前往我的博客主站! 如果本文对你的学习有帮助,请多多点赞、评论、收藏,你们的反馈是我更新最大的动力! 创建和管理表 1. 基础知识 1.1 一条数据存储的过程 存储数据是处理数…...

【JetPack】WorkManager笔记
WorkManager简介: WorkManager 是 Android Jetpack 库中的一个重要组件。它用于处理那些需要在后台可靠执行的任务,这些任务可以是一次性的,也可以是周期性的,甚至是需要满足特定条件才执行的任务。例如,它可以用于在后…...

docker 安装 ftp
前言 经多次测试 不知道为什么 必须添加被动模式跟端口才可以 连接成功,有知道为什么可以评论下 下载镜像 docker pull fauria/vsftpd启动ftp 服务 参考链接 docker run -d -v /etc/localtime:/etc/localtime:ro -v /home/dr/data/ftp:/home/vsftpd \ -e "…...

5.C语言内存分区-堆-栈
目录 内存分区 运行之前 代码区 全局初始化数据区 、静态数据区 (data) 未初始化数据区(bss(Block Started by Symbol)区) 总结 运行之后 代码区 (text segment) 未初始化数据区(bss) 全局初始化数据区,静态…...

传统CV算法——基于opencv的答题卡识别判卷系统
基于OpenCV的答题卡识别系统,其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术,自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述: 1. 导入必要的库 系统首先导入…...

国产 HighGo 数据库企业版安装与配置指南
国产 HighGo 数据库企业版安装与配置指南 1. 下载安装包 访问 HighGo 官方网站(https://www.highgo.com/),选择并下载企业版安装包。 2. 上传安装包到服务器 将下载的安装包上传至服务器,并执行以下命令: [rootmas…...

「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。 关键词 UI互动应用天气预报数据绑定动态展示状态管理 一、功能说明 自定义…...

Springboot @Transactional使用时需注意的几个问题
一、事务的隔离级别 在Springboot应用中,如果我们想实现方法一旦执行有异常产生,就触发事务回滚,可以在方法上面添加Transactional注解。如果应用采用mysql数据库,虽然mysql本身也有事务隔离机制,但在Sping数据库的应…...

数字经济下的 AR 眼镜
目录 1. 📂 AR 眼镜发展历史 1.1 AR 眼镜相关概念 1.2 市面主流 XR 眼镜 1.3 AR 眼镜大事记 1.4 国内外 XR 眼镜 1.5 国内 AR 眼镜四小龙 2. 🔱 关键技术 2.1 AR 眼镜近眼显示原理 2.2 AR 眼镜关键技术 2.3 AR 眼镜技术难点 3. Ὂ…...

力扣150题
88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 **注意:**…...

剑指offer搜索二维矩阵
题目连接 https://leetcode.cn/problems/search-a-2d-matrix-ii/’ 代码 自己想出来的 解法一 初始化两个指针,i0,j列数-1 若此时matrix[i][j]target 则返回true 若此时matrix[i][j]>target,表明在第j列中不可能存在target,因为列是升序的 若此时ma…...

如何设置浏览器不缓存网页
设置浏览器不缓存网页可以通过多种方法实现,以下是一些常见的策略: HTTP响应头控制: Cache-Control:这是最常用的HTTP头之一,用于控制响应的缓存行为。例如: Cache-Control: no-cache, no-store, must-r…...

Iris简单实现Go web服务器
package mainimport ("github.com/kataras/iris" )func main() {app : iris.New() // 实例一个iris对象//配置路由app.Get("/", func(ctx iris.Context) {ctx.WriteString("Hello Iris")})app.Get("/aa", func(ctx iris.Context) {ct…...

后端项目java中字符串、集合、日期时间常用方法
我这里只介绍了项目中最常用的哈,比如像集合有很多,但我们最常用的就是ArrayList。 然后我这里会以javascript中的字符串、数组的方法为基准来实现,有些方法js和java会有些区别也会介绍 字符串 每次修改 String 对象都会创建一个新的对象,而 StringBuffer 可以在同一个对象…...

【Spring事务】深入浅出Spring事务从原理到源码
什么是事务 保证业务操作完整性的一种数据库机制 (driver 驱动)事务特定 ACID A 原子性 (多次操作 要不一起成功 要不一起失败 (部分失败 savepoint)) C 一致性 (事务开始时数据状态,…...