零基础入门图像分割:从数据到预测

本文介绍从零开始完成图像分割任务的项目。项目自建鸽子图片数据集,经拍摄、标注等步骤创建。分别用Paddle2.3 API、PaddleSeg2.5和PaddleX2.1三种方法,以U-Net网络为例,完成训练、验证和预测,还优化了数据集和流程,提升效率与可操作性。

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

零基础入门图像分割:从数据到预测 - 创想鸟

1. 项目简介

本项目介绍如何从零开始完成一个图像分割任务。通过自建数据集,并分别使用基于Paddle2.3,PaddleSeg2.5和PaddleX2.1的方法完成图像分割任务。相对于原有项目有如下几点改进:

对Paddle和PaddleSeg的版本进行了升级,使用了最新版本。增加了使用PaddleX完成图像分割的方法。对数据集图片进行了缩放使其尺寸变小,训练更快;并且对标签文件进行了预处理,避免了训练时的Bug。对整个项目流程的部分细节进行了优化,使其更加容易理解、减少bug、方便运行。

1.1 什么是图像分割

图像分割是一种典型的计算机视觉任务,指的是将一张图像分割成既定类别的几个区域。图像分割本质上是一种像素级别的图像分类任务。

图像分割通常分为语义分割、实例分割、全景分割,如图1所示。另外,还有基于视频的目标分割和实例分割。本项目中我们将完成一个图像语义分割任务。

零基础入门图像分割:从数据到预测 - 创想鸟            

图1 图像分割任务示意图

2. 创建数据集

本项目采用自建的鸽子图片数据集。创建数据集分为如下几步:

2.1. 拍摄鸽子的照片

拍摄鸽子图片时尽量选择不同角度、不同背景进行拍摄,图片中的鸽子数量也尽量不同,以便增加图片的多样性从而提高最后模型的鲁棒性。由于本项目只是讲述流程,故这里仅采用了122张照片。

2.2. 使用labelme进行标注

严格按照labelme github仓库主页的描述来安装labelme,链接为labelme github网

2.3. 基于标注好的图片利用json文件生成原始图片和标签图片

使用labelme完成标注任务后,需要利用保存的json文件来生成原始图片和对应的标签图片。这里要注意的是,由于labelme自带的labelme_json_to_dataset命令只能处理单个json文件,如果要批量处理所有生成的json文件可以采用并修改如下示例代码:

import ospath = PATH_TO_JSONjson_file = os.listdir(path)#os.system("conda activate labelme")for file in json_file:    os.system("labelme_json_to_dataset %s"%(path+"/"+file))

       

2.4. 使用AI Studio创建并上传标注好的图片

通常生成的数据集较大,这时可以使用AI Studio的创建数据集功能上传生成的数据,然后在项目中挂载使用。

完成以上步骤后就可以使用AI Studio进行训练、验证和预测了。

3. 训练、验证和预测

下面以U-Net网络为例,讲述两种进行训练、验证和预测的方法:基于Paddle2.3 API的方法和基于PaddleSeg2.5的方法。

3.1 基于Paddle2.3 API使用U-Net网络实现鸽子图像的语义分割任务

3.1.1 简要介绍

U-Net网络结构是一个基于FCN并改进后的深度学习网络,包含下采样(编码器,特征提取)和上采样(解码器,分辨率还原)两个阶段,因模型结构比较像U型而命名为U-Net。

3.1.2.环境设置

导入一些比较基础常用的模块,确认自己的飞桨版本。

In [4]

import osimport ioimport numpy as npimport matplotlib.pyplot as pltfrom PIL import Image as PilImageimport paddlefrom paddle.nn import functional as Fimport warningswarnings.filterwarnings('ignore') paddle.__version__

       

'2.3.0'

               

3.1.3 解压数据集

In [1]

!unzip -q 'data/data149031/imgs.zip' -d work/

   In [2]

## 预处理标签!python code/process_label.py

       

finished processing labels

       

3.1.4 数据集概览

首先我们先来了解一下我们的数据集。

