unetr_plus_plus(UNETR++、nnU-Net)系列数据处理理解汇总

unetr_plus_plus(UNETR++、nnU-Net)系列数据处理理解汇总,这是一个 3D 图像分割的任务系列集。

为什么说他们是一个系列集合呢?主要是因为:

  1. 论文的训练和评价数据集是一样的,都是来自于10全挑战赛;
  2. 数据的前处理工作基本是一致的,后续的文章都延续了nnU-Net的处理方式;
  3. 评价方式是一致的,具有可比性。

所以,如果你也在做3D 图像分割相关的任务,尤其是医学领域的任务,这部分就是必看的。最好是将自己的数据进行跑通测试对比下,应该会有新的感悟。

参考阅读论文:

  1. nnU-Net: a self-configuring method for deep learning-based biomedical image segmentation
  2. nnFormer: Volumetric Medical Image Segmentation via a 3D Transformer
  3. UNETR++: Delving into Efficient and Accurate 3D Medical Image Segmentation

相关博客推荐阅读理解:

  • 对于nnU-Net论文的理解,有CSDN会员的,可以去这里看:(一:2020.07.06)nnUNet论文主体解析(8.02更新认识)。没有的可以去这里看看:医学图像深度学习分割方法的自动设计(二)
  • 数据处理部分解读:如何针对三维医学图像分割任务进行通用数据预处理:nnUNet中预处理流程总结及代码分析
  • 哔哩哔哩也有一些介绍的视频,可以作为学习的理解参考
  • 最最好的是nnU-Net这篇论文,介绍的很详细

本文后面的是参考unetr_plus_plus下面这个开源库的,不知道和原始的有啥区别,做个提醒。

  • unetr_plus_plus的开源代码地址:github code of unetr_plus_plus

nnUNet 框架,三维医学图像分割的通用预处理可以分为四步,分别是:

  • 数据格式的转换
  • 裁剪crop
  • 重采样resample
  • 标准化normalization

后面的内容,是以unetr_plus_plus这个开源项目的数据处理部分展开的介绍,主要是自己对数据处理部分的一种记录,需要的可以往后看。

一、原始数据

输入的原始图像是img2667.nii.gz,以这个为参考,查看这个数据的变化。它的基本信息如下:

