深度学习·mmsegmentation基础教程

mmsegmentation的使用教程

mmsegmentation微调方法总结

  • 自定义自己的数据集:mmsegmentation\configs\_base_\datasets\ZihaoDataset_pipeline.py
  • 注册:mmsegmentation\configs\_base_\datasets\__init__.py
  • 定义训练和测试的pipeline:mmsegmentation\configs\_base_\datasets\ZihaoDataset_pipeline.py,修改关键参数(与之前匹配)
  • 融合预训练模型:configs/fastscnn/fast_scnn_8xb4-160k_cityscapes-512x1024.py和pipeline:mmsegmentation\configs\_base_\datasets\ZihaoDataset_pipeline.py文件,注意微调分割头!!!注意微调分割头!!!注意微调分割头!!!
  • 得到最后的config文件ZihaoDataset_FastSCNN_20230818.py
  • 下载预训练模型:修改mmsegmentation\configs\segformer\segformer_mit-b5_8xb2-160k_ade20k-512x512.py的pth路径,避免下载!
  • 训练:命令tools/train.py Zihao-Configs/ZihaoDataset_PSPNet_20230818.py,默认使用预训练模型开始微调
  • 测试:需要用到训练时的.pth文件
  • 推理:根据融合后的config文件和.pth文件调用inference_model()API对图片进行推理。
  • 可视化:可以使用官方提供的针对单个图片的可视化结果
  • 所有指标和日志保存在work_dirs/xxx/.json文件下,如果需要单个class的指标结果,可以使用.log文件匹配。
  • 注意:opencv加载图片的格式是:bgr格式

自定义数据集mmsegmentation\mmseg\datasets\ZihaoDataset.py

  • 继承BaseSegDatasetfrom .basesegdataset import BaseSegDataset
class ZihaoDataset(BaseSegDataset):
  • 类别和RGB标签的映射关系