数据集解压后,里面放的每个文件夹中有四个文件,分别是图片文件、标签文件、标签名字文件和可视化的图片文件,如下所示。

.├── label.png├── img.png├── label_names.txt└── label_viz.png

       

我们来看看这个数据集给我们提供了多少个训练样本。

In [5]

images_path = "work/imgs"image_count = len([os.path.join(images_path, image_name)           for image_name in os.listdir(images_path) if not image_name.startswith('.')])print("用于训练的图片样本数量:", image_count)

       

用于训练的图片样本数量: 122

       

3.1.5 划分训练集、验证集和测试集

In [6]

def _sort_images(image_dir):    """    对文件夹内的图像进行按照文件名排序    """    images = []    labels = []    for image_name in os.listdir(image_dir):        if os.path.isdir(os.path.join(image_dir, image_name)):            images.append('/home/aistudio/' + os.path.join(image_dir, image_name, 'img.png'))            labels.append('/home/aistudio/' + os.path.join(image_dir, image_name, 'result.png'))    return sorted(images), sorted(labels)"""这里的分割符是空格,因为PaddleSeg读取文件时默认的分割符是空格。"""def write_file(mode, images, labels):    with open('/home/aistudio/{}.txt'.format(mode), 'w') as f:        for i in range(len(images)):            f.write('{} {}n'.format(images[i], labels[i]))    """由于所有文件都是散落在文件夹中,在训练时我们需要使用的是数据集和标签对应的数据关系,所以我们第一步是对原始的数据集进行整理,得到数据集和标签两个数组,分别一一对应。这样可以在使用的时候能够很方便的找到原始数据和标签的对应关系,否则对于原有的文件夹图片数据无法直接应用。"""images, labels = _sort_images(images_path)eval_num = int(image_count * 0.1)"""由于图片数量有限,这里的测试集和验证集采用相同的一组图片。"""write_file('train', images[:-eval_num], labels[:-eval_num])write_file('test', images[-eval_num:], labels[-eval_num:])write_file('eval', images[-eval_num:], labels[-eval_num:])

   

3.1.6 DoveDataSet数据集抽样展示

划分好数据集之后,我们来查验一下数据集是否符合预期,我们通过划分的配置文件读取图片路径后再加载图片数据来用matplotlib进行展示。

In [7]

with open('/home/aistudio/train.txt', 'r') as f:    i = 0    for line in f.readlines():        image_path, label_path = line.strip().split(' ')        label_path = label_path.replace('result.png', 'label.png')        image = np.array(PilImage.open(image_path))        label = np.array(PilImage.open(label_path))            if i > 2:            break        # 进行图片的展示        plt.figure()        plt.subplot(1,2,1),         plt.title('Train Image')        plt.imshow(image.astype('uint8'))        plt.axis('off')        plt.subplot(1,2,2),         plt.title('Label')        plt.imshow(label.astype('uint8'))        plt.axis('off')        plt.show()        i = i + 1

       

               

               

               

3.1.7 数据集类定义

飞桨(PaddlePaddle)数据集加载方案是统一使用Dataset(数据集定义) + DataLoader(多进程数据集加载)。

首先我们先进行数据集的定义,数据集定义主要是实现一个新的Dataset类,继承父类paddle.io.Dataset,并实现父类中以下两个抽象方法,__getitem__和__len__:

class MyDataset(Dataset):    def __init__(self):        ...            # 每次迭代时返回数据和对应的标签    def __getitem__(self, idx):        return x, y    # 返回整个数据集的总数    def __len__(self):        return count(samples)

       

在数据集内部可以结合图像数据预处理相关API进行图像的预处理(改变大小、反转、调整格式等)。

由于加载进来的图像不一定都符合自己的需求,举个例子,已下载的这些图片里面可能会有RGBA格式的图片,这个时候图片就不符合我们所需3通道的需求,我们需要进行图片的格式转换,那么这里我们直接实现了一个通用的图片读取接口,确保读取出来的图片都是满足我们的需求。

本项目的数据集定义的代码可以参考code目录下的dove_dataset.py文件。

3.1.8 模型组网

