diff --git a/SegFormer/demo/class_names.py b/SegFormer/demo/class_names.py index f78f1f5..49c929b 100644 --- a/SegFormer/demo/class_names.py +++ b/SegFormer/demo/class_names.py @@ -120,7 +120,7 @@ def voc_palette(): def msd_palette(): """MSD palette for external use.""" - return [[128, 128, 128], [0, 64, 0]] + return [[75, 0, 130], [255, 255, 0]] dataset_aliases = { diff --git a/SegFormer/demo/image_demo.py b/SegFormer/demo/image_demo.py index 2e8d29d..6ee51a0 100755 --- a/SegFormer/demo/image_demo.py +++ b/SegFormer/demo/image_demo.py @@ -1,7 +1,41 @@ from argparse import ArgumentParser - -from mmseg.apis import inference_segmentor, init_segmentor, show_result_pyplot +import matplotlib.pyplot as plt +from glob import glob +import mmcv +from mmseg.apis import inference_segmentor, init_segmentor from class_names import get_palette +from imageio import imread +import matplotlib.cm as cm +my_cmap = cm.Reds +my_cmap.set_under('k', alpha=0) + + +def show_result_pyplot(model, img, result, palette=None, fig_size=(15, 10), train_or_test='train'): + """Visualize the segmentation results on the image. + + Args: + model (nn.Module): The loaded segmentor. + img (str or np.ndarray): Image filename or loaded image. + result (list): The segmentation result. + palette (list[list[int]]] | None): The palette of segmentation + map. If None is given, random palette will be generated. + Default: None + fig_size (tuple): Figure size of the pyplot figure. + train_or_test (str): 'train' or 'test'. + """ + + if hasattr(model, 'module'): + model = model.module + img = model.show_result(img, result, palette=palette, show=False) + plt.figure(figsize=fig_size) + fig, ax = plt.subplots(1, 1, figsize=fig_size) + ax.imshow(mmcv.bgr2rgb(img), alpha=1.0) + if train_or_test == 'train': + img_annot = img.replace("images", "annotations") + img_annot = imread(img_annot) + ax.imshow(img_annot, cmap=my_cmap, interpolation='none', + clim=[0.9, 1], alpha=.4) + plt.show() def main(): @@ -9,6 +43,8 @@ def main(): parser.add_argument('img', help='Image file') parser.add_argument('config', help='Config file') parser.add_argument('checkpoint', help='Checkpoint file') + parser.add_argument('--num', help='Number of images to show', type=int) + parser.add_argument('--train_or_test', help='Number of images to show', default='train', type=str) parser.add_argument( '--device', default='cuda:0', help='Device used for inference') parser.add_argument( @@ -19,10 +55,12 @@ def main(): # build the model from a config file and a checkpoint file model = init_segmentor(args.config, args.checkpoint, device=args.device) - # test a single image - result = inference_segmentor(model, args.img) - # show the results - show_result_pyplot(model, args.img, result, get_palette(args.palette)) + for img in glob(f'{args.img}/*.png')[:args.num]: + print("Plotting: ", img) + # test a single image + result = inference_segmentor(model, img) + # show the results + show_result_pyplot(model, img, result, get_palette(args.palette), args.train_or_test) if __name__ == '__main__': diff --git a/SegFormer/local_configs/_base_/datasets/msd_balanced.py b/SegFormer/local_configs/_base_/datasets/msd_balanced.py new file mode 100755 index 0000000..40d92c7 --- /dev/null +++ b/SegFormer/local_configs/_base_/datasets/msd_balanced.py @@ -0,0 +1,67 @@ +# dataset settings +dataset_type = 'MSDBalancedDataset' +data_root = 'data/MSD/Task09_Spleen_RGB_2D_512_Balanced' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +crop_size = (512, 512) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations'), + dict(type='Resize', img_scale=(512, 512), ratio_range=(0.5, 2.0)), + dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), + dict(type='RandomFlip', prob=0.5), + dict(type='PhotoMetricDistortion'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_semantic_seg']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(512, 512), + # img_ratios=[0.5, 0.75, 1.0, 1.25, 1.5, 1.75], + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + data_root='../../data/MSD/Task09_Spleen_RGB_2D_512_Balanced', + img_dir='images/training', + ann_dir='annotations/training', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + data_root='../../data/MSD/Task09_Spleen_RGB_2D_512_Balanced', + img_dir='images/training', + ann_dir='annotations/training', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + data_root='../../data/MSD/Task09_Spleen_RGB_2D_512_Balanced', + img_dir='images/training', + ann_dir='annotations/training', + pipeline=test_pipeline) + # val=dict( + # type=dataset_type, + # data_root='../../data/MSD/Task09_Spleen_RGB_2D_512_Balanced', + # img_dir='images/validation', + # ann_dir='annotations/validation', + # pipeline=test_pipeline), + # test=dict( + # type=dataset_type, + # data_root='../../data/MSD/Task09_Spleen_RGB_2D_512_Balanced', + # img_dir='images/validation', + # ann_dir='annotations/validation', + # pipeline=test_pipeline) +) diff --git a/SegFormer/local_configs/segformer/MSD/segformer.512x512.msd_balanced.20k.py b/SegFormer/local_configs/segformer/MSD/segformer.512x512.msd_balanced.20k.py new file mode 100644 index 0000000..7d48879 --- /dev/null +++ b/SegFormer/local_configs/segformer/MSD/segformer.512x512.msd_balanced.20k.py @@ -0,0 +1,47 @@ +_base_ = [ + '../../_base_/models/segformer.py', + '../../_base_/datasets/msd_balanced.py', + '../../_base_/default_runtime.py', + '../../_base_/schedules/schedule_20k.py' +] + +# model settings +norm_cfg = dict(type='SyncBN', requires_grad=True) +find_unused_parameters = True +model = dict( + type='EncoderDecoder', + pretrained='../../pretrained/ImageNet-1K/mit_b0.pth', + backbone=dict( + type='mit_b0', + style='pytorch'), + decode_head=dict( + type='SegFormerHead', + in_channels=[32, 64, 160, 256], + in_index=[0, 1, 2, 3], + feature_strides=[4, 8, 16, 32], + channels=128, + dropout_ratio=0.1, + num_classes=150, + norm_cfg=norm_cfg, + align_corners=False, + decoder_params=dict(embed_dim=256), + loss_decode=dict(type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)), + # model training and testing settings + train_cfg=dict(), + test_cfg=dict(mode='whole')) + +# optimizer +optimizer = dict(_delete_=True, type='AdamW', lr=0.00006, betas=(0.9, 0.999), weight_decay=0.01, + paramwise_cfg=dict(custom_keys={'pos_block': dict(decay_mult=0.), + 'norm': dict(decay_mult=0.), + 'head': dict(lr_mult=10.) + })) + +lr_config = dict(_delete_=True, policy='poly', + warmup='linear', + warmup_iters=1500, + warmup_ratio=1e-6, + power=1.0, min_lr=0.0, by_epoch=False) + +data = dict(samples_per_gpu=2) +evaluation = dict(interval=16000, metric='mIoU') diff --git a/SegFormer/mmseg/datasets/__init__.py b/SegFormer/mmseg/datasets/__init__.py index c211a10..053b3d6 100755 --- a/SegFormer/mmseg/datasets/__init__.py +++ b/SegFormer/mmseg/datasets/__init__.py @@ -1,6 +1,7 @@ from .ade import ADE20KDataset from .msd import MSDDataset from .msd_marked import MSDMarkedDataset +from .msd_balanced import MSDBalancedDataset from .builder import DATASETS, PIPELINES, build_dataloader, build_dataset from .chase_db1 import ChaseDB1Dataset from .cityscapes import CityscapesDataset @@ -19,5 +20,5 @@ 'DATASETS', 'build_dataset', 'PIPELINES', 'CityscapesDataset', 'PascalVOCDataset', 'ADE20KDataset', 'PascalContextDataset', 'ChaseDB1Dataset', 'DRIVEDataset', 'HRFDataset', 'STAREDataset', 'MapillaryDataset', 'CocoStuff', - 'MSDDataset', 'MSDMarkedDataset' + 'MSDDataset', 'MSDMarkedDataset', 'MSDBalancedDataset' ] diff --git a/SegFormer/mmseg/datasets/msd_balanced.py b/SegFormer/mmseg/datasets/msd_balanced.py new file mode 100755 index 0000000..f1a898d --- /dev/null +++ b/SegFormer/mmseg/datasets/msd_balanced.py @@ -0,0 +1,24 @@ +from .builder import DATASETS +from .custom import CustomDataset + + +@DATASETS.register_module() +class MSDBalancedDataset(CustomDataset): + """ADE20K dataset. + + In segmentation map annotation for ADE20K, 0 stands for background, which + is not included in 150 categories. ``reduce_zero_label`` is fixed to True. + The ``img_suffix`` is fixed to '.jpg' and ``seg_map_suffix`` is fixed to + '.png'. + """ + CLASSES = ( + "no ailment", "ailment") + + PALETTE = [[120, 120, 120], [92, 0, 255]] + + def __init__(self, **kwargs): + super(MSDBalancedDataset, self).__init__( + img_suffix='.png', + seg_map_suffix='.png', + reduce_zero_label=True, + **kwargs) diff --git a/data/MSD/Task09_Spleen/dataset.json b/data/MSD/Task09_Spleen/dataset.json deleted file mode 100644 index c8ce865..0000000 --- a/data/MSD/Task09_Spleen/dataset.json +++ /dev/null @@ -1,22 +0,0 @@ -{ -"name": "Spleen", -"description": "Spleen Segmentation", -"reference": "Memorial Sloan Kettering Cancer Center", -"licence":"CC-BY-SA 4.0", -"release":"1.0 06/08/2018", -"tensorImageSize": "3D", -"modality": { - "0": "CT" - }, - "labels": { - "0": "background", - "1": "spleen" - }, - "numTraining": 41, - "numTest": 20, - "training":[{"image":"./imagesTr/spleen_19.nii.gz","label":"./labelsTr/spleen_19.nii.gz"},{"image":"./imagesTr/spleen_31.nii.gz","label":"./labelsTr/spleen_31.nii.gz"},{"image":"./imagesTr/spleen_52.nii.gz","label":"./labelsTr/spleen_52.nii.gz"},{"image":"./imagesTr/spleen_40.nii.gz","label":"./labelsTr/spleen_40.nii.gz"},{"image":"./imagesTr/spleen_3.nii.gz","label":"./labelsTr/spleen_3.nii.gz"},{"image":"./imagesTr/spleen_17.nii.gz","label":"./labelsTr/spleen_17.nii.gz"},{"image":"./imagesTr/spleen_21.nii.gz","label":"./labelsTr/spleen_21.nii.gz"},{"image":"./imagesTr/spleen_33.nii.gz","label":"./labelsTr/spleen_33.nii.gz"},{"image":"./imagesTr/spleen_9.nii.gz","label":"./labelsTr/spleen_9.nii.gz"},{"image":"./imagesTr/spleen_29.nii.gz","label":"./labelsTr/spleen_29.nii.gz"},{"image":"./imagesTr/spleen_46.nii.gz","label":"./labelsTr/spleen_46.nii.gz"},{"image":"./imagesTr/spleen_25.nii.gz","label":"./labelsTr/spleen_25.nii.gz"},{"image":"./imagesTr/spleen_13.nii.gz","label":"./labelsTr/spleen_13.nii.gz"},{"image":"./imagesTr/spleen_62.nii.gz","label":"./labelsTr/spleen_62.nii.gz"},{"image":"./imagesTr/spleen_27.nii.gz","label":"./labelsTr/spleen_27.nii.gz"},{"image":"./imagesTr/spleen_44.nii.gz","label":"./labelsTr/spleen_44.nii.gz"},{"image":"./imagesTr/spleen_56.nii.gz","label":"./labelsTr/spleen_56.nii.gz"},{"image":"./imagesTr/spleen_60.nii.gz","label":"./labelsTr/spleen_60.nii.gz"},{"image":"./imagesTr/spleen_2.nii.gz","label":"./labelsTr/spleen_2.nii.gz"},{"image":"./imagesTr/spleen_53.nii.gz","label":"./labelsTr/spleen_53.nii.gz"},{"image":"./imagesTr/spleen_41.nii.gz","label":"./labelsTr/spleen_41.nii.gz"},{"image":"./imagesTr/spleen_22.nii.gz","label":"./labelsTr/spleen_22.nii.gz"},{"image":"./imagesTr/spleen_14.nii.gz","label":"./labelsTr/spleen_14.nii.gz"},{"image":"./imagesTr/spleen_18.nii.gz","label":"./labelsTr/spleen_18.nii.gz"},{"image":"./imagesTr/spleen_20.nii.gz","label":"./labelsTr/spleen_20.nii.gz"},{"image":"./imagesTr/spleen_32.nii.gz","label":"./labelsTr/spleen_32.nii.gz"},{"image":"./imagesTr/spleen_16.nii.gz","label":"./labelsTr/spleen_16.nii.gz"},{"image":"./imagesTr/spleen_12.nii.gz","label":"./labelsTr/spleen_12.nii.gz"},{"image":"./imagesTr/spleen_63.nii.gz","label":"./labelsTr/spleen_63.nii.gz"},{"image":"./imagesTr/spleen_28.nii.gz","label":"./labelsTr/spleen_28.nii.gz"},{"image":"./imagesTr/spleen_24.nii.gz","label":"./labelsTr/spleen_24.nii.gz"},{"image":"./imagesTr/spleen_59.nii.gz","label":"./labelsTr/spleen_59.nii.gz"},{"image":"./imagesTr/spleen_47.nii.gz","label":"./labelsTr/spleen_47.nii.gz"},{"image":"./imagesTr/spleen_8.nii.gz","label":"./labelsTr/spleen_8.nii.gz"},{"image":"./imagesTr/spleen_6.nii.gz","label":"./labelsTr/spleen_6.nii.gz"},{"image":"./imagesTr/spleen_61.nii.gz","label":"./labelsTr/spleen_61.nii.gz"},{"image":"./imagesTr/spleen_10.nii.gz","label":"./labelsTr/spleen_10.nii.gz"},{"image":"./imagesTr/spleen_38.nii.gz","label":"./labelsTr/spleen_38.nii.gz"},{"image":"./imagesTr/spleen_45.nii.gz","label":"./labelsTr/spleen_45.nii.gz"},{"image":"./imagesTr/spleen_26.nii.gz","label":"./labelsTr/spleen_26.nii.gz"},{"image":"./imagesTr/spleen_49.nii.gz","label":"./labelsTr/spleen_49.nii.gz"}], - "test":["./imagesTs/spleen_15.nii.gz","./imagesTs/spleen_23.nii.gz","./imagesTs/spleen_1.nii.gz","./imagesTs/spleen_42.nii.gz","./imagesTs/spleen_50.nii.gz","./imagesTs/spleen_54.nii.gz","./imagesTs/spleen_37.nii.gz","./imagesTs/spleen_58.nii.gz","./imagesTs/spleen_39.nii.gz","./imagesTs/spleen_48.nii.gz","./imagesTs/spleen_35.nii.gz","./imagesTs/spleen_11.nii.gz","./imagesTs/spleen_7.nii.gz","./imagesTs/spleen_30.nii.gz","./imagesTs/spleen_43.nii.gz","./imagesTs/spleen_51.nii.gz","./imagesTs/spleen_36.nii.gz","./imagesTs/spleen_55.nii.gz","./imagesTs/spleen_57.nii.gz","./imagesTs/spleen_34.nii.gz"] - } - - - diff --git a/models/20220515_165920.log.json b/models/20220515_165920.log.json deleted file mode 100644 index 11e4a72..0000000 --- a/models/20220515_165920.log.json +++ /dev/null @@ -1 +0,0 @@ -{"env_info": "sys.platform: linux\nPython: 3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:04:18) [GCC 10.3.0]\nCUDA available: True\nGPU 0: Tesla T4\nCUDA_HOME: /usr/local/cuda\nNVCC: Build cuda_11.7.r11.7/compiler.31294372_0\nGCC: gcc (Debian 8.3.0-6) 8.3.0\nPyTorch: 1.7.0\nPyTorch compiling details: PyTorch built with:\n - GCC 7.3\n - C++ Version: 201402\n - Intel(R) oneAPI Math Kernel Library Version 2021.4-Product Build 20210904 for Intel(R) 64 architecture applications\n - Intel(R) MKL-DNN v1.6.0 (Git Hash 5ef631a030a6f73131c77892041042805a06064f)\n - OpenMP 201511 (a.k.a. OpenMP 4.5)\n - NNPACK is enabled\n - CPU capability usage: AVX2\n - CUDA Runtime 10.2\n - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_61,code=sm_61;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_37,code=compute_37\n - CuDNN 7.6.5\n - Magma 2.5.2\n - Build settings: BLAS=MKL, BUILD_TYPE=Release, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DUSE_VULKAN_WRAPPER -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, USE_CUDA=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, \n\nTorchVision: 0.8.0\nOpenCV: 4.5.1\nMMCV: 1.3.0\nMMCV Compiler: GCC 7.3\nMMCV CUDA Compiler: 11.0\nMMSegmentation: 0.11.0+", "seed": null, "exp_name": "segformer.b1.512x512.ade.160k.py"} diff --git a/models/20220515_170407.log.json b/models/20220515_170407.log.json deleted file mode 100644 index c271494..0000000 --- a/models/20220515_170407.log.json +++ /dev/null @@ -1,6 +0,0 @@ -{"env_info": "sys.platform: linux\nPython: 3.8.13 | packaged by conda-forge | (default, Mar 25 2022, 06:04:18) [GCC 10.3.0]\nCUDA available: True\nGPU 0: Tesla T4\nCUDA_HOME: usr/local/cuda\nGCC: gcc (Debian 8.3.0-6) 8.3.0\nPyTorch: 1.7.0\nPyTorch compiling details: PyTorch built with:\n - GCC 7.3\n - C++ Version: 201402\n - Intel(R) oneAPI Math Kernel Library Version 2021.4-Product Build 20210904 for Intel(R) 64 architecture applications\n - Intel(R) MKL-DNN v1.6.0 (Git Hash 5ef631a030a6f73131c77892041042805a06064f)\n - OpenMP 201511 (a.k.a. OpenMP 4.5)\n - NNPACK is enabled\n - CPU capability usage: AVX2\n - CUDA Runtime 10.2\n - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_61,code=sm_61;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_37,code=compute_37\n - CuDNN 7.6.5\n - Magma 2.5.2\n - Build settings: BLAS=MKL, BUILD_TYPE=Release, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DUSE_VULKAN_WRAPPER -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, USE_CUDA=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, \n\nTorchVision: 0.8.0\nOpenCV: 4.5.1\nMMCV: 1.3.0\nMMCV Compiler: GCC 7.3\nMMCV CUDA Compiler: 11.0\nMMSegmentation: 0.11.0+", "seed": null, "exp_name": "segformer.b1.512x512.ade.160k.py"} -{"mode": "train", "epoch": 1, "iter": 50, "lr": 0.0, "memory": 6463, "data_time": 0.00425, "decode.loss_seg": 4.00595, "decode.acc_seg": 0.3562, "loss": 4.00595, "time": 0.27083} -{"mode": "train", "epoch": 1, "iter": 100, "lr": 0.0, "memory": 6463, "data_time": 0.00232, "decode.loss_seg": 3.96242, "decode.acc_seg": 1.89888, "loss": 3.96242, "time": 0.24262} -{"mode": "train", "epoch": 1, "iter": 150, "lr": 1e-05, "memory": 6463, "data_time": 0.00263, "decode.loss_seg": 3.9038, "decode.acc_seg": 9.5145, "loss": 3.9038, "time": 0.24269} -{"mode": "train", "epoch": 1, "iter": 200, "lr": 1e-05, "memory": 6463, "data_time": 0.00254, "decode.loss_seg": 3.54471, "decode.acc_seg": 20.88363, "loss": 3.54471, "time": 0.24335} -{"mode": "train", "epoch": 1, "iter": 250, "lr": 1e-05, "memory": 6463, "data_time": 0.00237, "decode.loss_seg": 3.22963, "decode.acc_seg": 21.13161, "loss": 3.22963, "time": 0.23734}