0

0

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割

P粉084495128

P粉084495128

发布时间:2025-07-29 10:28:11

|

379人浏览过

|

来源于php中文网

原创

本文对印度与津巴布韦板球比赛场景进行语义分割研究,使用U-Net、PP-LiteSeg和SegFormer三个模型。数据集含9个类别,经解压、重命名等预处理后用于训练。评估显示,PP-LiteSeg效果最佳,mIoU达0.7751,SegFormer次之,U-Net表现稍弱,最后还进行了模型部署。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

[ai达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网

印度vs津巴布韦!板球比赛语义分割

在本次板球分割任务中,我先后使用了三个模型来比较语义分割的效果,分别是U-Net、PP-LiteSeg和SegFormer。在实际检测中,PP-LiteSeg模型的预测效果还是不错的,整体情况如下:

模型名称 mIoU Acc Kappa Dice
U-Net 0.5752 0.9700 0.9065 0.6856
PP-LiteSeg 0.7751 0.9865 0.9594 0.8632
SegFormer 0.7669 0.9877 0.9625 0.8593

一、项目背景

语义分割是指从图像中提取特征信息,并将这些特征信息转换为对应的类别。这些类别可以是人、汽车、花朵、家具等。在计算机视觉和机器学习领域,语义分割是一个热门的研究方向,因为它在自动驾驶、室内导航、虚拟现实/增强现实等应用中有着广泛的应用。在这些应用中,我们需要准确地将图像中的每个像素映射到一个特定的类别中,以便更好地理解和处理图像。例如,在本项目中,我们可以使用语义分割模型将板球比赛场景分为击球手,投球手,检票口守门员,外野手,球,裁判员,检票口,地面和背景共9个类别。

二、数据集介绍

该数据集来自公开媒体的印度和津巴布韦之间的比赛,每 298 帧拍摄 12 帧,并替换其中的一些模糊的帧和异常值。该数据集适用于训练有关体育分析的检测模型,不过更偏向于板球。 该数据集包含9个类别:击球手,投球手,检票口守门员,外野手,球,裁判员,检票口,地面和背景。

部分数据如下:

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

三、数据预处理

Step01: 解压数据集

ERROR1:

/bin/bash: -c: 行 0: 未预期的符号 `(' 附近有语法错误
/bin/bash: -c: 行 0: `unzip /home/aistudio/data/data192893/archive (1).zip -d /home/aistudio/work/'
       

SOLUTION1: 重命名文件夹 archive(1).zip -> archive.zip

In [ ]
!unzip /home/aistudio/data/data192893/archive.zip -d /home/aistudio/work/
   

Step02: 重命名文件夹。www.acmeai.tech ODataset 4 - Cricket Semantic Segmentation -> cricket

Step03: 分开不同后缀的文件。

在/home/aistudio/work目录下新建images、jsons、labels和save文件夹。

  • images:原始图像。
  • labels:标注文件。

在本次项目中只需要用到images和labels两个文件夹。

In [5]
!mv /home/aistudio/work/cricket/images/*.png___fuse.png /home/aistudio/work/labels/
!mv /home/aistudio/work/cricket/images/*.png___pixel.json /home/aistudio/work/jsons/
!mv /home/aistudio/work/cricket/images/*.png___save.png /home/aistudio/work/save/
!mv /home/aistudio/work/cricket/images/*.png /home/aistudio/work/images/
   

Step04: 修改文件后缀名。

In [ ]
%cd /home/aistudio/work/labels/
!rename 's/\.png___fuse.png/\.png/'  ./*
   

四、代码实现

4.1 环境配置

从Github下载PaddleSeg代码。

In [ ]
%cd /home/aistudio/
!git clone https://github.com/PaddlePaddle/PaddleSeg
   

执行如下命令,从源码编译安装PaddleSeg包。大家对于PaddleSeg/paddleseg目录下的修改,都会立即生效,无需重新安装。

In [ ]
%cd /home/aistudio/PaddleSeg/
!pip install -r requirements.txt
!pip install -v -e .
   

4.2 数据准备

Step01: 将数据集移动到/home/aistudio/PaddleSeg/data/cricket目录下。

首先要在/home/aistudio/PaddleSeg目录下新建data和cricket文件夹。

In [8]
!mv /home/aistudio/work/images /home/aistudio/PaddleSeg/data/cricket/
!mv /home/aistudio/work/labels /home/aistudio/PaddleSeg/data/cricket/
   
In [ ]
%cd /home/aistudio/PaddleSeg/data/cricket/images/
!rename 's/\ (/\_/'  ./*
!rename 's/\).png/\.png/'  ./*
%cd /home/aistudio/PaddleSeg/data/cricket/labels/
!rename 's/\ (/\_/'  ./*
!rename 's/\).png/\.png/'  ./*
   

Step02: 将彩色标注图转换成灰度标注图

首先找到各个类别对应的RGB像素值,结果如下所示:

  • Background:#916041 对应RGB (145,96,65)
  • Ground:#e2d5de 对应RGB (226,213,222)
  • Bowler:#0018fd 对应RGB (0,24,253)
  • Batsmen:#b07a53 对应RGB (176,122,83)
  • Wicket Keeper:#8fdfa9 对应RGB (143,223,169)
  • Umpire:#e20959 对应RGB (226,9,89)
  • Fielder:#c2fe6b 对应RGB (194,254,107)
  • Ball:#5e8d38 对应RGB (94,141,56)
  • Wicket:#1e472a 对应RGB (30,71,42)

然后,实现RGB像素值到灰度值的映射关系。

In [ ]
import osimport numpy as npfrom PIL import Imagefrom tqdm import tqdm

Origin_SegmentationClass_path = "/home/aistudio/PaddleSeg/data/cricket/labels"Out_SegmentationClass_path = "/home/aistudio/PaddleSeg/data/cricket/mask"# 对应关系Origin_Point_Value = np.array([[145, 96, 65], [226, 213, 222], [0, 24, 253], [176, 122, 83], [143, 223, 169], [226, 9, 89], [194, 254, 107], [94, 141, 56], [30, 71, 42]])
Out_Point_Value = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])if __name__ == "__main__":    if not os.path.exists(Out_SegmentationClass_path):
        os.makedirs(Out_SegmentationClass_path)    #
    png_names = os.listdir(Origin_SegmentationClass_path) # 获得图片的文件名
    print("正在遍历全部标签。")    for png_name in tqdm(png_names):        if png_name == ".ipynb_checkpoints":            continue
        png = Image.open(os.path.join(Origin_SegmentationClass_path, png_name)) # RGB
        w, h = png.size
        png = np.array(png, np.uint8) # h, w, c
        out_png = np.zeros([h, w]) # 灰度 h, w

        for map_idx, rgb in enumerate(Origin_Point_Value):
            idx = np.where(
                (png[..., 0] == rgb[0]) & (png[..., 1] == rgb[1]) & (png[..., 2] == rgb[2]))
            out_png[idx] = map_idx        # print("out_png:", out_png.shape)

        out_png = Image.fromarray(np.array(out_png, np.uint8)) # 再次转化为Image进行保存
        out_png.save(os.path.join(Out_SegmentationClass_path, png_name))    # 统计输出,各个像素点的值的个数
    print("正在统计输出的图片每个像素点的数量。")
    classes_nums = np.zeros([256], np.int32)    for png_name in tqdm(png_names):        if png_name == ".ipynb_checkpoints":            continue
        png_file_name = os.path.join(Out_SegmentationClass_path, png_name)        if not os.path.exists(png_file_name):            raise ValueError("未检测到标签图片%s,请查看具体路径下文件是否存在以及后缀是否为png。" % (png_file_name))

        png = np.array(Image.open(png_file_name), np.uint8)
        classes_nums += np.bincount(np.reshape(png, [-1]), minlength=256)    print("打印像素点的值与数量。")    print('-' * 37)    print("| %15s | %15s |" % ("Key", "Value"))    print('-' * 37)    for i in range(256):        if classes_nums[i] > 0:            print("| %15s | %15s |" % (str(i), str(classes_nums[i])))            print('-' * 37)
   

最后,为了判断转换的结果是否正确,我们可以使用PaddleSeg提供的转换工具,将灰度标注图转换成伪彩色标注图。

In [ ]
!python tools/data/gray2pseudo_color.py /home/aistudio/PaddleSeg/data/cricket/mask /home/aistudio/PaddleSeg/data/cricket/output
   

处理结果如下:

  • 左上:板球比赛原图。
  • 右上:板球比赛原标注图。
  • 左下:转换得到的训练用的灰度标注图
  • 右下:通过PaddleSeg的转换工具得到的伪彩色标注图,用于判断转换结果是否正确。[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网            

Step03: 切分数据。

In [ ]
%cd /home/aistudio/PaddleSeg/
!python tools/data/split_dataset_list.py /home/aistudio/PaddleSeg/data/cricket images mask --format "png" "png" --split 0.7 0.3 0
   

4.3 模型训练

PP-LiteSeg

PP-LiteSeg提出三个创新模块:

  • 解码模块(FLD)调整解码模块中通道数,平衡编码模块和解码模块的计算量。
  • 注意力融合模块(UAFM)加强特征表示。
  • 简易金字塔池化模块(SPPM)减小中间特征图的通道数、移除跳跃连接。

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

准备好配置文件后,我们使用tools/train.py脚本进行模型训练。

BlackBox AI
BlackBox AI

AI编程助手,智能对话问答助手

下载
In [ ]
!python tools/train.py \
    --config configs/pp_liteseg/pp_liteseg_stdc2_cityscapes_1024x512_scale1.0_160k.yml \
    --save_dir output/pp_liteseg \
    --save_interval 2000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   

如果训练中断,我们可以恢复训练,避免从头开始训练。通过给train.py脚本设置resume_model输入参数,加载中断前最近一次保存的模型信息,恢复训练。

In [ ]
!python tools/train.py \
    --config configs/pp_liteseg/pp_liteseg_stdc2_cityscapes_1024x512_scale1.0_160k.yml \
    --save_dir output/pp_liteseg \
    --save_interval 2000 \
    --resume_model output/pp_liteseg/iter_52000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   

损失函数如下:

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

U-Net

U-Net网络结构因为形似字母“U”而得名,最早是在医学影像的细胞分割任务中提出,结构简单适合处理小数量级的数据集。比较于FCN网络的像素相加,U-Net是对通道进行concat操作,保留上下文信息的同时,加强了它们之间的语义联系。整体是一个Encode-Decode的结构,如下图所示。

  • 知识点1:下采样Encode包括conv和max pool,上采样Decode包括up-conv和conv。
  • 知识点2:U-Net特点在于灰色箭头,利用通道融合使上下文信息紧密联系起来。

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

In [ ]
!python tools/train.py \
    --config configs/unet/unet_cityscapes_1024x512_160k.yml \
    --save_dir output/unet \
    --save_interval 2000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   
In [ ]
!python tools/train.py \
    --config configs/unet/unet_cityscapes_1024x512_160k.yml \
    --save_dir output/unet \
    --save_interval 2000 \
    --resume_model output/unet/iter_56000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   

SegFormer

SegFormer是一种将Transformer和轻量级的MLP相结合的语义分割框架。该框架的优势在于:

  • 知识点1:层次化的transformer编码器/MiT,生成不同尺度特征;
  • 知识点2:轻量的全MLP解码器,融合不同层级特征。

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

In [ ]
!python tools/train.py \
    --config configs/segformer/segformer_b5_cityscapes_1024x512_160k.yml \
    --save_dir output/segformer \
    --save_interval 2000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   
In [ ]
!python tools/train.py \
    --config configs/segformer/segformer_b5_cityscapes_1024x512_160k.yml \
    --save_dir output/segformer \
    --save_interval 2000 \
    --resume_model output/segformer/iter_34000 \
    --num_workers 2 \
    --do_eval \
    --use_vdl
   

恢复训练中,大家可能会遇到一个问题,那就是日志文件是分割开的,接下来我们可以通过以下代码合并日志文件。

  1. 将所有的x.log文件拷贝到一个logs目录下。
  2. 将代码中的target_dir设置为上一步logs的根目录,运行后,会生成一个与logs同级的目录merge,merge下的x.log文件即包含了完整训练数据。
  3. 可视化。
In [ ]
import osfrom visualdl import LogReader, LogWriterdef trans_vdlrecords_to_txt(vdl_file_path):
    txt_path = vdl_file_path.replace('.log', '.txt')
    reader = LogReader(file_path=vdl_file_path)
    tags = reader.get_tags()
    scalar = tags.get('scalar')    if scalar is not None:
        fo = open(txt_path, "w")
        fo.write(f'tags:{tags}')        for tag in scalar:
            fo.write(f'\n------------{tag}------------\n')
            data = reader.get_data('scalar', tag)
            fo.write(f'The Last One is {str(data[-1])}')
            fo.write(str(data))

        fo.close()def merge_vdlrecords(vdl_file_path, last_step_dict, writer=None):
    reader = LogReader(file_path=vdl_file_path)
    tags = reader.get_tags()
    scalar = tags.get('scalar')    if scalar is not None:        print(f'tags:{tags}')
        data = None
        for tag in scalar:
            data = reader.get_data('scalar', tag)            for e in data:
                curr_last_step = last_step_dict[tag] if tag in last_step_dict else -1
                if e.id > curr_last_step:
                    writer.add_scalar(tag=tag, step=e.id, value=e.value)
            last_step_dict[tag] = data[-1].id
            print(f'{vdl_file_path} {tag} last_id is {last_step_dict[tag]}')    return last_step_dictdef do_merge(target_dir):
    logdir = target_dir + '/merge'
    writer = LogWriter(logdir=logdir)
    last_step_dict = {}    print('called1')    try:        for path, dir_list, file_list in os.walk(target_dir + '/logs'):            print('called2', file_list)
            file_list.sort() 
            for file_name in file_list:                if file_name.endswith('.log'):
                    log_path = os.path.join(path, file_name)                    print(log_path)
                    last_step = merge_vdlrecords(log_path, last_step_dict, writer)    except Exception as err:        print(f'error {erro}')    finally:
        writer.close()def do_trans(_dir):
    for path, dir_list, file_list in os.walk(_dir):        for file_name in file_list:            if file_name.endswith('.log'):
                log_path = os.path.join(path, file_name)                print(log_path)
                trans_vdlrecords_to_txt(log_path)if __name__ == '__main__':

    target_dir = '/home/aistudio/PaddleSeg/output/segformer/'
    do_merge(target_dir)
   

4.4 模型评估

训练完成后,大家可以使用评估脚本tools/val.py来评估模型的精度,即对配置文件中的验证数据集进行测试。

PP-LiteSeg

In [ ]
!python tools/val.py \
       --config configs/pp_liteseg/pp_liteseg_stdc2_cityscapes_1024x512_scale1.0_160k.yml \
       --model_path output/pp_liteseg/best_model/model.pdparams
   

指标如下:

  • [EVAL] #Images: 89 mIoU: 0.7751 Acc: 0.9865 Kappa: 0.9594 Dice: 0.8632
  • [EVAL] Class IoU: [0.9485 0.9878 0.7535 0.8408 0.7275 0.9158 0.7254 0.4405 0.6366]
  • [EVAL] Class Precision: [0.9588 0.9972 0.9282 0.9318 0.8178 0.9601 0.7737 0.6414 0.7756]
  • [EVAL] Class Recall: [0.9888 0.9906 0.8001 0.8959 0.8682 0.952 0.9208 0.5845 0.7803]

U-Net

In [ ]
!python tools/val.py \
       --config configs/unet/unet_cityscapes_1024x512_160k.yml \
       --model_path output/unet/best_model/model.pdparams
   

指标如下:

  • [EVAL] #Images: 89 mIoU: 0.5752 Acc: 0.9700 Kappa: 0.9065 Dice: 0.6856
  • [EVAL] Class IoU: [0.8739 0.9779 0.5385 0.6238 0.4768 0.7272 0.4314 0. 0.5272]
  • [EVAL] Class Precision: [0.985 0.9806 0.8682 0.7056 0.5954 0.7795 0.5945 0. 0.7845]
  • [EVAL] Class Recall: [0.8857 0.9972 0.5864 0.8433 0.7053 0.9156 0.6113 0. 0.6165]

SegFormer

In [ ]
!python tools/val.py \
       --config configs/segformer/segformer_b5_cityscapes_1024x512_160k.yml \
       --model_path output/segformer/best_model/model.pdparams
   

指标如下:

  • [EVAL] #Images: 89 mIoU: 0.7669 Acc: 0.9877 Kappa: 0.9625 Dice: 0.8593
  • [EVAL] Class IoU: [0.959 0.991 0.6543 0.8017 0.7272 0.915 0.6649 0.4981 0.6908]
  • [EVAL] Class Precision: [0.9877 0.9943 0.8839 0.863 0.8486 0.9723 0.7471 0.6818 0.8416]
  • [EVAL] Class Recall: [0.9706 0.9967 0.7158 0.9186 0.8356 0.9395 0.8581 0.6491 0.7941]

4.5 模型预测

我们可以通过tools/predict.py脚本是来进行可视化预测,命令格式如下所示。

In [ ]
!python tools/predict.py \
       --config configs/pp_liteseg/pp_liteseg_stdc2_cityscapes_1024x512_scale1.0_160k.yml \
       --model_path output/pp_liteseg/best_model/model.pdparams \
       --image_path data/cricket/images \
       --save_dir output/result
   

部分可视化结果如下:

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

当分割目标比较清晰的时候,分割效果还是很好的;但当分割目标较小时,分割效果还有待加强。

4.6 模型导出

执行如下命令,导出预测模型,保存在output/inference_model目录。

In [ ]
!python tools/export.py \
       --config configs/pp_liteseg/pp_liteseg_stdc2_cityscapes_1024x512_scale1.0_160k.yml \
       --model_path output/pp_liteseg/best_model/model.pdparams \
       --save_dir output/inference_model
   

4.7 FastDeploy快速部署

环境准备: 本项目的部署环节主要用到的套件为飞桨部署工具FastDeploy,因此我们先安装FastDeploy。

In [ ]
!pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html
   

部署模型:

导入飞桨部署工具FastDepoy包,创建Runtimeoption,具体实现如下代码所示。

In [1]
import fastdeploy as fdimport cv2import os
   
In [2]
def build_option(device='cpu', use_trt=False):
    option = fd.RuntimeOption()    if device.lower() == "gpu":
        option.use_gpu()    if use_trt:
        option.use_trt_backend()
        option.set_trt_input_shape("x", [1, 3, 1080, 1920])
        option.set_trt_input_shape("scale_factor", [1, 2])    return option
   

配置模型路径,创建Runtimeoption,指定部署设备和后端推理引擎,代码实现如下所示。

In [ ]
# 配置模型路径model_path = '/home/aistudio/PaddleSeg/output/inference_model'image_path = '/home/aistudio/PaddleSeg/data/cricket/images/2022-08-24_134.png'model_file = os.path.join(model_path, "model.pdmodel")
params_file = os.path.join(model_path, "model.pdiparams")
config_file = os.path.join(model_path, "deploy.yaml")# 创建RuntimeOptionruntime_option = build_option(device='gpu', use_trt=False)# 创建PPYOLOE模型model = fd.vision.segmentation.PaddleSegModel(model_file,
                                              params_file,
                                              config_file,
                                              runtime_option=runtime_option)# 预测图片检测结果im = cv2.imread(image_path)
result = model.predict(im.copy())print(result)# 预测结果可视化vis_im = fd.vision.vis_segmentation(im, result, weight=0.5)
cv2.imwrite("/home/aistudio/work/visualized_result.jpg", vis_im)print("Visualized result save in ./visualized_result.jpg")
   

结果如下:

[AI达人特训营]印度vs津巴布韦!板球比赛语义分割 - php中文网        

5. 总结提高

在本次板球分割任务中,我先后使用了三个模型来比较语义分割的效果,分别是U-Net、PP-LiteSeg和SegFormer。整体情况如下:

模型名称 mIoU Acc Kappa Dice
U-Net 0.5752 0.9700 0.9065 0.6856
PP-LiteSeg 0.7751 0.9865 0.9594 0.8632
SegFormer 0.7669 0.9877 0.9625 0.8593

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

469

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

13

2025.12.06

github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

918

2026.01.21

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

165

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

34

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

73

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

2

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

4

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

8

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号