U-Net是一个U型网络结构,可以看做两个大的阶段,图像先经过Encoder编码器进行下采样得到高级语义特征图,再经过Decoder解码器上采样将特征图恢复到原图片的分辨率。

具体的网络定义的代码可以参考code目录下的unet.py文件,具体网络结构包括如下几部分。

3.1.9 定义SeparableConv2D接口

我们为了减少卷积操作中的训练参数来提升性能,是继承paddle.nn.Layer自定义了一个SeparableConv2D Layer类,整个过程是把filter_size * filter_size * num_filters的Conv2D操作拆解为两个子Conv2D,先对输入数据的每个通道使用filter_size * filter_size * 1的卷积核进行计算,输入输出通道数目相同,之后在使用1 * 1 * num_filters的卷积核计算。

3.1.10 定义Encoder编码器

我们将网络结构中的Encoder下采样过程进行了一个Layer封装,方便后续调用,减少代码编写,下采样是有一个模型逐渐向下画曲线的一个过程,这个过程中是不断的重复一个单元结构将通道数不断增加,形状不断缩小,并且引入残差网络结构,我们将这些都抽象出来进行统一封装。

3.1.11 定义Decoder解码器

在通道数达到最大得到高级语义特征图后,网络结构会开始进行decode操作,进行上采样,通道数逐渐减小,对应图片尺寸逐步增加,直至恢复到原图像大小,那么这个过程里面也是通过不断的重复相同结构的残差网络完成,我们也是为了减少代码编写,将这个过程定义一个Layer来放到模型组网中使用。

3.1.12 训练模型组网

按照U型网络结构格式进行整体的网络结构搭建,三次下采样,四次上采样。

3.1.13 模型可视化

调用飞桨提供的summary接口对组建好的模型进行可视化,方便进行模型结构和参数信息的查看和确认。

In [19]

%cd codeimport paddlefrom unet import DoveNetnum_classes = 2IMAGE_SIZE = (224, 224)network = DoveNet(num_classes)model = paddle.Model(network)model.summary((-1, 3,) + IMAGE_SIZE)

       

/home/aistudio/code

       

W0607 10:10:12.904951   166 gpu_context.cc:278] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1W0607 10:10:12.909504   166 gpu_context.cc:306] device: 0, cuDNN Version: 7.6.

       

