文章目录

  • 1.MedPy简介
  • 2.MedPy安装
  • 3.MedPy常用函数
    • 3.1 `medpy.io.load(image)`
    • 3.2 `medpy.metric.binary.dc(result, reference)`
    • 3.3 `medpy.metric.binary.jc(result, reference)`
    • 3.4 `medpy.metric.binary.hd(result,reference,voxelspacing=None,connectivity=1,)`
    • 3.5 `medpy.metric.binary.hd95(result,reference,voxelspacing=None,connectivity=1,)`
    • 3.6 `medpy.metric.binary.recall(result, reference)`
    • 3.7 `medpy.metric.binary.sensitivity(result, reference)`
    • 3.8`medpy.metric.binary.true_positive_rate(result, reference)`
    • 3.9`medpy.metric.binary.specificity(result, reference)`
    • 3.10`medpy.metric.binary.true_negative_rate(result, reference)`
    • 3.11`medpy.metric.binary.precision(result, reference)`
    • 3.12 `medpy.metric.binary.positive_predictive_value(result, reference)`
    • 3.13 `medpy.io.save(arr, filename, hdr=False, force=True, use_compression=False)`
  • 4.参考文献

1.MedPy简介

MedPy 是一个图像处理库和针对医学(如高维)图像处理的脚本集合,此处主要讨论利用该库计算常见的医学图像分割任务评价指标,如Dice、Jaccard、Hausdorff Distance、Sensitivity、Specificity、Positive predictive value等。

