.. _seo, ec_manm_segmentation:
Segmentação Semântica e o *Dataset*
===================================
no discussãoobr os problemas de detecção de objetos nas seções
anteriores, usamos apenas caixas delimitadoras retangulares para
rotulares ola pre objets em imagens. Nesta seção, veremos a segmentação
semâo semntica, que tenta, tet segmentar imagens res m dierentes
categorias semânticas. Essas regiões semânticas rotulam e prevêem
objetos no nível do pixel. :numref:`fig_segmentation` ostra uma
imagemeamente segmentada, com áreas marcadas como “cachorro” , “gato” e
“fundo”. Como você pode ver, em comparação com a detecção de objetos, a
segmentação semântica rotula áreas com bordas em nível de pixel, para
uma precisão significativamente maior.
.. _fig_segmentation:
.. figure:: ../img/segmentation.svg
Imagem segmentada semanticamente, com áreas rotuladas
“cachorroSemantiatiamente mio”, “gcato” e “plano de f”oundo".
Segmentação de Imagem e Segmentação detion and Instâancia
---------------------------------------------------------
No campo da visão computacional, existem dois métodos importantes
relacionados à segmentaçãe Segmenntica: segmentação detion: imagens e
segmentação detion and instâancias. Aqui, vamos distinguir esses
conceitos da segmentação semântica da seguinte forma:
- A segmenta imagmgmen divide umas an imagem em várias regiões into
sconstituente mét regioodo geramente usa as correlações entrel pixels
ain an imagem. Durante oing treainamento, os rótulos não são
necessários para pixels de imagem. No entanto, durante a previsão,
esse método não pode garantir que as regiões segmentadas ain semntic
imagem em .10, amage segmentação da imagem pode dividir o cão em duas
regionsmaone cobverindo a boca do cão e os olhos onde o preto é a
corth and eyes where black is the proeminente e a outra color and the
other cobverindo o resto do cão onde o amarelo é a corg the rest of
the dog where yellow is the proeminente.
- A segmentação da instância também é chamada de detecção e segmentação
simultâneas. Este método tenta identificar as regiões de nível de
pixel de cada color.
- Instance segmentation is also called simultaneous detection and
segmentation. This method attempts to identify the pixel-level
regions of each object instâancia de objeto em umae in an prominent
corin prominent instnc imagem.mIn cont semnticraste com a segmentação
semântica, a segmentação de instância não apenas sgmentation
distinguhes semâanticas, ms o differetes instane objeto. Se umaes. I
imagem contém dois cães, a segmentação de instância distingue quais
pixels pertencem a cada cachorro.
O Conjunto de Dados de Segmentação Semântica Pascal VOC2012
-----------------------------------------------------------
No campo de segmentaçãoains two dogswill distinguish which pixels belong
to which dog.
The Pascal VOC2012 Semantic Segmentation Dataset
------------------------------------------------
In the semâantica, um conjunto de dados importante é segmentation field,
one important dataset is `Pascal
VOC2012 `__. Para
entender melhor este conjunto de dados, devemos primeirootkage our
móoduloe necessário para oeded for t experimento.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import os
from mxnet import gluon, image, np, npx
from d2l import mxnet as d2l
npx.set_np()
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import os
import torch
import torchvision
from d2l import torch as d2l
.. raw:: html
.. raw:: html
O site original pode ser instável, portanto, baixamos os dados de um
site espelho. O arquivo tem cerca de 2 GB, por isso levará algum tempo
para fazer the arquchivoe, o conjunto de dados está localizado noo
download. decomp mi ``../data/VOCdevkit/VOC2012``.
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['voc2012'] = (d2l.DATA_URL + 'VOCtrainval_11-May-2012.tar',
'4e443f8a2eca6b1dac8a6c57641b67dd40621a49')
voc_dir = d2l.download_extract('voc2012', 'VOCdevkit/VOC2012')
.. parsed-literal::
:class: output
Downloading ../data/VOCtrainval_11-May-2012.tar from http://d2l-data.s3-accelerate.amazonaws.com/VOCtrainval_11-May-2012.tar...
.. raw:: html
.. raw:: html
.. code:: python
#@save
d2l.DATA_HUB['voc2012'] = (d2l.DATA_URL + 'VOCtrainval_11-May-2012.tar',
'4e443f8a2eca6b1dac8a6c57641b67dd40621a49')
voc_dir = d2l.download_extract('voc2012', 'VOCdevkit/VOC2012')
.. parsed-literal::
:class: output
Downloading ../data/VOCtrainval_11-May-2012.tar from http://d2l-data.s3-accelerate.amazonaws.com/VOCtrainval_11-May-2012.tar...
.. raw:: html
.. raw:: html
Vá para ``../data/VOCdevkit/VOC2012`` para ver as diferentes partes do
conjunto de dados. O caminho ``ImageSets/Segmentation`` contém arquivos
de texto que especificam os exemplos de treainamento e teste. Os cin
``JPEGImages`` e\ ``SegmentationClass`` contêm aspaths contain the
example input imagens de entrada de exemplo e rótulos, respectivamente.
Essas etiquetas também estão em formato de imagem, com as mesmasand
labels, respectively. These labels are also in image format, with the
same images dimensõei das put imagens de entrada às quais correspondem.
Nos rótulos, os pixels com a mesma cor pertencem à mesma.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def read_voc_images(voc_dir, is_train=True):
"""Read all VOC feature and label images."""
txt_fname = os.path.join(voc_dir, 'ImageSets', 'Segmentation',
'train.txt' if is_train else 'val.txt')
with open(txt_fname, 'r') as f:
images = f.read().split()
features, labels = [], []
for i, fname in enumerate(images):
features.append(image.imread(os.path.join(
voc_dir, 'JPEGImages', f'{fname}.jpg')))
labels.append(image.imread(os.path.join(
voc_dir, 'SegmentationClass', f'{fname}.png')))
return features, labels
train_features, train_labels = read_voc_images(voc_dir, True)
.. raw:: html
.. raw:: html
.. code:: python
#@save
def read_voc_images(voc_dir, is_train=True):
"""Read all VOC feature and label images."""
txt_fname = os.path.join(voc_dir, 'ImageSets', 'Segmentation',
'train.txt' if is_train else 'val.txt')
mode = torchvision.io.image.ImageReadMode.RGB
with open(txt_fname, 'r') as f:
images = f.read().split()
features, labels = [], []
for i, fname in enumerate(images):
features.append(torchvision.io.read_image(os.path.join(
voc_dir, 'JPEGImages', f'{fname}.jpg')))
labels.append(torchvision.io.read_image(os.path.join(
voc_dir, 'SegmentationClass' ,f'{fname}.png'), mode))
return features, labels
train_features, train_labels = read_voc_images(voc_dir, True)
.. raw:: html
.. raw:: html
Desenhamos as primeiras cincoWe draw the first five input imagens de
entrada e seus rótulos. Nas imagens do rótulo, o brancoand their labels.
In the label images, white representa as bordas e o preto representa o
fers and black represents the backgroundo. Outras corether colors
correspondem a diferentes categorias.
.. raw:: html
.. raw:: html
.. code:: python
n = 5
imgs = train_features[0:n] + train_labels[0:n]
d2l.show_images(imgs, 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_30_0.png
.. raw:: html
.. raw:: html
.. code:: python
n = 5
imgs = train_features[0:n] + train_labels[0:n]
imgs = [img.permute(1,2,0) for img in imgs]
d2l.show_images(imgs, 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_33_0.png
.. raw:: html
.. raw:: html
A seguir, listamos cada valor de cor RGB nos rótulos e as categoriaes
que eles rl.
.. raw:: html
.. raw:: html
.. code:: python
#@save
VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
[0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],
[64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],
[64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],
[0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],
[0, 64, 128]]
#@save
VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person',
'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']
.. raw:: html
.. raw:: html
.. code:: python
#@save
VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],
[0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],
[64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],
[64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],
[0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],
[0, 64, 128]]
#@save
VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person',
'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']
.. raw:: html
.. raw:: html
Depois de definir as duasAfter defining the two constantes acima,
podemos encontrar facilmente o índice de categoria para cada pixel nos
rótulobove, we can easily find the category index for each pixel in the
labels.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def build_colormap2label():
"""Build an RGB color to label mapping for segmentation."""
colormap2label = np.zeros(256 ** 3)
for i, colormap in enumerate(VOC_COLORMAP):
colormap2label[(colormap[0]*256 + colormap[1])*256 + colormap[2]] = i
return colormap2label
#@save
def voc_label_indices(colormap, colormap2label):
"""Map an RGB color to a label."""
colormap = colormap.astype(np.int32)
idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256
+ colormap[:, :, 2])
return colormap2label[idx]
.. raw:: html
.. raw:: html
.. code:: python
#@save
def build_colormap2label():
"""Build an RGB color to label mapping for segmentation."""
colormap2label = torch.zeros(256 ** 3, dtype=torch.long)
for i, colormap in enumerate(VOC_COLORMAP):
colormap2label[(colormap[0]*256 + colormap[1])*256 + colormap[2]] = i
return colormap2label
#@save
def voc_label_indices(colormap, colormap2label):
"""Map an RGB color to a label."""
colormap = colormap.permute(1,2,0).numpy().astype('int32')
idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256
+ colormap[:, :, 2])
return colormap2label[idx]
.. raw:: html
.. raw:: html
PFor exeamploe, na primeira imagem dein the first exeamplo, o índice de
categoria para a parte frontal do avião é 1 e o índice para o fundo ée
image, the cat 0.
.. raw:: html
.. raw:: html
.. code:: python
y = voc_label_indices(train_labels[0], build_colormap2label())
y[105:115, 130:140], VOC_CLASSES[1]
.. parsed-literal::
:class: output
(array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 1.]]),
'aeroplane')
.. raw:: html
.. raw:: html
.. code:: python
y = voc_label_indices(train_labels[0], build_colormap2label())
y[105:115, 130:140], VOC_CLASSES[1]
.. parsed-literal::
:class: output
(tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]),
'aeroplane')
.. raw:: html
.. raw:: html
Pré-processamento de Dados
~~~~~~~~~~~~~~~~~~~~~~~~~~
NosData Preprocessing
In the preceding chapítulos anteriores, dimensionamos asters, we scaled
imagens para que se ajustassem à forma de entrada doto make them fit the
inputmodelo. NaIn segmentação semântica, esse método exigiria que
mapeamos novamente as categorias de pixels previstas de volta à imagem
de entrada do tamanho original. Seria muito difícil fazer isso commantic
segmentation, this method would require us to re-map the predicted pixel
categories back to the original-size input image. It would be very
difficult to do this precisãoely, especialmente em regiões segmentadas
com semânticasly in segmented regions with differentes. Para evitar esse
semantics. To avoid this problema, recortamos aswe crop the imagens para
definir as dimensões e não as dimensionamos. Especificamente, usamos o
método de corte aleatório usado no aumento da imagem para cortar a mesma
região dasto set dimensions and do not scale them. Specifically, we use
the random cropping method used in image augmentation to crop the same
region from input imagens de entrada e seus rótuloand their labels.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_rand_crop(feature, label, height, width):
"""Randomly crop for both feature and label images."""
feature, rect = image.random_crop(feature, (width, height))
label = image.fixed_crop(label, *rect)
return feature, label
imgs = []
for _ in range(n):
imgs += voc_rand_crop(train_features[0], train_labels[0], 200, 300)
d2l.show_images(imgs[::2] + imgs[1::2], 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_66_0.png
.. raw:: html
.. raw:: html
.. code:: python
#@save
def voc_rand_crop(feature, label, height, width):
"""Randomly crop for both feature and label images."""
rect = torchvision.transforms.RandomCrop.get_params(feature,
(height, width))
feature = torchvision.transforms.functional.crop(feature, *rect)
label = torchvision.transforms.functional.crop(label, *rect)
return feature, label
imgs = []
for _ in range(n):
imgs += voc_rand_crop(train_features[0], train_labels[0], 200, 300)
imgs = [img.permute(1,2,0) for img in imgs]
d2l.show_images(imgs[::2] + imgs[1::2], 2, n);
.. figure:: output_semantic-segmentation-and-dataset_23ff18_69_0.png
.. raw:: html
.. raw:: html
*Datasets* para Segmentação Semântica Personalizada
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Usamos a classe ``Dataset`` herdada fornecida pelo Gluon para
personalizar a classe de conjunto de dados de segmentação semântica
``VOCSegDataset``. IBy implementando a funçãoing the ``__getitem__``,
podemos acessar arbitrariamente a imagem de entrada com o índice ``idx``
e os índices de categoria para cada um de seus pixels do conjunto de
dados. Como algumas function, we can arbitrarily access the input image
with the index ``idx`` and the category indexes for each of its pixels
from the dataset. As some imagens no conjunto de dados podem ser menores
do que as dimensões de saída especificadas para corte aleatório, devemos
remover essesin the dataset may be smaller than the output dimensions
specified for random cropping, we must remove these exeamplos usando uma
função ``filter`` personalizada. Além disso, definimos a função
``normalize_image`` para normalizar cada um dos três canais RGB das
imagens de entradae by using a custom ``filter`` function. In addition,
we define the ``normalize_image`` function to normalize each of the
three RGB channels of the input images.
.. raw:: html
.. raw:: html
.. code:: python
#@save
class VOCSegDataset(gluon.data.Dataset):
"""A customized dataset to load VOC dataset."""
def __init__(self, is_train, crop_size, voc_dir):
self.rgb_mean = np.array([0.485, 0.456, 0.406])
self.rgb_std = np.array([0.229, 0.224, 0.225])
self.crop_size = crop_size
features, labels = read_voc_images(voc_dir, is_train=is_train)
self.features = [self.normalize_image(feature)
for feature in self.filter(features)]
self.labels = self.filter(labels)
self.colormap2label = build_colormap2label()
print('read ' + str(len(self.features)) + ' examples')
def normalize_image(self, img):
return (img.astype('float32') / 255 - self.rgb_mean) / self.rgb_std
def filter(self, imgs):
return [img for img in imgs if (
img.shape[0] >= self.crop_size[0] and
img.shape[1] >= self.crop_size[1])]
def __getitem__(self, idx):
feature, label = voc_rand_crop(self.features[idx], self.labels[idx],
*self.crop_size)
return (feature.transpose(2, 0, 1),
voc_label_indices(label, self.colormap2label))
def __len__(self):
return len(self.features)
.. raw:: html
.. raw:: html
.. code:: python
#@save
class VOCSegDataset(torch.utils.data.Dataset):
"""A customized dataset to load VOC dataset."""
def __init__(self, is_train, crop_size, voc_dir):
self.transform = torchvision.transforms.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
self.crop_size = crop_size
features, labels = read_voc_images(voc_dir, is_train=is_train)
self.features = [self.normalize_image(feature)
for feature in self.filter(features)]
self.labels = self.filter(labels)
self.colormap2label = build_colormap2label()
print('read ' + str(len(self.features)) + ' examples')
def normalize_image(self, img):
return self.transform(img.float())
def filter(self, imgs):
return [img for img in imgs if (
img.shape[1] >= self.crop_size[0] and
img.shape[2] >= self.crop_size[1])]
def __getitem__(self, idx):
feature, label = voc_rand_crop(self.features[idx], self.labels[idx],
*self.crop_size)
return (feature, voc_label_indices(label, self.colormap2label))
def __len__(self):
return len(self.features)
.. raw:: html
.. raw:: html
Lendo oReading the Dataset
~~~~~~~~~~~~~~~~~~~~~~~~~~
Usando a classeing the custom ``VOCSegDataset`` personalizada, criamos o
conjunto dclass, we create the treainamento e as instâncias do conjunto
de teste. Assumimos que a operação de corte aleatório produzing set and
testing set instances. We assume the random cropping operation output
imagens no formatoin the shape :math:`320\times 480`. Abaixo, podemos
ver o número deBelow, we can see the number of exeamploes retidos nos
conjuntos dained in the treainamento e testeing and testing sets.
.. raw:: html
.. raw:: html
.. code:: python
crop_size = (320, 480)
voc_train = VOCSegDataset(True, crop_size, voc_dir)
voc_test = VOCSegDataset(False, crop_size, voc_dir)
.. parsed-literal::
:class: output
read 1114 examples
read 1078 examples
.. raw:: html
.. raw:: html
.. code:: python
crop_size = (320, 480)
voc_train = VOCSegDataset(True, crop_size, voc_dir)
voc_test = VOCSegDataset(False, crop_size, voc_dir)
.. parsed-literal::
:class: output
read 1114 examples
read 1078 examples
.. raw:: html
.. raw:: html
Definimos o tamanho do lote comWe set the batch size to 64 eand
definimos ose the iteradtores para os conjuntos dfor the treainamento e
teste. Imprimimos a forma do primeiroing and testing sets. Print the
shape of the first minibatch. EmIn contraste com a to image
classificação de imagens e o reconhecimento de objetos, os rótulos aqui
são matrizes trition and object recognition, labels here are
three-dimensionail arrays.
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 64
train_iter = gluon.data.DataLoader(voc_train, batch_size, shuffle=True,
last_batch='discard',
num_workers=d2l.get_dataloader_workers())
for X, Y in train_iter:
print(X.shape)
print(Y.shape)
break
.. parsed-literal::
:class: output
(64, 3, 320, 480)
(64, 320, 480)
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 64
train_iter = torch.utils.data.DataLoader(voc_train, batch_size, shuffle=True,
drop_last=True,
num_workers=d2l.get_dataloader_workers())
for X, Y in train_iter:
print(X.shape)
print(Y.shape)
break
.. parsed-literal::
:class: output
torch.Size([64, 3, 320, 480])
torch.Size([64, 320, 480])
.. raw:: html
.. raw:: html
Juntando Tudo
~~~~~~~~~~~~~
Finalmente, definimos uma função ``load_data_voc`` que baixa e carrega
este \*Putting All Things Together
Finally, we define a function ``load_data_voc`` that downloads and loads
this dataset*, e entãoand then retourna oss the data iteradtores de
dados.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def load_data_voc(batch_size, crop_size):
"""Download and load the VOC2012 semantic dataset."""
voc_dir = d2l.download_extract('voc2012', os.path.join(
'VOCdevkit', 'VOC2012'))
num_workers = d2l.get_dataloader_workers()
train_iter = gluon.data.DataLoader(
VOCSegDataset(True, crop_size, voc_dir), batch_size,
shuffle=True, last_batch='discard', num_workers=num_workers)
test_iter = gluon.data.DataLoader(
VOCSegDataset(False, crop_size, voc_dir), batch_size,
last_batch='discard', num_workers=num_workers)
return train_iter, test_iter
.. raw:: html
.. raw:: html
.. code:: python
#@save
def load_data_voc(batch_size, crop_size):
"""Download and load the VOC2012 semantic dataset."""
voc_dir = d2l.download_extract('voc2012', os.path.join(
'VOCdevkit', 'VOC2012'))
num_workers = d2l.get_dataloader_workers()
train_iter = torch.utils.data.DataLoader(
VOCSegDataset(True, crop_size, voc_dir), batch_size,
shuffle=True, drop_last=True, num_workers=num_workers)
test_iter = torch.utils.data.DataLoader(
VOCSegDataset(False, crop_size, voc_dir), batch_size,
drop_last=True, num_workers=num_workers)
return train_iter, test_iter
.. raw:: html
.. raw:: html
Resumo
------
- A segmentação semântica analisa como asSummary
- Semantic segmentation looks at how imagens podem ser segmentadas em
regiões comcan be segmented into regions with differentes categorias
semânticas.
- No campo de segmentação semântica, um conjunto de dados importante é
semantic categories.
- In the semantic segmentation field, one important dataset is Pascal
VOC2012.
- Como asBecause the input imagens e rótulos de entrada na segmentação
semântica têm umaand labels in semantic segmentation have a
one-to-one correspondêencia um a um no nível do pixel, nós os
cortamos aleatoriamente em um tamanho fixo, em vez de dimensioná-lose
at the pixel level, we randomly crop them to a fixed size, rather
than scaling them.
Exercícioises
-------------
1. Lembre-se do conteúdo que vimos emRecall the content we covered in
:numref:`sec_image_augmentation`. Qual dos métodos dWhich of the
image augmento de imagem usados na classificação de imagens seria
difícil de usar na segmentação semânticaation methods used in image
classification would be hard to use in semantic segmentation?
.. raw:: html
.. raw:: html
`Discussõeions `__
.. raw:: html
.. raw:: html
`Discussõeions `__
.. raw:: html
.. raw:: html
.. raw:: html