-----------------------------------------------------------------------------  Layer (type)        Input Shape          Output Shape         Param #    =============================================================================    Conv2D-1       [[1, 3, 224, 224]]   [1, 32, 112, 112]         896        BatchNorm2D-1   [[1, 32, 112, 112]]   [1, 32, 112, 112]         128           ReLU-1       [[1, 32, 112, 112]]   [1, 32, 112, 112]          0            ReLU-2       [[1, 32, 112, 112]]   [1, 32, 112, 112]          0       SeparableConv2D-1 [[1, 32, 112, 112]]   [1, 64, 112, 112]        2,400       BatchNorm2D-2   [[1, 64, 112, 112]]   [1, 64, 112, 112]         256           ReLU-3       [[1, 64, 112, 112]]   [1, 64, 112, 112]          0       SeparableConv2D-2 [[1, 64, 112, 112]]   [1, 64, 112, 112]        4,736       BatchNorm2D-3   [[1, 64, 112, 112]]   [1, 64, 112, 112]         256         MaxPool2D-1    [[1, 64, 112, 112]]    [1, 64, 56, 56]           0           Conv2D-2      [[1, 32, 112, 112]]    [1, 64, 56, 56]         2,112         Encoder-1     [[1, 32, 112, 112]]    [1, 64, 56, 56]           0            ReLU-4        [[1, 64, 56, 56]]     [1, 64, 56, 56]           0       SeparableConv2D-3  [[1, 64, 56, 56]]     [1, 128, 56, 56]        8,896       BatchNorm2D-4    [[1, 128, 56, 56]]    [1, 128, 56, 56]         512           ReLU-5        [[1, 128, 56, 56]]    [1, 128, 56, 56]          0       SeparableConv2D-4  [[1, 128, 56, 56]]    [1, 128, 56, 56]       17,664       BatchNorm2D-5    [[1, 128, 56, 56]]    [1, 128, 56, 56]         512         MaxPool2D-2     [[1, 128, 56, 56]]    [1, 128, 28, 28]          0           Conv2D-3       [[1, 64, 56, 56]]     [1, 128, 28, 28]        8,320         Encoder-2      [[1, 64, 56, 56]]     [1, 128, 28, 28]          0            ReLU-6        [[1, 128, 28, 28]]    [1, 128, 28, 28]          0       SeparableConv2D-5  [[1, 128, 28, 28]]    [1, 256, 28, 28]       34,176       BatchNorm2D-6    [[1, 256, 28, 28]]    [1, 256, 28, 28]        1,024          ReLU-7        [[1, 256, 28, 28]]    [1, 256, 28, 28]          0       SeparableConv2D-6  [[1, 256, 28, 28]]    [1, 256, 28, 28]       68,096       BatchNorm2D-7    [[1, 256, 28, 28]]    [1, 256, 28, 28]        1,024        MaxPool2D-3     [[1, 256, 28, 28]]    [1, 256, 14, 14]          0           Conv2D-4       [[1, 128, 28, 28]]    [1, 256, 14, 14]       33,024         Encoder-3      [[1, 128, 28, 28]]    [1, 256, 14, 14]          0            ReLU-8        [[1, 256, 14, 14]]    [1, 256, 14, 14]          0       Conv2DTranspose-1  [[1, 256, 14, 14]]    [1, 256, 14, 14]       590,080      BatchNorm2D-8    [[1, 256, 14, 14]]    [1, 256, 14, 14]        1,024          ReLU-9        [[1, 256, 14, 14]]    [1, 256, 14, 14]          0       Conv2DTranspose-2  [[1, 256, 14, 14]]    [1, 256, 14, 14]       590,080      BatchNorm2D-9    [[1, 256, 14, 14]]    [1, 256, 14, 14]        1,024        Upsample-1      [[1, 256, 14, 14]]    [1, 256, 28, 28]          0          Upsample-2      [[1, 256, 14, 14]]    [1, 256, 28, 28]          0           Conv2D-5       [[1, 256, 28, 28]]    [1, 256, 28, 28]       65,792         Decoder-1      [[1, 256, 14, 14]]    [1, 256, 28, 28]          0            ReLU-10       [[1, 256, 28, 28]]    [1, 256, 28, 28]          0       Conv2DTranspose-3  [[1, 256, 28, 28]]    [1, 128, 28, 28]       295,040     BatchNorm2D-10    [[1, 128, 28, 28]]    [1, 128, 28, 28]         512           ReLU-11       [[1, 128, 28, 28]]    [1, 128, 28, 28]          0       Conv2DTranspose-4  [[1, 128, 28, 28]]    [1, 128, 28, 28]       147,584     BatchNorm2D-11    [[1, 128, 28, 28]]    [1, 128, 28, 28]         512         Upsample-3      [[1, 128, 28, 28]]    [1, 128, 56, 56]          0          Upsample-4      [[1, 256, 28, 28]]    [1, 256, 56, 56]          0           Conv2D-6       [[1, 256, 56, 56]]    [1, 128, 56, 56]       32,896         Decoder-2      [[1, 256, 28, 28]]    [1, 128, 56, 56]          0            ReLU-12       [[1, 128, 56, 56]]    [1, 128, 56, 56]          0       Conv2DTranspose-5  [[1, 128, 56, 56]]    [1, 64, 56, 56]        73,792      BatchNorm2D-12    [[1, 64, 56, 56]]     [1, 64, 56, 56]          256           ReLU-13       [[1, 64, 56, 56]]     [1, 64, 56, 56]           0       Conv2DTranspose-6  [[1, 64, 56, 56]]     [1, 64, 56, 56]        36,928      BatchNorm2D-13    [[1, 64, 56, 56]]     [1, 64, 56, 56]          256         Upsample-5      [[1, 64, 56, 56]]    [1, 64, 112, 112]          0          Upsample-6      [[1, 128, 56, 56]]   [1, 128, 112, 112]         0           Conv2D-7      [[1, 128, 112, 112]]  [1, 64, 112, 112]        8,256         Decoder-3      [[1, 128, 56, 56]]   [1, 64, 112, 112]          0            ReLU-14      [[1, 64, 112, 112]]   [1, 64, 112, 112]          0       Conv2DTranspose-7 [[1, 64, 112, 112]]   [1, 32, 112, 112]       18,464      BatchNorm2D-14   [[1, 32, 112, 112]]   [1, 32, 112, 112]         128           ReLU-15      [[1, 32, 112, 112]]   [1, 32, 112, 112]          0       Conv2DTranspose-8 [[1, 32, 112, 112]]   [1, 32, 112, 112]        9,248      BatchNorm2D-15   [[1, 32, 112, 112]]   [1, 32, 112, 112]         128         Upsample-7     [[1, 32, 112, 112]]   [1, 32, 224, 224]          0          Upsample-8     [[1, 64, 112, 112]]   [1, 64, 224, 224]          0           Conv2D-8      [[1, 64, 224, 224]]   [1, 32, 224, 224]        2,080         Decoder-4     [[1, 64, 112, 112]]   [1, 32, 224, 224]          0           Conv2D-9      [[1, 32, 224, 224]]    [1, 2, 224, 224]         578      =============================================================================Total params: 2,058,690Trainable params: 2,051,138Non-trainable params: 7,552-----------------------------------------------------------------------------Input size (MB): 0.57Forward/backward pass size (MB): 230.07Params size (MB): 7.85Estimated Total Size (MB): 238.50-----------------------------------------------------------------------------

       