论文表格的表头一般使用评价指标的英文全称首字母大写简写,如PPV代表阳性预测值,故此处也给出。

  • Dice相似系数(Dice Similarity Coefficient,DSC)或Dice系数(Dice Coefficient,DC)

    也称为索伦森-骰子系数是用于衡量两个样本相似性的统计量。它是由植物学家Thorvald Sørensen和Lee Raymond Dice独立开发的,他们分别于1948年和1945年发表。是最常用的一项评价指标,用于有效衡量分割算法预测标签与真实标注标签的空间重叠程度,其对应值越大表示分割精度越高。该指标最初应用于离散数据,给定两个集合A 和B,则定义为两个集合共有的元素数除以每个集合中元素数之和的两倍
    DSC=2∣A∩B∣∣A∣+∣B∣DSC=\frac{2|A\cap B|}{|A|+|B|} DSC=∣A∣+∣B∣2∣A∩B∣​
    其中,∣A∣|A|∣A∣和∣B∣|B|∣B∣是两个集合的基数(即每个集合中的元素数)

    当应用于布尔数据时,使用真阳性 (TP)、假阳性(FP) 和假阴性(FN) 的定义,它可以写为
    DSC=2TP2TP+FP+FND S C=\frac{2 T P}{2 T P+F P+F N} DSC=2TP+FP+FN2TP​

  • Jaccard相似系数(Jaccard Similarity Coefficient,JSC)或Jaccard系数(Jaccard Coefficient,JC)

    与 Dice 相似系数指标相似,也是一种衡量两幅图像相似程度的指标,其由实际分割结果与真实标签的交集同二者并集的比值得出,反映了分割方法的准确程度,其值越高,分割结果越准确。设TP表示正确预测为正例的数量,FP表示错误预测为正例的数量,FN表示错误预测为反例的数量,则定义为

    Jaccard=TPTP+FP+FN\text { Jaccard}=\frac{T P}{T P+F P+F N}  Jaccard=TP+FP+FNTP​

  • 豪斯多夫距离(Hausdorff distance,HD)

    表示预测分割区域边界与真实肿瘤区域边界之间的最大距离,其值越小代表脑肿瘤边界分割误差越小、质量越好。设 XY 是度量空间(M,d)(M,d)(M,d)的两个非空子集,则定义他们的Hausdorff distance dH(X,Y)d_H(X,Y)dH​(X,Y)为
    dH(X,Y)=max⁡{dXY,dYX}=max⁡{max⁡x∈Xmin⁡y∈Yd(x,y),max⁡y∈Ymin⁡x∈Xd(x,y)}d_H(X, Y)=\max \left\{d_{X Y}, d_{Y X}\right\}=\max \left\{\max _{x \in X} \min_{y \in Y}d(x, y), \max _{y \in Y} \min _{x \in X} d(x, y)\right\} dH​(X,Y)=max{dXY​,dYX​}=max{x∈Xmax​y∈Ymin​d(x,y),y∈Ymax​x∈Xmin​d(x,y)}
    计算绿色曲线 X 和蓝色曲线 Y 之间的豪斯多夫距离的分量过程如下图所示。

    首先,对点集X中的每一个点xxx计算其到点集Y中的每一个点yyy的距离,保留最短距离inf⁡x∈Xd(x,y)\inf_{x \in X}d(x,y)infx∈X​d(x,y),然后找出保留的最短距离中的最大距离sup⁡y∈Yinf⁡x∈Xd(x,y)\sup_{y \in Y}{\inf_{x \in X}d(x,y)}supy∈Y​infx∈X​d(x,y)记为dXYd_{XY}dXY​。然后,对点集Y中的每一个点yyy计算其到点集X中的每一个点xxx的距离,保留最短距离inf⁡y∈Yd(x,y)\inf_{y \in Y}d(x,y)infy∈Y​d(x,y),然后找出保留的最短距离中的最大距离sup⁡x∈Xinf⁡y∈Yd(x,y)\sup_{x \in X}{\inf_{y \in Y}d(x,y)}supx∈X​infy∈Y​d(x,y)记为dYXd_{YX}dYX​。最后,取dXYd_{XY}dXY​和dYXd_{YX}dYX​最大值作为点集X和Y之间的豪斯多夫距离。

  • 95% 豪斯多夫距离(95% Hausdorff distance,HD95)

    为了排除一些离群点造成的不合理距离,保持整体数值稳定性,一般选择从小到大排名前 95%的距离作为实际豪斯多夫距离,称之为 95% 豪斯多夫距离。

  • 灵敏度(Sensitivity)

    也称真阳性率(True Positive Rate)、命中率(hit rate)和召回率(Recall),表示预测为正的肿瘤标签占真实肿瘤标签的比例,其值越大,漏检率越低。设P表示数据中真阳样例的数量,TP表示正确预测为正例的数量,FN表示错误预测为反例的数量,则定义为
    Sensitivity=TPR=Recall=TPP=TPTP+FN=1−FNR\mathrm{Sensitivity}=\mathrm{TPR}=\mathrm{Recall}=\frac{\mathrm{TP}}{\mathrm{P}}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FN}}=1-\mathrm{FNR} Sensitivity=TPR=Recall=PTP​=TP+FNTP​=1−FNR

  • 特异度(Specificity)

    也称真阴性率(True Negative Rate)和选择性(Selectivity),表示预测为正的背景标签占所有真实背景标签的比例,其值越高则误诊率越低。设N表示数据中真阴样例的数量,TN表示正确预测为负例的数量,FP表示错误预测为正例的数量,则定义为
    Specificity=Selectivity=TNR=TNN=TNTN+FP=1−FPR\mathrm{Specificity}=\mathrm{Selectivity}=\mathrm{TNR}=\frac{\mathrm{TN}}{\mathrm{N}}=\frac{\mathrm{TN}}{\mathrm{TN}+\mathrm{FP}}=1-\mathrm{FPR} Specificity=Selectivity=TNR=NTN​=TN+FPTN​=1−FPR

  • 阳性预测值(Positive Predictive Value,PPV)

    也称精确度(Precision),指在所有样本的预测结果中,真阳性占所有阳性样本的比例,其值越大越好。设TP表示正确预测为正例的数量,FP表示错误预测为正例的数量,则定义为
    Precision=PPV=TPTP+FP=1−FDR\mathrm{Precision}=\mathrm{PPV}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FP}}=1-\mathrm{FDR} Precision=PPV=TP+FPTP​=1−FDR

2.MedPy安装

medpy安装较为简单,此处以Ubuntu 18.04.5 LTS系统的root用户为例,其他情况详见参考文献安装即可。

为了启用graph-cut包,我们需要安装下列软件包

sudo apt-get install libboost-python-dev build-essential

然后使用阿里云镜像源高速安装medpy

sudo pip install medpy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

3.MedPy常用函数

3.1 medpy.io.load(image)

加载图像并返回包含图像像素内容以及头部对象的 ndarray