METAINFO = {'classes':['background', 'red', 'green', 'white', 'seed-black', 'seed-white'],'palette':[[127,127,127], [200,0,0], [0,200,0], [144,238,144], [30,30,30], [251,189,8]]}
  • 指定图像扩展名、标注扩展名
    def __init__(self,seg_map_suffix='.png',   # 标注mask图像的格式reduce_zero_label=False, # 类别ID为0的类别是否需要除去**kwargs) -> None:super().__init__(seg_map_suffix=seg_map_suffix,reduce_zero_label=reduce_zero_label,**kwargs)
from mmseg.registry import DATASETS
from .basesegdataset import BaseSegDataset@DATASETS.register_module()
class ZihaoDataset(BaseSegDataset):# 类别和对应的 RGB配色METAINFO = {'classes':['background', 'red', 'green', 'white', 'seed-black', 'seed-white'],'palette':[[127,127,127], [200,0,0], [0,200,0], [144,238,144], [30,30,30], [251,189,8]]}# 指定图像扩展名、标注扩展名def __init__(self,seg_map_suffix='.png',   # 标注mask图像的格式reduce_zero_label=False, # 类别ID为0的类别是否需要除去**kwargs) -> None:super().__init__(seg_map_suffix=seg_map_suffix,reduce_zero_label=reduce_zero_label,**kwargs)

注册修改mmsegmentation\mmseg\datasets\__init__.py

  • 导入ZihaoDataset
from .ZihaoDataset import ZihaoDataset
  • __all__ 后面加入'ZihaoDataset'
# yapf: enable
__all__ = ['BaseSegDataset', 'BioMedical3DRandomCrop', 'BioMedical3DRandomFlip','CityscapesDataset', 'PascalVOCDataset', 'ADE20KDataset','PascalContextDataset', 'PascalContextDataset59', 'ChaseDB1Dataset','DRIVEDataset', 'HRFDataset', 'STAREDataset', 'DarkZurichDataset','NightDrivingDataset', 'COCOStuffDataset', 'LoveDADataset','MultiImageMixDataset', 'iSAIDDataset', 'ISPRSDataset', 'PotsdamDataset','LoadAnnotations', 'RandomCrop', 'SegRescale', 'PhotoMetricDistortion','RandomRotate', 'AdjustGamma', 'CLAHE', 'Rerange', 'RGB2Gray','RandomCutOut', 'RandomMosaic', 'PackSegInputs', 'ResizeToMultiple','LoadImageFromNDArray', 'LoadBiomedicalImageFromFile','LoadBiomedicalAnnotation', 'LoadBiomedicalData', 'GenerateEdge','DecathlonDataset', 'LIPDataset', 'ResizeShortestEdge','BioMedicalGaussianNoise', 'BioMedicalGaussianBlur','BioMedicalRandomGamma', 'BioMedical3DPad', 'RandomRotFlip','SynapseDataset', 'REFUGEDataset', 'MapillaryDataset_v1','MapillaryDataset_v2', 'Albu', 'LEVIRCDDataset','LoadMultipleRSImageFromFile', 'LoadSingleRSImageFromFile','ConcatCDInput', 'BaseCDDataset', 'DSDLSegDataset', 'BDD100KDataset','ZihaoDataset'
]

`mmsegmentation\mmseg相当于源码部分

configs中自定义训练和测试pipeline mmsegmentation\configs\_base_\datasets\ZihaoDataset_pipeline.py

必须修改的地方有:

  • 类名和数据集根地址,注意接下来的img_pathseg_map_path参数会和data_root拼接在一起
  • 还包括一些数据增强和训练相关的参数。
dataset_type = 'ZihaoDataset' # 数据集类名
data_root = 'Watermelon87_Semantic_Seg_Mask/' # 数据集路径(相对于mmsegmentation主目录)
  • img_pathseg_map_path参数
train_dataloader = dict(batch_size=2,num_workers=2,persistent_workers=True,sampler=dict(type='InfiniteSampler', shuffle=True),dataset=dict(type=dataset_type,data_root=data_root,data_prefix=dict(img_path='img_dir/train', seg_map_path='ann_dir/train'),pipeline=train_pipeline))# 验证 Dataloader
val_dataloader = dict(batch_size=1,num_workers=4,persistent_workers=True,sampler=dict(type='DefaultSampler', shuffle=False),dataset=dict(type=dataset_type,data_root=data_root,data_prefix=dict(img_path='img_dir/val', seg_map_path='ann_dir/val'),pipeline=test_pipeline))
# 数据处理 pipeline
# 数据集路径
dataset_type = 'ZihaoDataset' # 数据集类名
data_root = 'Watermelon87_Semantic_Seg_Mask/' # 数据集路径(相对于mmsegmentation主目录)# 输入模型的图像裁剪尺寸,一般是 128 的倍数,越小显存开销越少
crop_size = (512, 512)# 训练预处理
train_pipeline = [dict(type='LoadImageFromFile'),dict(type='LoadAnnotations'),dict(type='RandomResize',scale=(2048, 1024),ratio_range=(0.5, 2.0),keep_ratio=True),dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75),dict(type='RandomFlip', prob=0.5),dict(type='PhotoMetricDistortion'),dict(type='PackSegInputs')
]# 测试预处理
test_pipeline = [dict(type='LoadImageFromFile'),dict(type='Resize', scale=(2048, 1024), keep_ratio=True),dict(type='LoadAnnotations'),dict(type='PackSegInputs')
]# TTA后处理(增强性能的技巧)
img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] # 先缩放后全部加权得到结果
tta_pipeline = [dict(type='LoadImageFromFile', file_client_args=dict(backend='disk')),dict(type='TestTimeAug',transforms=[[dict(type='Resize', scale_factor=r, keep_ratio=True)for r in img_ratios],[dict(type='RandomFlip', prob=0., direction='horizontal'),dict(type='RandomFlip', prob=1., direction='horizontal')], [dict(type='LoadAnnotations')], [dict(type='PackSegInputs')]])
]# 训练 Dataloader
train_dataloader = dict(batch_size=2,num_workers=2,persistent_workers=True,sampler=dict(type='InfiniteSampler', shuffle=True),dataset=dict(type=dataset_type,data_root=data_root,data_prefix=dict(img_path='img_dir/train', seg_map_path='ann_dir/train'),pipeline=train_pipeline))# 验证 Dataloader
val_dataloader = dict(batch_size=1,num_workers=4,persistent_workers=True,sampler=dict(type='DefaultSampler', shuffle=False),dataset=dict(type=dataset_type,data_root=data_root,data_prefix=dict(img_path='img_dir/val', seg_map_path='ann_dir/val'),pipeline=test_pipeline))# 测试 Dataloader
test_dataloader = val_dataloader# 验证 Evaluator
val_evaluator = dict(type='IoUMetric', iou_metrics=['mIoU', 'mDice', 'mFscore'])# 测试 Evaluator
test_evaluator = val_evaluator

微调(迁移学习)方法

  • 导入两个py文件,一个是预训练模型的文件configs/fastscnn/fast_scnn_8xb4-160k_cityscapes-512x1024.py
  • 一个是我们定义好的训练和测试pipeline文件./configs/_base_/datasets/ZihaoDataset_pipeline.py
  • 两个要结合起来
from mmengine import Config
cfg = Config.fromfile('configs/fastscnn/fast_scnn_8xb4-160k_cityscapes-512x1024.py')
dataset_cfg = Config.fromfile('./configs/_base_/datasets/ZihaoDataset_pipeline.py')
cfg.merge_from_dict(dataset_cfg)

微调方法

  • 修改分割头
NUM_CLASS = 6
cfg.norm_cfg = dict(type='BN', requires_grad=True) # 只使用GPU时,BN取代SyncBN
cfg.model.backbone.norm_cfg = cfg.norm_cfg
cfg.model.decode_head.norm_cfg = cfg.norm_cfgcfg.dump('Zihao-Configs/ZihaoDataset_FastSCNN_20230818.py')
cfg.model.auxiliary_head[0].norm_cfg = cfg.norm_cfg
cfg.model.auxiliary_head[1].norm_cfg = cfg.norm_cfg# 模型 decode/auxiliary 输出头,指定为类别个数
cfg.model.decode_head.num_classes = NUM_CLASS
cfg.model.auxiliary_head[0]['num_classes'] = NUM_CLASS
cfg.model.auxiliary_head[1]['num_classes'] = NUM_CLASScfg.train_dataloader.batch_size = 4cfg.test_dataloader = cfg.val_dataloader# 结果保存目录
cfg.work_dir = './work_dirs/ZihaoDataset-FastSCNN'cfg.train_cfg.max_iters = 30000 # 训练迭代次数
cfg.train_cfg.val_interval = 500 # 评估模型间隔
cfg.default_hooks.logger.interval = 100 # 日志记录间隔
cfg.default_hooks.checkpoint.interval = 2500 # 模型权重保存间隔
cfg.default_hooks.checkpoint.max_keep_ckpts = 2 # 最多保留几个模型权重
cfg.default_hooks.checkpoint.save_best = 'mIoU' # 保留指标最高的模型权重# 随机数种子
cfg['randomness'] = dict(seed=0)

保存为最终的Config配置文件

cfg.dump('Zihao-Configs/ZihaoDataset_FastSCNN_20230818.py')

修改预训练模型

mmsegmentation\configs\segformer\segformer_mit-b5_8xb2-160k_ade20k-512x512.py:默认会下载预训练模型(见下面的url链接),可以手动修改为预先下载的文件

_base_ = ['./segformer_mit-b0_8xb2-160k_ade20k-512x512.py']# checkpoint = 'https://download.openmmlab.com/mmsegmentation/v0.5/pretrain/segformer/mit_b5_20220624-658746d9.pth'  # noqa
checkpoint = 'C:\\Users\\ASUS\\PycharmProjects\\pythonProject\\research\\MMSegmentation_Tutorials-main\\MMSegmentation_Tutorials-main\\20230816\\mmsegmentation\\pretrained\\mit_b5_20220624-658746d9.pth'  # noqa
# model settings
model = dict(backbone=dict(init_cfg=dict(type='Pretrained', checkpoint=checkpoint),embed_dims=64,num_heads=[1, 2, 5, 8],num_layers=[3, 6, 40, 3]),decode_head=dict(in_channels=[64, 128, 320, 512]))

训练细节

08/02 12:35:34 - mmengine - INFO - Iter(val) [11/11]    aAcc: 87.5900  mIoU: 56.0600  mAcc: 71.7300  mDice: 65.9000  mFscore: 79.0800  mPrecision: 75.2700  mRecall: 71.7300  data_time: 0.0069  time: 0.0345
08/02 12:35:47 - mmengine - INFO - Iter(train) [ 9600/10000]  lr: 1.1351e-01  eta: 0:00:50  time: 0.1238  data_time: 0.0031  memory: 864  loss: 0.0688  decode.loss_ce: 0.0305  decode.acc_seg: 92.9966  aux_0.loss_ce: 0.0163  aux_0.acc_seg: 87.6057  aux_1.loss_ce: 0.0220  aux_1.acc_seg: 87.0640
08/02 12:35:59 - mmengine - INFO - Iter(train) [ 9700/10000]  lr: 1.1344e-01  eta: 0:00:37  time: 0.1298  data_time: 0.0033  memory: 864  loss: 0.1297  decode.loss_ce: 0.0651  decode.acc_seg: 71.6496  aux_0.loss_ce: 0.0297  aux_0.acc_seg: 69.3979  aux_1.loss_ce: 0.0349  aux_1.acc_seg: 58.9588
08/02 12:36:12 - mmengine - INFO - Iter(train) [ 9800/10000]  lr: 1.1337e-01  eta: 0:00:25  time: 0.1242  data_time: 0.0031  memory: 864  loss: 0.1223  decode.loss_ce: 0.0587  decode.acc_seg: 51.1257  aux_0.loss_ce: 0.0292  aux_0.acc_seg: 53.5561  aux_1.loss_ce: 0.0345  aux_1.acc_seg: 46.3654
08/02 12:36:25 - mmengine - INFO - Iter(train) [ 9900/10000]  lr: 1.1330e-01  eta: 0:00:12  time: 0.1261  data_time: 0.0032  memory: 864  loss: 0.0845  decode.loss_ce: 0.0380  decode.acc_seg: 86.1641  aux_0.loss_ce: 0.0210  aux_0.acc_seg: 77.3401  aux_1.loss_ce: 0.0255  aux_1.acc_seg: 62.3304
08/02 12:36:37 - mmengine - INFO - Exp name: ZihaoDataset_FastSCNN_20230818_20250802_121506
08/02 12:36:37 - mmengine - INFO - Iter(train) [10000/10000]  lr: 1.1323e-01  eta: 0:00:00  time: 0.1213  data_time: 0.0031  memory: 864  loss: 0.0956  decode.loss_ce: 0.0432  decode.acc_seg: 93.6745  aux_0.loss_ce: 0.0243  aux_0.acc_seg: 90.1726  aux_1.loss_ce: 0.0281  aux_1.acc_seg: 90.2538
08/02 12:36:37 - mmengine - INFO - Saving checkpoint at 10000 iterations
08/02 12:36:38 - mmengine - INFO - per class results:
08/02 12:36:38 - mmengine - INFO - 
+------------+-------+-------+-------+--------+-----------+--------+
|   Class    |  IoU  |  Acc  |  Dice | Fscore | Precision | Recall |
+------------+-------+-------+-------+--------+-----------+--------+
| background | 85.65 | 89.88 | 92.27 | 92.27  |   94.79   | 89.88  |
|    red     |  81.3 | 98.28 | 89.69 | 89.69  |   82.47   | 98.28  |
|   green    | 59.15 | 67.73 | 74.33 | 74.33  |   82.37   | 67.73  |
|   white    | 58.04 | 69.85 | 73.45 | 73.45  |   77.44   | 69.85  |
| seed-black | 61.43 | 78.07 | 76.11 | 76.11  |   74.24   | 78.07  |
| seed-white |  0.0  |  0.0  |  0.0  |  nan   |    nan    |  0.0   |
+------------+-------+-------+-------+--------+-----------+--------+
08/02 12:36:38 - mmengine - INFO - Iter(val) [11/11]    aAcc: 88.9900  mIoU: 57.5900  mAcc: 67.3000  mDice: 67.6400  mFscore: 81.1700  mPrecision: 82.2600  mRecall: 67.3000  data_time: 0.0075  time: 0.0340

可视化数据mmsegmentation\work_dirs\ZihaoDataset-FastSCNN\20250802_121506\vis_data

vis_data目录下的log_path = './work_dirs/ZihaoDataset-FastSCNN/20250802_121506/vis_data/scalars.json'的文件,用于记录整体各种指标的记录情况。

with open(log_path, "r") as f:json_list = f.readlines()eval(json_list[4])

输出结果如下:

{'lr': 0.11973086417099389,'data_time': 0.004000043869018555,'loss': 0.1377907693386078,'decode.loss_ce': 0.07181963995099068,'decode.acc_seg': 88.35430145263672,'aux_0.loss_ce': 0.032481906749308107,'aux_0.acc_seg': 85.88199615478516,'aux_1.loss_ce': 0.03348922152072191,'aux_1.acc_seg': 81.13632202148438,'time': 0.12697319984436034,'iter': 400,'memory': 863,'step': 400}

针对每一个类别的各种指标可视化
存储在log文件中:work_dirs/ZihaoDataset-FastSCNN/20250802_121506/20250802_121506.log
我们要读取的就是这种格式的指标:

+------------+-------+-------+-------+--------+-----------+--------+
|   Class    |  IoU  |  Acc  |  Dice | Fscore | Precision | Recall |
+------------+-------+-------+-------+--------+-----------+--------+
| background | 85.65 | 89.88 | 92.27 | 92.27  |   94.79   | 89.88  |
|    red     |  81.3 | 98.28 | 89.69 | 89.69  |   82.47   | 98.28  |
|   green    | 59.15 | 67.73 | 74.33 | 74.33  |   82.37   | 67.73  |
|   white    | 58.04 | 69.85 | 73.45 | 73.45  |   77.44   | 69.85  |
| seed-black | 61.43 | 78.07 | 76.11 | 76.11  |   74.24   | 78.07  |
| seed-white |  0.0  |  0.0  |  0.0  |  nan   |    nan    |  0.0   |
+------------+-------+-------+-------+--------+-----------+--------+

pth权重保存路径mmsegmentation\work_dirs\ZihaoDataset-FastSCNN

我将这个pth文件移动到mmsegmentation\pretrained\ZihaoDataset_FastSCNN_20230818.pth这个路径下

测试方法

最终config配置文件+模型的权重文件

python tools/test.py Zihao-Configs/ZihaoDataset_FastSCNN_20230818.py pretrained/ZihaoDataset_FastSCNN_20230818.pth

默认保存路径mmsegmentation\work_dirs\ZihaoDataset-FastSCNN\20250802_134015与训练的保存目录一致

推理

使用合并后的config配置文件和权重

载入模型

# 模型 config 配置文件
config_file = 'Zihao-Configs/ZihaoDataset_FastSCNN_20230818.py'
# 模型 checkpoint 权重文件
checkpoint_file = 'pretrained/ZihaoDataset_FastSCNN_20230818.pth'
# device = 'cpu'
device = 'cuda:0'
model = init_model(config_file, checkpoint_file, device=device)

推理过程

result = inference_model(model, img_bgr),好像要用BGR格式的图片进行推理?返回一个result,SegDataSample类型,分为两个东西,一个是预测的类别,一个是概率,其余就是tensor的使用方法

result = inference_model(model, img_bgr)
result.keys()  ['pred_sem_seg', 'seg_logits']
pred_mask = result.pred_sem_seg.data[0].cpu().numpy()
pred_mask.shape (1280, 1280)
result.seg_logits.data.shape torch.Size([6, 1280, 1280])

批量推理

其实就是将每个图像都预测一下,然后与掩码矩阵叠加一下,保存到输出文件夹下

def process_single_img(img_path, save=False):img_bgr = cv2.imread(img_path)# 语义分割预测result = inference_model(model, img_bgr)pred_mask = result.pred_sem_seg.data[0].cpu().numpy()# 将预测的整数ID,映射为对应类别的颜色pred_mask_bgr = np.zeros((pred_mask.shape[0], pred_mask.shape[1], 3))for idx in palette_dict.keys():pred_mask_bgr[np.where(pred_mask==idx)] = palette_dict[idx]pred_mask_bgr = pred_mask_bgr.astype('uint8')# 将语义分割预测图和原图叠加显示pred_viz = cv2.addWeighted(img_bgr, opacity, pred_mask_bgr, 1-opacity, 0)# 保存图像至 outputs/testset-pred 目录if save:save_path = os.path.join('../','../','../','outputs', 'testset-pred', 'pred-'+img_path.split('/')[-1])cv2.imwrite(save_path, pred_viz)

摄像头推理(实时分割)

但是我没有摄像头😒

python demo/video_demo.py 0 Zihao-Configs/ZihaoDataset_FastSCNN_20230818.py pretrained/ZihaoDataset_FastSCNN_20230818.pth --device cuda:0 --opacity 0.5 --show

可视化

官方提供的可视化分割图片的代码

根据在Dataset中定义METAINFO来绘制掩码矩阵的,最后返回处理好的图片

 METAINFO = {'classes':['background', 'red', 'green', 'white', 'seed-black', 'seed-white'],'palette':[[127,127,127], [200,0,0], [0,200,0], [144,238,144], [30,30,30], [251,189,8]]}
from mmseg.apis import show_result_pyplot
img_viz = show_result_pyplot(model, img_path, result, opacity=0.8, title='MMSeg', out_file='outputs/K1-4.jpg')
plt.figure(figsize=(14, 8))
plt.imshow(img_viz)
plt.show()

批量可视化代码:用于获得n行n列的图像

不用记忆

# n 行 n 列可视化
n = 4fig, axes = plt.subplots(nrows=n, ncols=n, figsize=(16, 10))for i, file_name in enumerate(os.listdir()[:n**2]):img_bgr = cv2.imread(file_name)# 可视化axes[i//n, i%n].imshow(img_bgr[:,:,::-1])axes[i//n, i%n].axis('off') # 关闭坐标轴显示
fig.suptitle('Semantic Segmentation Predictions', fontsize=30)
# plt.tight_layout()
plt.savefig('../K3.jpg')
plt.show()

在这里插入图片描述







数据集的存储要求(待续)

整数掩码/掩膜

  • 存储格式必须是png,目的是为了无损
    在这里插入图片描述
    像素太小,什么都看不出来。

在这里插入图片描述

虽然掩码是一个整数矩阵,但是保存为png格式时,必须存储3通道

img.shape
mask.shape
(300, 440, 3)
(300, 440, 3)

整数掩码转换为RGB通道可视化
取图像的任一一个通道,关键是使用np.where()

mask = mask[:,:,0]# 将整数ID,映射为对应类别的颜色
viz_mask_bgr = np.zeros((mask.shape[0], mask.shape[1], 3))
for idx in palette_dict.keys():viz_mask_bgr[np.where(mask==idx)] = palette_dict[idx]
viz_mask_bgr = viz_mask_bgr.astype('uint8')# 将语义分割标注图和原图叠加显示
opacity = 0.1 # 透明度越大,可视化效果越接近原图
label_viz = cv2.addWeighted(img, opacity, viz_mask_bgr, 1-opacity, 0)

在这里插入图片描述

opencv的注意事项

注意opencv载入图片是bgr格式,要进行一个转换img_bgr[:,:,::-1]

img_bgr = cv2.imread(img_path)

在这里插入图片描述
在这里插入图片描述




参考文献

同济子豪兄

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

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

相关文章

InfluxDB 与 Node.js 框架:Express 集成方案(二)

四、优化与注意事项 (一)性能优化技巧 连接池管理:使用连接池可以有效减少创建和销毁数据库连接的开销。在 Node.js 中,可以借助influx模块结合第三方连接池库,如generic-pool来实现连接池的管理 。通过设置连接池的…

单位长度上的RC参数

1inch1000mil25.4mm2.54cm 使用SI9000计算导线上电容电感参数并使用Q2D进行仿真验证。使用SI9000建立一个阻抗为50欧的微带线模型,后对该模型进行1GHz频域计算 通过计算得到结果,可知1GHz频率下单位传输线上的RLGC参数使用SI9000计算好单位长度上的RLGC参…

基于Dockerfile 部署一个 Flask 应用

Docker 与 Python:容器化部署应用,实现快速发布与弹性伸缩 以下是一个简单的 Flask 应用 # app.py - 一个简单的Flask应用 from flask import Flask import osapp Flask(__name__)app.route("/") def hello():env os.environ.get(FLASK_ENV,…

DFT设计中的不同阶段介绍

在DFT(Design for Test,可测试性设计)软件开发中,针对设计检测的完整流程通常包含Setup(设置)、Analysis(分析)、Insertion(插入)和Verification(…

自动化测试准备工作:概念篇

自动化 什么是自动化? 超市的自动闸门,不需要手动的开门关门生活中的自动动化案例有效的减少了人力的消耗,同时也提高了生活的质量。 软件自动化测试同理,通过编写自动化测试程序(减少人力和时间的消耗,提高软件的…

每日主题切换网页:用纯前端技术打造随心情变化的动态界面

🎨 每日主题切换网页:用纯前端技术打造随心情变化的动态界面 项目地址:https://github.com/hhse/daily-theme-switcher 在线演示:https://hhse.github.io/daily-theme-switcher 这里写目录标题🎨 每日主题切换网页&…

TOPSIS(Technique for Order Preference by Similarity to Ideal Solution )简介与简单示例

前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…

uniapp 富文本rich-text 文本首行缩进和图片居中

1. uniapp 富文本rich-text 文本首行缩进和图片居中 1.1. rich-text 文本首行缩进使用 rich-text 组件渲染html格式的代码,常常因为不能自定义css导致文本不能缩进,以及图片不能居中等问题,这里可以考虑使用js的replace方法,替换…

Apple基础(Xcode③-Singbox Core)

brew install go open ~/.bash_profile export PATH="$PATH:$(go env GOPATH)/bin" 先确保工具链完整 go install github.com/sagernet/gomobile/cmd/gomobile@v0.1.4 go install github.com/sagernet/gomobile/cmd/gobind@v0.1.4 gomobile init -v # 关键:-v …

JVM学习日记(十四)Day14——性能监控与调优(一)

经过前几篇的铺垫,现在开始正式进入调优篇,也是大火实际用的到的和感兴趣的,但是前期的知识积累还是有必要的,所以还对JVM基础没什么了解的,建议还是回看主包的前几篇内容,当然看其他优秀的博主也是可以的。…

使用 Elasticsearch 和 AI 构建智能重复项检测

作者:来自 Elastic Dayananda Srinivas 探索组织如何利用 Elasticsearch 检测和处理贷款或保险申请中的重复项。 Elasticsearch 带来了大量新功能,帮助你为你的使用场景构建最佳搜索方案。深入了解我们的示例 notebooks,开始免费云试用&#…

如何在不依赖 Office 的情况下转换 PDF 为可编辑文档

在日常工作里,我们经常需要处理各种文件格式的转换问题,像Word转PDF或者PDF转Excel这样的需求屡见不鲜。它是一款功能全面的PDF转换工具,能够帮助你轻松应对多种文档处理任务。不仅能够实现PDF与其他格式之间的转换,如Word、Excel…

嵌入式学习笔记-MCU阶段--DAY09

1. oled屏幕的接口IIC应用场合:2.IIC通信原理概念:IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司…

解决 Node.js 托管 React 静态资源的跨域问题

在 Node.js 项目中托管 React 打包后的静态资源时,可能会遇到跨域问题(CORS)。以下是几种解决方案: 1. 使用 Express 中间件设置 CORS 头 const express require(express); const path require(path); const app express();// …

【Linux】多路转接之epoll

优化poll进行拷贝的开销poll开销过大将整个 pollfd 数组拷贝到内核态,以便内核检查 fd 是否就绪(从用户态 → 内核态)。内核检查 fd 状态,并填充 revents。将 pollfd 数组从内核态拷贝回用户态,让应用程序可以读取 rev…

下载一个JeecgBoot-master项目 导入idea需要什么操作启动项目

官网:开发环境搭建 | JEECG 文档中心 一般做开发的电脑里都是有的,没有的只能下载了 前端安装 node官网:https://nodejs.org/zh-cnpnpm安装:通过命令 后端安装: jdk17 :https://www.oracle.com/cn/java/technologies/downloads/#java17maven :https://m…

解决 InputStream 只能读取一次问题

是的,InputStream 的一个重要特性是它通常只能被读取一次。这是因为:输入流通常是单向的、顺序访问的数据源很多流(如网络流、文件流)读取后指针就移动了,无法回退有些流(如Socket流)甚至读取后…

数据分析面试题

技都测试 1、请列举5个 Excel 中常用的函数及写法。[ if ] IF(A1>60, "及格", "不及格") —— 若 A1 单元格数值≥60,返回 “及格”,否则返回 “不及格”。IF(B2>100, B2*0.8, B2) —— 若 B2 数值 > 100&#xff0c…

【07】VisionMaster入门到精通——Blob分折

文章目录0 视屏讲解与演示1 案例演示2 参数详解1 运行参数0 视屏讲解与演示 1 案例演示 周长使能查找U型槽 短轴使能查找U型槽 面积筛选区域 当条件不符合是,该模块显示红色,状态为NG 显示二值图像 显示Blob图像 2 参数详解 Blob分折,…

解释 MySQL 中的 EXPLAIN 命令的作用和使用场景

解释 MySQL 中的 EXPLAIN 命令的作用和使用场景 总结性回答 EXPLAIN 是 MySQL 中用于分析 SQL 查询执行计划的命令,它能展示 MySQL 如何执行一个查询,包括使用的索引、表连接顺序、扫描行数等关键信息。主要用于查询性能优化,帮助开发者识别潜…