{'total_params': 2058690, 'trainable_params': 2051138}

               

3.1.14 启动模型训练

使用模型代码进行Model实例生成,使用prepare接口定义优化器、损失函数和评价指标等信息,用于后续训练使用。在所有初步配置完成后,调用fit接口开启训练执行过程,调用fit时只需要将前面定义好的训练数据集、测试数据集、训练轮次(Epoch)和批次大小(batch_size)配置好即可。

In [1]

!python ../code/train.py

   

3.1.15 预测数据集准备和预测

继续使用DoveDataset来实例化待预测使用的数据集。

我们可以直接使用model.predict接口来对数据集进行预测操作,只需要将预测数据集传递到接口内即可。

In [ ]

import paddlefrom unet import DoveNetfrom dove_dataset import DoveDataset

   In [ ]

num_classes = 2network = DoveNet(num_classes)

   In [ ]

state_dict = paddle.load('./unet.pdparams')network.set_state_dict(state_dict)model = paddle.Model(network)

   In [ ]

predict_dataset = DoveDataset(mode='test')test_loader = paddle.io.DataLoader(predict_dataset, places=paddle.CUDAPlace(0), batch_size= 32)model.prepare(paddle.nn.CrossEntropyLoss(axis=1))predict_results = model.predict(test_loader)

       

Predict begin...step 1/1 [==============================] - 678ms/stepPredict samples: 12

       

3.1.16 预测结果可视化

从我们的预测数据集中抽3个图片来看看预测的效果,展示一下原图、标签图和预测结果。

In [ ]

import numpy as npimport matplotlib.pyplot as pltfrom paddle.vision.transforms import transforms as Tfrom PIL import Image as PilImage

   In [ ]

plt.figure(figsize=(10, 10))IMAGE_SIZE = (224, 224)i = 0idx = 0with open('/home/aistudio/test.txt', 'r') as f:    for line in f.readlines():        image_path, label_path = line.strip().split(' ')        label_path = label_path.replace('result.png', 'label.png')        resize_t = T.Compose([            T.Resize(IMAGE_SIZE)        ])        image = resize_t(PilImage.open(image_path))        label = resize_t(PilImage.open(label_path))        image = np.array(image).astype('uint8')        label = np.array(label).astype('uint8')        if i > 8:             break        plt.subplot(3, 3, i + 1)        plt.imshow(image)        plt.title('Input Image')        plt.axis("off")        plt.subplot(3, 3, i + 2)        plt.imshow(label, cmap='gray')        plt.title('Label')        plt.axis("off")                data = predict_results[0][0][idx].transpose((1, 2, 0))        mask = np.argmax(data, axis=-1)        plt.subplot(3, 3, i + 3)        plt.imshow(mask.astype('uint8'), cmap='gray')        plt.title('Predict')        plt.axis("off")        i += 3        idx += 1plt.show()

       

               