import os
from medpy.io import load,save
# 文件夹路径和文件名
dirname="/dataset/RSNA_ASNR_MICCAI_BraTS2021_TrainingData_16July2021/BraTS2021_00000/"
basename="BraTS2021_00000_seg.nii.gz"
full_path=os.path.join(dirname,basename)
# 加载脑肿瘤标记图像返回图像数据数组和头部信息
image_data, image_header = load(full_path)
print("图像数据类型为{},图像数据形状为{}".format(type(image_data),image_data.shape))

# 获取一个切片数组
slice_0=image_data[:,:,77]
print("切片数组的形状为{},切片数组的数据类型为{}".format(slice_0.shape,slice_0.dtype))

# 转置显示灰度图
plt.imshow(slice_0.T, cmap="gray")

# 将纵坐标设置为对数尺度,等宽区间数量设置为为8个绘制切片数组灰度直方图
plt.hist(image_data.flatten(), bins=8, log=True)

3.2 medpy.metric.binary.dc(result, reference)

计算二值图像之间的Dice系数(也称为索伦森指数)

首先编辑第三方库源代码在最后追加一行输出语句,保存退出后重启kernel。该输出语句指示此时调用的numpy定义,若调用dc函数前有输出,则表示调用依赖numpy的函数,否则调用依赖jax.numpy的兼容函数实现加速运算

vim /opt/conda/lib/python3.7/site-packages/medpy/metric/binary.py

然后定义统一的一个数组大小参数,最后使用魔术命令%%timeit评估CPU和GPU计算两种方法的运行效率

# 设置数组形状为10000*10000的元组
tup=(10000,10000)
  • 调用依赖numpy的函数

    %%timeit
    from medpy.metric.binary import dc
    import numpy as np
    # 设置伪随机数种子
    seed=np.random.seed(6)
    # 定义预测结果和真实标记数组
    predict=np.random.randint(0,4,size=tup)
    ground_truth=np.random.randint(0,4,size=tup)
    # 计算Dice相似系数
    dice1=dc(predict,ground_truth)
    print("Dice相似系数为{}".format(dice1))
    

  • 调用依赖jax.numpy的兼容函数

    %%timeit
    from medpy.metric.binary import dc
    import jax.numpy as numpy # 重载numpy定义使得dc函数底层可以加速计算
    from jax import random
    # 设置伪随机数种子
    rng1=random.PRNGKey(1)
    rng2=random.PRNGKey(2)
    # 定义预测结果和真实标记数组
    predict=random.randint(key=rng1,shape=tup,minval=0,maxval=4)
    ground_truth=random.randint(key=rng2,shape=tup,minval=0,maxval=4)
    # 计算Dice相似系数
    dice2=dc(predict,ground_truth)
    print("Dice相似系数为{}".format(dice2))
    

3.3 medpy.metric.binary.jc(result, reference)

计算两个图像中二值对象间的Jaccard系数,下面通过两种方式计算

  • 直接调用第三方库函数计算jaccard系数
%%timeit
from medpy.metric.binary import jc
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=tup,minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=tup,minval=0,maxval=4)
# 直接计算Jaccard相似系数
jaccard=jc(predict,ground_truth)
print("Jaccard相似系数为{}".format(jaccard))

  • 通过Dice系数和Jaccard系数的如下关系推导计算

Jaccard=Dice2−DiceJaccard=\frac{Dice}{2-Dice}\nonumber Jaccard=2−DiceDice​

%%timeit
from medpy.metric.binary import dc
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=tup,minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=tup,minval=0,maxval=4)
# 通过Dice相似系数推导Jaccard相似系数
dice=dc(predict,ground_truth)
jaccard=dice/(2-dice)
print("通过Dice相似系数推导Jaccard相似系数为{}".format(jaccard))

  • 对比两种计算结果、源代码实现、运行效率可知,两种方式结果一样但通过Dice系数推导Jaccard系数运行效率更高,其原因是将一个统计非零值的O(n)O(n)O(n)时间复杂度的函数替换成了O(1)O(1)O(1)时间复杂度的简单推导。

3.4 medpy.metric.binary.hd(result,reference,voxelspacing=None,connectivity=1,)

计算两个图像中二值对象之间的(对称)豪斯多夫距离(HD)。它被定义为对象之间的最大表面距离。

%%timeit
from medpy.metric.binary import hd,hd95
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算豪斯多夫距离
hausdorff_distance=hd(predict,ground_truth)
print("豪斯多夫距离为{}".format(hausdorff_distance))