(512, 512, 55)
<class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b''
dim_info        : 0
dim             : [  3 512 512  55   1   1   1   1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : float64
bitpix          : 64
slice_start     : 0
pixdim          : [1.       0.644531 0.644531 6.       1.       1.       1.       1.      ]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 0
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : unknown
sform_code      : aligned
quatern_b       : 0.0
quatern_c       : 0.0
quatern_d       : 1.0
qoffset_x       : 167.4
qoffset_y       : 165.0
qoffset_z       : 78.85
srow_x          : [ -0.644531   0.         0.       167.4     ]
srow_y          : [  0.        -0.644531   0.       165.      ]
srow_z          : [ 0.    0.    6.   78.85]
intent_name     : b''
magic           : b'n+1' <class 'nibabel.nifti1.Nifti1Header'>

原始标注标签label0026.nii.gz的信息,最大值是类别数。比如有3个类别,那么:

  • 像素值为0的,是背景
  • 像素值为1的,是类别1
  • 像素值为2的,是类别2
  • 像素值为3的,是类别3

如果之前不是这么记录的,需要先转换到这种数据形式。下面是对应标签的信息,和图像信息一致就行。

(512, 512, 55)
<class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b''
dim_info        : 0
dim             : [  3 512 512  55   1   1   1   1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : float64
bitpix          : 64
slice_start     : 0
pixdim          : [1.       0.644531 0.644531 6.       1.       1.       1.       1.      ]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 0
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : unknown
sform_code      : aligned
quatern_b       : 0.0
quatern_c       : 0.0
quatern_d       : 1.0
qoffset_x       : 167.4
qoffset_y       : 165.0
qoffset_z       : 78.85
srow_x          : [ -0.644531   0.         0.       167.4     ]
srow_y          : [  0.        -0.644531   0.       165.      ]
srow_z          : [ 0.    0.    6.   78.85]
intent_name     : b''
magic           : b'n+1' <class 'nibabel.nifti1.Nifti1Header'>

二、原始数据拆分出各个模态存储

这个阶段是第一步的处理,它需要将原始输入数据转化成不同的模态进行保存。对于一般的情况下,都是只有一个模态,转换后的形式就是这样的,img2667_0000.nii.gz

而对于Brats这个脑部数据集,就存在着多个模态的情况。尽管是不同的模态,但是他们都是同一时间节点,同时拍摄的。这样各个模态之间是一一对应的,也就是配准后的样子。如果有4个模态,那么就会有img2667_0000.nii.gzimg2667_0001.nii.gzimg2667_0002.nii.gzimg2667_0003.nii.gz。根据你自己的实际情况,得到不同的数据信息。

下面是img2667_0000.nii.gz的数据信息。

(512, 512, 55)
<class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b''
dim_info        : 0
dim             : [  3 512 512  55   1   1   1   1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : float64
bitpix          : 64
slice_start     : 0
pixdim          : [1.       0.644531 0.644531 6.       1.       1.       1.       1.      ]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 0
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : unknown
sform_code      : aligned
quatern_b       : 0.0
quatern_c       : 0.0
quatern_d       : 1.0
qoffset_x       : 167.4
qoffset_y       : 165.0
qoffset_z       : 78.85
srow_x          : [ -0.644531   0.         0.       167.4     ]
srow_y          : [  0.        -0.644531   0.       165.      ]
srow_z          : [ 0.    0.    6.   78.85]
intent_name     : b''
magic           : b'n+1' <class 'nibabel.nifti1.Nifti1Header'>

三、crop 操作后

crop是去除掉图像数据中,边缘为0的部分。比如CT 结节项目中,crop 掉肺区外的部分,只留下肺部的数据。这样剩下的图像就都是肺区的图像了,图像的数据量也就变小了。

如果,这部分你没有做非肺区的处理,那么经过crop后,图像部分的大小是不会发生改变的,还是和处理前的大小是一样的,这点不必惊讶。

3.1、npz 文件

DATASET_actTB/unetr_pp_raw/unetr_pp_cropped_data/Task002_Synapse 下img2667.npz文件记录的信息

读取代码,如下:

import numpy as np# 加载npz文件
data = np.load(npz_path)# 获取所有变量名称列表
variable_names = data.files
print("Variables in the file:", variable_names)# 选择特定的变量名称(如'array1')
selected_var = 'data'
if selected_var in variable_names:# 将选定的变量赋值给相应的变量array = data[selected_var]# 输出数组内容print(f"Array {selected_var}:")print(array.shape)
else:print(f"Variable '{selected_var}' does not exist.")

输出内容如下:

Variables in the file: ['data']
Array data:
(2, 55, 303, 426)

四维数组array(CXYZ)中:

  • 最后一个维度存储的是分割标注信息,如array[-1,:,:,:]存储的是分割标注结果。
  • 而第一个维度的前面存储不同模态的数据,如MRI数据中有FLAIR、T1w、t1gd、 T2w等四种模态,array[0,:,:,:]表示FLAIR序列成像的强度数据,array[1,:,:,:]表示T1加权的强度数据,以此类推。
  • 如果仅单模态,则四维数组第一维度长度仅为2,分别表示影像数据以及标注数据。四维数组array的后三个维度代表x,y,z三个坐标表示的三维数据,对于原始影像数据,值大小代表强度
  • 而对于标注结果,后三个维度的三维数据值分别为0,1,2……表示不同的标注类别

3.2、pkl 文件

pickle文件中存储该医学影像中其它的重要信息,是对numpy数组提供信息的补充。包含spacing,direction,origin等信息。

DATASET_actTB/unetr_pp_raw/unetr_pp_cropped_data/Task002_Synapse 下img2667.pkl文件记录的信息

OrderedDict([('original_size_of_raw_data', array([ 55, 512, 512], dtype=int64)), 
('original_spacing', array([6.        , 0.64453101, 0.64453101])), 
('list_of_data_files', ['./unetr_plus_plus-main/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/imagesTr/img2667_0000.nii.gz']), 
('seg_file', './unetr_plus_plusmain/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/labelsTr/label2667.nii.gz'), 
('itk_origin', (-167.39999389648438, -165.0, 78.8499984741211)), 
('itk_spacing', (0.6445310115814209, 0.6445310115814209, 6.0)), 
('itk_direction', (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)), 
('crop_bbox', [[0, 55], [94, 397], [54, 480]]), 
('classes', array([-1.,  0.,  1.], dtype=float32)), 
('size_after_cropping', (55, 303, 426)), 
('use_nonzero_mask_for_norm', OrderedDict([(0, False)]))]) 

四、nnFormerData_plans_v2.1_2D_stage0

4.1、npz 文件

DATASET_actTB/unetr_pp_preprocessed/Task002_Synapse/nnFormerData_plans_v2.1_2D_stage0 img2667.npz同样数组大小。

Array data:
(2, 55, 273, 384)

4.2、pkl 文件

DATASET_actTB/unetr_pp_preprocessed/Task002_Synapse/nnFormerData_plans_v2.1_2D_stage0 img2667.pkl

OrderedDict([('original_size_of_raw_data', array([ 55, 512, 512], dtype=int64)), 
('original_spacing', array([6.        , 0.64453101, 0.64453101])), 
('list_of_data_files', ['./unetr_plus_plus-main/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/imagesTr/img2667_0000.nii.gz']), ('seg_file', './unetr_plus_plusmain/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/labelsTr/label2667.nii.gz'), 
('itk_origin', (-167.39999389648438, -165.0, 78.8499984741211)), 
('itk_spacing', (0.6445310115814209, 0.6445310115814209, 6.0)), 
('itk_direction', (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)), 
('crop_bbox', [[0, 55], [94, 397], [54, 480]]), 
('classes', array([-1.,  0.,  1.], dtype=float32)), 
('size_after_cropping', (55, 303, 426)), 
('use_nonzero_mask_for_norm', OrderedDict([(0, False)])), 
('size_after_resampling', (55, 273, 384)), 
('spacing_after_resampling', array([6.        , 0.71484375, 0.71484375])), 
('class_locations', {1: array([[ 40, 244,  61],[ 46, 224,  40],[ 48, 233,  70],...,[ 34, 253,  49],[ 41, 215,  21],[ 35, 241,  32]], dtype=int64), 2: []})]) 

五、unetr_pp_Data_plans_v2.1_stage0

5.1、npz 文件

DATASET_actTB/unetr_pp_preprocessed/Task002_Synapse/unetr_pp_Data_plans_v2.1_stage0 img2667.npz

Variables in the file: ['data']
Array data:
(2, 228, 189, 266)

六、unetr_pp_Data_plans_v2.1_stage1

6.1、npz 文件

DATASET_actTB/unetr_pp_preprocessed/Task002_Synapse/unetr_pp_Data_plans_v2.1_stage1 img2667.npz

输出内容如下(经历了一次spacing调整):

Variables in the file: ['data']
Array data:
(2, 330, 273, 384)

6.2、pkl 文件

DATASET_actTB/unetr_pp_preprocessed/Task002_Synapse/unetr_pp_Data_plans_v2.1_stage1 img2667.pkl

OrderedDict([('original_size_of_raw_data', array([ 55, 512, 512], dtype=int64)), 
('original_spacing', array([6.        , 0.64453101, 0.64453101])), 
('list_of_data_files', ['/home/qlj/projects/unetr_plus_plus-main/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/imagesTr/img2667_0000.nii.gz']), ('seg_file', '/home/qlj/projects/unetr_plus_plus-main/DATASET_actTB/unetr_pp_raw/unetr_pp_raw_data/Task002_Synapse/labelsTr/label2667.nii.gz'), 
('itk_origin', (-167.39999389648438, -165.0, 78.8499984741211)), 
('itk_spacing', (0.6445310115814209, 0.6445310115814209, 6.0)), 
('itk_direction', (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)), 
('crop_bbox', [[0, 55], [94, 397], [54, 480]]), 
('classes', array([-1.,  0.,  1.], dtype=float32)), 
('size_after_cropping', (55, 303, 426)), 
('use_nonzero_mask_for_norm', OrderedDict([(0, False)])), 
('size_after_resampling', (330, 273, 384)), 
('spacing_after_resampling', array([1.        , 0.71484375, 0.71484375])), 
('class_locations', {1: array([[149, 238,  54],[259, 230,  43],[246, 230,  66],...,[141, 255,  86],[294, 213,  20],[145, 250,  72]], dtype=int64), 2: []})]) 

各个key对应的含义:

  • original_size_of_raw_data原始图像大小,
  • original_spacing 原始图像的spacing,
  • list_of_data_files 原始图像各个模态的文件路径list,
  • seg_file 对应label的文件路径list,
  • itk_origin, ‘itk_spacing’, ‘itk_direction’,
  • crop_bbox 去除原始图像四周为0的部分,z\y\x 对应的边界坐标,
  • classes 本例子包含的类别,-1是crop box去除的像素点填充,类别1、2就是标注类别,其他是0
  • size_after_cropping 裁剪后的size,
  • use_nonzero_mask_for_norm 是否使用非0的mask部分去norm 默认False,
  • size_after_resampling 使用resample操作后的size,
  • spacing_after_resampling 使用resample操作后的spacing,
  • class_locations 对应类别的坐标dict

七、preprocessed 文件

7.1、splits_final.pkl 文件

记录了k fold的中,每一个fold划分的train和val的数据名称,如下:

[OrderedDict([('train', array(['img0001', 'img0002', 'img0005', 'img0007', 'img0008', 'img0009','img0010', 'img0011', 'img0012', 'img0013', 'img0014', 'img0015','img0016', 'img0017', 'img0018', 'img0019', 'img0021', 'img0023','img0024', 'img0025', 'img0027', 'img0028', 'img0030', 'img0031','img0032', 'img0034', 'img0035', 'img0036', 'img0037', 'img0038','img0039', 'img0040'
], dtype = '<U7')), ('val', array(['img0003', 'img0004', 'img0006', 'img0020', 'img0022', 'img0026','img0029', 'img0033'
], dtype = '<U7'))]), OrderedDict([('train', array(['img0002', 'img0003', 'img0004', 'img0006', 'img0007', 'img0008','img0010', 'img0011', 'img0012', 'img0014', 'img0015', 'img0017','img0018', 'img0019', 'img0020', 'img0021', 'img0022', 'img0023','img0024', 'img0025', 'img0026', 'img0027', 'img0028', 'img0029','img0030', 'img0032', 'img0033', 'img0035', 'img0037', 'img0038','img0039', 'img0040'
], dtype = '<U7')), ('val', array(['img0001', 'img0005', 'img0009', 'img0013', 'img0016', 'img0031','img0034', 'img0036'
], dtype = '<U7'))]), OrderedDict([('train', array(['img0001', 'img0002', 'img0003', 'img0004', 'img0005', 'img0006','img0009', 'img0010', 'img0012', 'img0013', 'img0015', 'img0016','img0017', 'img0019', 'img0020', 'img0022', 'img0023', 'img0024','img0026', 'img0028', 'img0029', 'img0030', 'img0031', 'img0032','img0033', 'img0034', 'img0035', 'img0036', 'img0037', 'img0038','img0039', 'img0040'
], dtype = '<U7')), ('val', array(['img0007', 'img0008', 'img0011', 'img0014', 'img0018', 'img0021','img0025', 'img0027'
], dtype = '<U7'))]), OrderedDict([('train', array(['img0001', 'img0002', 'img0003', 'img0004', 'img0005', 'img0006','img0007', 'img0008', 'img0009', 'img0011', 'img0013', 'img0014','img0015', 'img0016', 'img0018', 'img0020', 'img0021', 'img0022','img0025', 'img0026', 'img0027', 'img0029', 'img0030', 'img0031','img0033', 'img0034', 'img0035', 'img0036', 'img0037', 'img0038','img0039', 'img0040'
], dtype = '<U7')), ('val', array(['img0010', 'img0012', 'img0017', 'img0019', 'img0023', 'img0024','img0028', 'img0032'
], dtype = '<U7'))]), OrderedDict([('train', array(['img0001', 'img0003', 'img0004', 'img0005', 'img0006', 'img0007','img0008', 'img0009', 'img0010', 'img0011', 'img0012', 'img0013','img0014', 'img0016', 'img0017', 'img0018', 'img0019', 'img0020','img0021', 'img0022', 'img0023', 'img0024', 'img0025', 'img0026','img0027', 'img0028', 'img0029', 'img0031', 'img0032', 'img0033','img0034', 'img0036'
], dtype = '<U7')), ('val', array(['img0002', 'img0015', 'img0030', 'img0035', 'img0037', 'img0038','img0039', 'img0040'
], dtype = '<U7'))])]

7.2、nnFormerPlansv2.1_plans_2D.pkl

pkl文件内存储的key的意义,如下:

  • num_stages stage的数量,
  • num_modalities,
  • modalities,
  • normalization_schemes,
  • dataset_properties 记录了所有数据的属性信息,包括size\spacing\classes\modalities\intensityproperties\size_reductions,
  • list_of_npz_files 所有croped data 的npz图像路径,
  • original_spacings 原始的spacing,
  • original_sizes 原始的size,
  • preprocessed_data_folder preprocessed data 文件夹路径,
  • num_classes 分类数量,
  • all_classes 各个类别在mask中的数字,
  • base_num_features,
  • use_mask_for_norm,
  • keep_only_largest_region,
  • min_region_size_per_class,
  • min_size_per_class,
  • transpose_forward,
  • transpose_backward,
  • data_identifier: nnFormerData_plans_v2.1_2D,
  • plans_per_stage,
  • preprocessor_name

plans_per_stage 内记录的信息如下:

{0: {'batch_size': 8,'num_pool_per_axis': [5, 4, 5],'patch_size': array([128, 112, 160], dtype = int64),'median_patient_size_in_voxels': array([190, 187, 258], dtype = int64),'current_spacing': array([1.44507647, 1.03300388, 1.03300388]),'original_spacing': array([1., 0.71484375, 0.71484375]),'do_dummy_2D_data_aug': False,'pool_op_kernel_sizes': [[2, 2, 2],[2, 2, 2],[2, 2, 2],[2, 2, 2],[2, 1, 2]],'conv_kernel_sizes': [[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3]]},1: {'batch_size': 16,'num_pool_per_axis': [5, 4, 5],'patch_size': array([64, 128, 128], dtype = int64),'median_patient_size_in_voxels': array([275, 270, 373], dtype = int64),'current_spacing': array([1., 0.71484375, 0.71484375]),'original_spacing': array([1., 0.71484375, 0.71484375]),'do_dummy_2D_data_aug': False,'pool_op_kernel_sizes': [[2, 2, 2],[2, 2, 2],[2, 2, 2]],'conv_kernel_sizes': [[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3],[3, 3, 3]]}
}

7.3、unetr_pp_Plansv2.1_plans_3D.pkl

记录内容,和7.2类似,我理解都是为了接下来的训练,做个准备配置

‘data_identifier’: ‘unetr_pp_Data_plans_v2.1’,

在训练阶段:
loading dataset of folder: /home/qlj/projects/unetr_plus_plus-main/DATASET_actTB_HU/unetr_pp_preprocessed/Task002_Synapse/unetr_pp_Data_plans_v2.1_stage1

7.3、dataset_properties.pkl

dict_keys([‘all_sizes’, ‘all_spacings’, ‘all_classes’, ‘modalities’, ‘intensityproperties’, ‘size_reductions’])

nnU-Net 这篇论文,对数据前处理和训练超参数的选择部分做了详细的介绍,对于后面的训练有很大的启发。作者认为:如果相应的管道pipeline设计得当,基本的U-Net仍然很难被击败。

意在指出:pipeline 设计的重要性。为此,设计了nnU-Net:一个深度学习框架,浓缩了当前的领域知识,并自主地做出关键决策,将基本架构转移到不同的数据集和分割任务。能够自动适应任意数据集,并基于两个关键贡献,实现开箱即用的分割:

  1. 我们用数据指纹(data fingerprint,代表数据集的关键属性)和管道指纹(pipeline fingerprint,代表分割算法的关键设计选择)来表述管道优化问题。
  2. 我们通过将领域知识(domain knowledge )压缩成一组启发式规则来明确它们之间的关系,这些规则可以在考虑相关硬件约束的情况下从相应的数据指纹稳健地生成高质量的管道指纹。

Automated Design, Without manual tuning。

nnU-Net是如何自动适应任何新的数据集呢?

data fingerprint,数据集指纹定义为包含关键属性的标准化数据集表示,如:

  1. 图像大小 image sizes
  2. 体素间距信息voxel spacing information
  3. 类别比率class ratios

pipeline fingerprint,管道指纹定义为方法设计期间所做出的整体选择,在nnU-Net中分为3个部分:

  1. blueprint parameters,例如:
    • loss function
    • optimizer
    • training schedule
    • data augmentation
  2. inferred parameters,推断参数,对新数据集进行必要的调整,例如:
    • patch size
    • batch size
    • image preprocessing(resampling, normalization)
    • architecture config
  3. empirrical parameters 经验主义参数,是通过对训练案例的交叉验证,自动识别的。包括后处理和整体策略。

数据指纹data fingerprint和推断参数inferred parameters之间的链接是通过执行一组启发式规则建立的,而不需要在应用于未见过的数据集时进行昂贵的重新优化。其中很多的设计选择是相互依赖的,例如(one instance):

  • target image spacing 影响到 image size
  • 进而又影响到 patch size
  • 进而影响到 batch size

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

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

相关文章

第五百回 Get路由管理

文章目录 1. 概念介绍2. 使用方法2.1 普通路由2.2 命名路由 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示Dialog"相关的内容&#xff0c;本章回中将介绍使用get进行路由管理.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

掌握MySQL常用的命令

前言 MySQL是一个流行的开源关系型数据库管理系统&#xff0c;广泛应用于各种应用场景。熟练掌握MySQL的常用命令&#xff0c;对于数据库管理员和开发人员来说至关重要。本文将介绍MySQL数据库的一些基础术语、SQL语言分类&#xff0c;以及DDL、DML、DQL和DCL等操作&#xff0…

高并发场景

缓存穿透 定义 大量请求的 key 是不合理的&#xff0c;根本不存在于缓存中&#xff0c;也不存在于数据库中 。这就导致这些请求直接到了数据库上&#xff0c;根本没有经过缓存这一层&#xff0c;对数据库造成了巨大的压力 举个例子 某个黑客故意制造一些非法的 key 发起大量…

C++类与对象的一些练习

1.设计一个名为Rectangle的矩形类&#xff0c;其属性为矩形的长和宽&#xff0c;能计算和输出矩形的周长和面积。 class Rectangle { public:Rectangle(int c0,int k0):m_c(c),m_k(k){}int length()//周长{return 2 * (m_c m_k);}int area()//面积{return m_c * m_k;} privat…

如何优雅简单地写 Controller 层代码?

本篇就来介绍一下&#xff0c;如何写好一个 controller &#xff0c;让你的接口变的更加优雅&#xff01; 一个完整的后端请求由 4 部分组成&#xff1a; 接口地址&#xff08;也就是 URL 地址&#xff09; 请求方式&#xff08;一般就是 get、set&#xff0c;当然还有 put、…

算法-排序详解

目录 前言 比较排序 选择排序 插入排序 冒泡排序 归并排序 快速排序 非比较类排序 计数排序 桶排序 基数排序 排序的稳定性 排序算法的题目 前言 计算机的工作之一就是对数据的处理&#xff0c;处理数据有一个常见的操作就是对数据排序&#xff0c;比如新闻系统总…

Linux——进程间通信

目录 一、进程通信的初步认识 1.1 进程间通信目的 1.2 进程间通信的种类 管道&#xff08;Pipes&#xff09; System V IPC POSIX IPC 三、管道 3.1 知识铺垫 3.2 匿名管道 3.2.1 基本概念 3.2.2 测试用例&#xff1a; 3.3 管道的行为 3.4 命名管道 3.4.1 基本概念…

Django Admin后台管理:高效开发与实践

title: Django Admin后台管理&#xff1a;高效开发与实践 date: 2024/5/8 14:24:15 updated: 2024/5/8 14:24:15 categories: 后端开发 tags: DjangoAdmin模型管理用户认证数据优化自定义扩展实战案例性能安全 第1章&#xff1a;Django Admin基础 1.1 Django Admin简介 Dj…

手撕C语言题典——反转链表

目录 前言 一.思路 1&#xff09;创建新链表 2&#xff09;创建三个指针 二.代码实现 搭配食用更佳哦~~ 数据结构之单单单——链表-CSDN博客 数据结构之单链表的基本操作-CSDN博客 前面学了单链表的相关知识&#xff0c;我们来尝试做一下关于顺序表的经典算法题~ 前言 反转…

Github 2024-05-12 php开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10Filament: 加速Laravel开发的完美起点 创建周期:1410 天开发语言:PHP协议类型:MIT LicenseStar数量:12228 个Fork数量:1990 次关…

Isaac Sim 4 键盘控制小车前进方向(学习笔记5.8.2)

写的乱糟糟&#xff0c;主要是这两周忘了记录了...吭哧吭哧往下搞&#xff0c;突然想起来要留档&#xff0c;先大致写一个&#xff0c;后面再往里添加和修改吧&#xff0c;再不写就全忘了 有一个一直没解决的问题&#xff1a; 在保存文件时出现问题&#xff1a;isaac sim mism…

Docker学习(带图详细)

一、安装docker 参考官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 查看系统版本 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# [rootlocalhost ~]# uname -a Linux localhost.localdomai…

Entity Framework Core中的延迟加载和即时加载

在Entity Framework Core&#xff08;EF Core&#xff09;中&#xff0c;延迟加载&#xff08;Lazy Loading&#xff09;和即时加载&#xff08;也称为早期加载或显式加载&#xff09;是两种主要的数据加载模式&#xff0c;它们在加载相关数据时有着不同的策略和优势。以下是这…

Leetcode 3145. Find Products of Elements of Big Array

Leetcode 3145. Find Products of Elements of Big Array 1. 解题思路2. 代码实现 题目链接&#xff1a;3145. Find Products of Elements of Big Array 1. 解题思路 这道题思路上还是比较直接的&#xff0c;就是实现上非常的繁琐&#xff0c;着实花了不少力气。 显然&…

vs code中如何使用git

由于本地代码有了一些储备&#xff0c;所以想通过网址托管形式&#xff0c;之前一直使用了github&#xff0c;但是鉴于一直被墙&#xff0c;无法登录账号&#xff0c;所以选择了国内的gitee来作为托管网站。 gitee的网址&#xff1a;Gitee - 基于 Git 的代码托管和研发协作平台…

C++11 新特性 decltype 说明符

一、typeof与typeid 1.1、typeof 在C11标准之前&#xff0c;GCC已经提供了一个类似功能的运算符 typeof对类型进行推导&#xff0c;但是这毕竟是编译器的实现&#xff0c;不是标准。 int a 0; typeof(a) b 5;1.2、typeid C标准提供了 typeid 运算符&#xff0c;获取的类型…

在另外一个页面,让另外一个页面弹框显示操作(调佣公共的弹框)

大概意思是&#xff0c;登录弹框在另外一个页面中&#xff0c;而当前页面不存在&#xff0c;在当前页面中判断如果token不存在&#xff0c;就弹框出登录的弹框 最后一行 window.location.href … 如果当前用户已登录&#xff0c;则执行后续操作(注意此处&#xff0c;可不要)

QT设计模式:策略模式

基本概念 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列方法&#xff0c;并使它们可以相互替换。策略模式使得算法可以独立于客户端而变化&#xff0c;使得客户端可以根据需要选择相应的算法。 策略模式通常由以下角色组…

如何创建window7,window10虚拟机

一、创建window7虚拟机 他的镜像不像window11一样可以搜到的&#xff0c;我们需要去msdn下载他的镜像文件 个人推荐倒数第四个&#xff0c;也就是我勾选的那个 这个是迅雷下载地址&#xff0c;复制到迅雷里下载就好了。 最好和我这样&#xff0c;创建文件夹&#xff0c;虚拟机…

Redis如何进行内存管理的?---过期删除策略和内存淘汰策略

1 过期删除策略 定时删除 在设置某个key 的过期时间同时&#xff0c;我们创建一个定时器&#xff0c;让定时器在该过期时间到来时&#xff0c;立即执行对其进行删除的操作。 优点&#xff1a;定时删除对内存是最友好的&#xff0c;能够保存内存的key一旦过期就能立即从内存…