3.2 基于PaddleSeg使用U-Net网络实现鸽子图像的语义分割任务

In [ ]

%cd

       

/home/aistudio

       

3.2.1 安装PaddleSeg

In [2]

!pip install paddleseg

   

3.2.2 克隆或者解压缩PaddleSeg

为避免由于网络造成的下载困难问题,这里采用解压缩的方法。也可以采用克隆的方法获取最新的PaddleSeg。

!git clone https://github.com/PaddlePaddle/PaddleSeg.git

   In [ ]

!git clone https://github.com/PaddlePaddle/PaddleSeg.git

   In [9]

!unzip -q data/data149927/PaddleSeg-release-2.5.zip -d ./

   

3.2.3 开始训练

使用PaddleSeg时的配置信息是采用yml文件描述的,这里使用的是unet.yml文件.

In [3]

## 使用U-net进行训练!python PaddleSeg-release-2.5/train.py --config unet.yml --save_interval 2000

   

3.2.4 开始预测

In [11]

## 将测试图片拷贝到新建的文件夹中import osimport shutilif not os.path.exists('test_imgs'):    os.mkdir('test_imgs')with open('test.txt', 'r') as f:    paths = f.readlines()    i = 0    for path in paths:        img, label = path.strip().split(' ')        shutil.copy(img, 'test_imgs/t'+str(i)+'.png')        i += 1

   In [12]

## 将标签图片拷贝到新建的文件夹中if not os.path.exists('label_imgs'):    os.mkdir('label_imgs')with open('test.txt', 'r') as f:    paths = f.readlines()    i = 0    for path in paths:        img, label = path.strip().split(' ')        label = label.replace('result.png', 'label.png')        shutil.copy(label, 'label_imgs/t'+str(i)+'.png')        i += 1

   In [4]

## 开始预测并保存预测后的图片!python PaddleSeg-release-2.5/predict.py --image_path test_imgs --model_path output/iter_10000/model.pdparams --save_dir saved_imges --crop_size 512 512 --config unet.yml

   

3.2.5 结果可视化

In [15]

## 创建需要可视化的图片列表test_images = os.listdir('test_imgs')label_images = os.listdir('label_imgs')predicted_images = os.listdir('saved_imges/pseudo_color_prediction')test_images = ['test_imgs/' + path for path in test_images if not path.startswith('.')]label_images = ['label_imgs/' + path for path in label_images if not path.startswith('.')]predicted_images = ['saved_imges/pseudo_color_prediction/' + path for path in predicted_images if not path.startswith('.')]test_images.sort()label_images.sort()predicted_images.sort()

   In [16]

## 开始可视化from paddle.vision.transforms import transforms as Timport matplotlib.pyplot as pltfrom PIL import Image as PilImageimport numpy as npplt.figure(figsize=(10, 10))IMAGE_SIZE = (224, 224)i = 0for j in range(len(test_images)):    test_path = test_images[j]    label_path = label_images[j]    predicted_path = predicted_images[j]    resize_t = T.Compose([        T.Resize(IMAGE_SIZE)    ])    image = resize_t(PilImage.open(test_path))    label = resize_t(PilImage.open(label_path))    predicted = resize_t(PilImage.open(predicted_path))    image = np.array(image).astype('uint8')    label = np.array(label).astype('uint8')    predicted = np.array(predicted).astype('uint8')    if i > 8:         break    plt.subplot(3, 3, i + 1)    plt.imshow(image)    plt.title('Input Image')    plt.axis("off")    plt.subplot(3, 3, i + 2)    plt.imshow(label, cmap='gray')    plt.title('Label')    plt.axis("off")    plt.subplot(3, 3, i + 3)    plt.imshow(predicted, cmap='gray')    plt.title('Predict')    plt.axis("off")    i += 3    j += 1plt.show()

       

               