3.5 medpy.metric.binary.hd95(result,reference,voxelspacing=None,connectivity=1,)

计算两个图像中二值对象之间的(对称)豪斯多夫距离 (HD) 的第 95 个百分位数。与豪斯多夫距离相比,该指标对于小异常值稍微稳定一些,通常用于生物医学分割挑战。

%%timeit
from medpy.metric.binary import hd,hd95
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算95%豪斯多夫距离
hausdorff_distance95=hd95(predict,ground_truth)
print("95%豪斯多夫距离为{}".format(hausdorff_distance95))

3.6 medpy.metric.binary.recall(result, reference)

返回召回率

%%timeit
from medpy.metric.binary import recall
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算召回率/灵敏度/真阳性率
sensitivity=recall(predict,ground_truth)
print("召回率/灵敏度/真阳性率为{}".format(sensitivity))

3.7 medpy.metric.binary.sensitivity(result, reference)

返回灵敏度,内部实现直接调用recall

%%timeit
from medpy.metric.binary import sensitivity
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算召回率/灵敏度/真阳性率
recall=sensitivity(predict,ground_truth)
print("召回率/灵敏度/真阳性率为{}".format(recall))

3.8medpy.metric.binary.true_positive_rate(result, reference)

返回真阳性率,内部实现直接调用recall

%%timeit
from medpy.metric.binary import true_positive_rate
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算召回率/灵敏度/真阳性率
sensitivity=true_positive_rate(predict,ground_truth)
print("召回率/灵敏度/真阳性率为{}".format(sensitivity))

3.9medpy.metric.binary.specificity(result, reference)

返回特异度

%%timeit
from medpy.metric.binary import specificity
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算特异度/真阴性率
tnr=specificity(predict,ground_truth)
print("特异度/真阴性率为{}".format(tnr))

3.10medpy.metric.binary.true_negative_rate(result, reference)

返回真阴性率

%%timeit
from medpy.metric.binary import true_negative_rate
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算特异度/真阴性率
specifity=true_negative_rate(predict,ground_truth)
print("特异度/真阴性率为{}".format(specifity))

3.11medpy.metric.binary.precision(result, reference)

返回精确度

%%timeit
from medpy.metric.binary import precision
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算精确度/阳性预测值
Precision=precision(predict,ground_truth)
print("精确度/阳性预测值为{}".format(Precision))

3.12 medpy.metric.binary.positive_predictive_value(result, reference)

返回阳性预测值

%%timeit
from medpy.metric.binary import positive_predictive_value
import jax.numpy as numpy
from jax import random
# 设置伪随机数种子
rng1=random.PRNGKey(1)
rng2=random.PRNGKey(2)
# 定义预测结果和真实标记数组
predict=random.randint(key=rng1,shape=(50,50),minval=0,maxval=4)
ground_truth=random.randint(key=rng2,shape=(50,50),minval=0,maxval=4)
# 计算精确度/阳性预测值
ppv=positive_predictive_value(predict,ground_truth)
print("精确度/阳性预测值为{}".format(ppv))

3.13 medpy.io.save(arr, filename, hdr=False, force=True, use_compression=False)

使用“hdr”中编码的信息将图像“arr”保存为文件名。目标图像格式由“文件名”后缀确定。如果“force”参数设置为 true,以静默方式覆盖已存在的映像。否则将引发错误。

import os
from medpy.io import load,save
# 文件夹路径和文件名
dirname="/dataset/RSNA_ASNR_MICCAI_BraTS2021_TrainingData_16July2021/BraTS2021_00000/"
basename="BraTS2021_00000_seg.nii.gz"
full_path=os.path.join(dirname,basename)
# 加载脑肿瘤标记图像返回图像数据数组和头部信息
image_data, image_header = load(full_path)
# 将图像数据保存为BraTS2021_00000_seg.nii
save(image_data,"BraTS2021_00000_seg.nii")

4.参考文献

  • MedPy — MedPy 0.4.0 documentation (loli.github.io)
  • Sørensen–Dice coefficient
  • Jaccard index
  • Hausdorff distance
  • Precision and recall
  • Sensitivity and specificity
  • Confusion matrix