3.3 基于PaddleX 2.1 API使用U-Net网络实现鸽子图像的语义分割任务

3.3.1 创建PaddleX需要的数据文件

PaddleX需要一些训练预测的数据文件,如labels.txt, train_list.txt,val_list.txt。我们已经创建了train.txt, eval.text和test.txt。现在只需要创建labels.txt。

In [1]

with open('labels.txt', 'w') as f:    f.writelines(['backgroundn', 'dove'])

   

3.3.2 安装PaddleX

In [5]

!pip install paddlex==2.1.0 -i https://mirror.baidu.com/pypi/simple

   

3.3.3 开始训练

In [6]

import paddlex as pdxfrom paddlex import transforms as Ttrain_transforms = T.Compose([    T.Resize(target_size=512),    T.RandomHorizontalFlip(),    T.Normalize(        mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),])eval_transforms = T.Compose([    T.Resize(target_size=512),    T.Normalize(        mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),])

   In [4]

train_dataset = pdx.datasets.SegDataset(    data_dir='./',    file_list='./train.txt',    label_list='./labels.txt',    transforms=train_transforms,    shuffle=True)eval_dataset = pdx.datasets.SegDataset(    data_dir='./',    file_list='./eval.txt',    label_list='./labels.txt',    transforms=eval_transforms,    shuffle=False)

       

2022-06-14 13:45:19 [INFO]110 samples in file ./train.txt2022-06-14 13:45:19 [INFO]12 samples in file ./eval.txt

       In [7]

num_classes = len(train_dataset.labels)model = pdx.seg.UNet(num_classes=num_classes)

       

W0614 13:47:08.356240   103 gpu_context.cc:278] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1W0614 13:47:08.361294   103 gpu_context.cc:306] device: 0, cuDNN Version: 7.6.

       In [7]

model.train(    num_epochs=100,    train_dataset=train_dataset,    train_batch_size=16,    eval_dataset=eval_dataset,    save_interval_epochs=10,    log_interval_steps=20,    learning_rate=0.01,    save_dir='output/unet')

   

3.3.4 开始预测

In [13]

import os## 创建需要预测的图片列表test_images = os.listdir('test_imgs')test_images = ['test_imgs/' + path for path in test_images if not path.startswith('.')]test_images.sort()

   In [8]

model = pdx.load_model('output/unet/best_model')for test_image in test_images:    result = model.predict(test_image)    pdx.seg.visualize(test_image, result, weight=0.0, save_dir='./result_imgs')

   

3.3.5 结果可视化

In [19]

## 创建需要可视化的图片列表label_images = os.listdir('label_imgs')predicted_images = os.listdir('result_imgs')label_images = ['label_imgs/' + path for path in label_images if not path.startswith('.')]predicted_images = ['result_imgs/' + path for path in predicted_images if not path.startswith('.')]label_images.sort()predicted_images.sort()

   In [24]

%matplotlib inline

   In [25]

## 开始可视化from paddle.vision.transforms import transforms as Timport matplotlib.pyplot as pltfrom PIL import Image as PilImageimport numpy as npplt.figure(figsize=(10, 10))IMAGE_SIZE = (512, 512)i = 0for j in range(len(test_images)):    test_path = test_images[j]    label_path = label_images[j]    predicted_path = predicted_images[j]    resize_t = T.Compose([        T.Resize(IMAGE_SIZE)    ])    image = resize_t(PilImage.open(test_path))    label = resize_t(PilImage.open(label_path))    predicted = resize_t(PilImage.open(predicted_path))    image = np.array(image).astype('uint8')    label = np.array(label).astype('uint8')    predicted = np.array(predicted).astype('uint8')    if i > 8:         break    plt.subplot(3, 3, i + 1)    plt.imshow(image)    plt.title('Input Image')    plt.axis("off")    plt.subplot(3, 3, i + 2)    plt.imshow(label, cmap='gray')    plt.title('Label')    plt.axis("off")    plt.subplot(3, 3, i + 3)    plt.imshow(predicted, cmap='gray')    plt.title('Predict')    plt.axis("off")    i += 3    j += 1plt.show()

       

               