Python第三方库之MedPy相关推荐

  1. 4行指令解决pip下载Python第三方库太慢问题(pip更换国内下载源)

     问题由来: 之前在写一篇项目博客时,pip下载Python第三方库:graphic-verification-code,实在太慢了,于是使用Python库官网下载,还是很慢,而且不断失败,下载慢且不 ...

  2. dos系统不能安装python模块,无法使用pip命令安装python第三方库的原因及解决方法...

    再dos中无法使用pip,命令主要是没有发现这个命令.我们先找到这个命令的位置,一般是在python里面的scripts文件夹里面.我们可以把dos切换到对应的文件夹,再使用pip命令就可以了. 如果 ...

  3. 查看本机中的python第三方库文档

    [转载] 原文链接:https://blog.csdn.net/weixin_43936250/article/details/105251049 本机系统为win10,在使用python编程的过程中 ...

  4. Python_note8 程序设计方法学+Python第三方库安装+os库

    实例13 体育竞技分析 自顶向下,解决复杂问题的有效方法,将一个小问题表达为若干小问题组成的形式,使用同样方法进一步解决小问题直至可以用计算机简单解决:自底向上 理解自顶向下的设计思维:分而治之:理解 ...

  5. 离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中)

    离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中) 参考文章: (1)离线安装python第三方库的实用方法:解决公 ...

  6. python如何离线安装第三方库_离线环境安装python第三方库

    python 离线环境安装python第三方库 author: yafeishi tags: AntDB,python python对于运维工作确实方便了很多,但很多比较实用的库都是第三方提供,在os ...

  7. 下面不属于python第三方库的安装方法的是-关于python中第三方库安装方法和问题解决...

    一.安装方法 方法一: 1.管理员身份启动命令行(运行--->cmd) 2.pip install 库的绝对路径和库的详细名称 :或者运用cd命令跳转到下载好的库所在的位置然后pip insta ...

  8. python中安装一个第三方库的命令格式是-无法使用pip命令安装python第三方库的彻底解决方案...

    无法使用pip命令安装python第三方库的原因及解决方法 再dos中无法使用pip,命令主要是没有发现这个命令.我们先找到这个命令的位置,一般是在python里面的Scripts文件夹里面.我们可以 ...

  9. python第三方库numpy-Python第三方库之openpyxl(2)

    Python第三方库之openpyxl(2) 简单的使用 写一个工作簿 >>> from openpyxl importWorkbook>>> from openp ...

最新文章

  1. Gartner:为什么每一位首席执行官都应重视物联网并为其投资?
  2. 无线节能组信标为什么会自动切换? 排查故障的过程真的像谜一样无法解释
  3. iOS 自定义 View
  4. python爬虫教程视频-python爬虫(入门教程、视频教程)
  5. mysql 视图慢_第03问:磁盘 IO 报警,MySQL 读写哪个文件慢了?
  6. 配置tomcat 7控制台账号
  7. 40-400-035-运维-优化-pt-variable-advisor优化工具
  8. wordpress主题安装教程及错误处理
  9. 我是怎么用缠论在商品里边抢钱之二 (2019-07-12 15:10:10)
  10. 微信小程序如何上传图片
  11. 微信小程序自定义侧滑删除组件
  12. 正弦和余弦(角度到弧度)
  13. 【5G会话管理】UE IP地址的管理
  14. UE4 InputMode无法锁定编辑器视口鼠标解决方案
  15. 智慧农业智能节水灌溉 机井灌溉控制器
  16. VR和AR将如何发展下去?哪个更有前景?
  17. spring boot 搭建测试报错Whitelabel Error Page No message available
  18. 判断是否为直角三角形
  19. Docker+Jenkins+Seneca构建去集中化微服务架构
  20. 香港科技大学数据建模硕士学位项目(MSc DDM)武汉站宣讲会通知(Mix Mode 线上+线下同步进行)

热门文章

  1. 齐二TK6916/20/26/32系列数控落地铣镗床简介5
  2. 伪类元素--before和after
  3. springboot毕设项目会议室预约管理系统kh090(java+VUE+Mybatis+Maven+Mysql)
  4. 电话都免费了 移动IM这么牛X 运营商知道么?
  5. js 屏幕滚动到固定位置
  6. 威纶通触摸屏通过移动图形元件实现动画效果的具体方法
  7. SPI的NSS 脉冲模式的作用
  8. Django博客搭建_用户注册1_图片生成
  9. 手机通讯录联系人怎么恢复 快速恢复的方法
  10. Scratch少儿编程教培系统源码下载