以上就是零基础入门图像分割:从数据到预测的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/53729.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
原神浏览器账号更换流程_原神账号切换操作攻略
上一篇 2025年11月9日 11:44:07
重新表述的标题为:Rarely Used jQuery Selectors
下一篇 2025年11月9日 11:44:10

相关推荐

  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 利用海象运算符简化条件赋值:Python教程与最佳实践

    本文旨在探讨Python中海象运算符(:=)在条件赋值场景下的应用。通过对比传统if/else语句与海象运算符,以及条件表达式,分析海象运算符在简化代码、提高可读性方面的优势与局限性。并通过具体示例,展示如何在列表推导式等场景下合理使用海象运算符,同时强调其潜在的复杂性及替代方案,帮助开发者更好地掌…

    2026年5月10日
    000
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    000
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000
  • Python命令怎样使用profile分析脚本性能 Python命令性能分析的基础教程

    使用Python的cProfile模块分析脚本性能最直接的方式是通过命令行执行python -m cProfile your_script.py,它会输出每个函数的调用次数、总耗时、累积耗时等关键指标,帮助定位性能瓶颈;为进一步分析,可将结果保存为文件python -m cProfile -o ou…

    2026年5月10日
    000
  • 使用 WebCodecs VideoDecoder 实现精确逐帧回退

    本文档旨在解决在使用 WebCodecs VideoDecoder 进行视频解码时,实现精确逐帧回退的问题。通过比较帧的时间戳与目标帧的时间戳,可以避免渲染中间帧,从而提高用户体验。本文将提供详细的解决方案和示例代码,帮助开发者实现精确的视频帧控制。 在使用 WebCodecs VideoDecod…

    2026年5月10日
    000
  • 如何插入查询结果数据_SQL插入Select查询结果方法

    如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法

    使用INSERT INTO…SELECT语句可高效插入数据,通过NOT EXISTS、LEFT JOIN、MERGE语句或唯一约束避免重复;表结构不一致时可通过别名、类型转换、默认值或计算字段处理;结合存储过程可提升可维护性,支持参数化与动态SQL。 将查询结果数据插入到另一个表中,可以…

    2026年5月10日 用户投稿
    000
  • Debian Copilot的社区活跃度如何

    debian copilot是codeberg社区维护的ai助手,旨在为debian用户提供服务。尽管搜索结果中没有直接提供关于debian copilot社区支持活跃度的具体数据,但我们可以通过debian社区的整体活跃度和特点来推断其活跃性。 Debian社区的一般情况: Debian拥有详尽的…

    2026年5月10日
    000
  • Discord.py 交互按钮超时与持久化解决方案

    本教程旨在解决Discord.py中交互按钮在一段时间后出现“This Interaction Failed”错误的问题。我们将深入探讨视图(View)的超时机制,并提供通过正确设置timeout参数以及利用bot.add_view()方法实现按钮持久化的具体方案,确保您的机器人交互功能稳定可靠,即…

    2026年5月10日
    000
  • Python递归函数追踪与性能考量:以序列打印为例

    本文深入探讨了Python中一种递归打印序列元素的方法,并着重演示了如何通过引入缩进参数来有效追踪递归函数的执行流程和参数变化。通过实际代码示例,文章揭示了递归调用可能带来的潜在性能开销,特别是对调用栈空间的需求,以及Python默认递归深度限制可能导致的错误,为读者提供了理解和优化递归算法的实用见…

    2026年5月10日
    000
  • python中zip函数详解 python多序列压缩zip函数应用场景

    zip函数的应用场景包括:1) 同时遍历多个序列,2) 合并多个列表的数据,3) 数据分析和科学计算中的元素运算,4) 处理csv文件,5) 性能优化。zip函数是一个强大的工具,能够简化代码并提高处理多个序列时的效率。 在Python中,zip函数是一个非常有用的工具,它能够将多个可迭代对象打包成…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信