繁体   English   中英

Python 用于分割的图像类型、形状和通道

[英]Python image types, shapes, and channels for segmentation

我正在使用本教程在 PyTorch 中进行实例分割。 本教程使用的测试数据包括来自此处可用数据集的图像和随附的图像掩码。 我有一个来自该数据集的图像掩码示例here (此问题的示例数据)。 默认情况下,该掩码在数据集中如下所示:

在此处输入图像描述

本教程使用以下代码

mask.putpalette([
    0, 0, 0, # black background
    255, 0, 0, # index 1 is red
    255, 255, 0, # index 2 is yellow
    255, 153, 0, # index 3 is orange
])

作为掩码的解释步骤,使其看起来像这样:

在此处输入图像描述

但是该代码在分段过程本身中不是必需的。 它只是用来显示面具包含的内容。

我正在尝试使用我自己的图像数据。 我在GIMP中为图像创建了蒙版 这是我制作的蒙版之一 默认情况下看起来像这样。

在此处输入图像描述

当我尝试运行教程代码时,我遇到了面具问题。 此代码块创建一个 class,它创建 PyTorch 数据集。

import os
import numpy as np
import torch
import torch.utils.data
from PIL import Image


class PennFudanDataset(torch.utils.data.Dataset):
    def __init__(self, root, transforms=None):
        self.root = root
        self.transforms = transforms
        # load all image files, sorting them to
        # ensure that they are aligned
        self.imgs = list(sorted(os.listdir(os.path.join(root, "PNGImages"))))
        self.masks = list(sorted(os.listdir(os.path.join(root, "PedMasks"))))

    def __getitem__(self, idx):
        # load images ad masks
        img_path = os.path.join(self.root, "PNGImages", self.imgs[idx])
        mask_path = os.path.join(self.root, "PedMasks", self.masks[idx])
        img = Image.open(img_path).convert("RGB")
        # note that we haven't converted the mask to RGB,
        # because each color corresponds to a different instance
        # with 0 being background
        mask = Image.open(mask_path)

        mask = np.array(mask)
        # instances are encoded as different colors
        obj_ids = np.unique(mask)
        # first id is the background, so remove it
        obj_ids = obj_ids[1:]

        # split the color-encoded mask into a set
        # of binary masks
        masks = mask == obj_ids[:, None, None]

        # get bounding box coordinates for each mask
        num_objs = len(obj_ids)
        boxes = []
        for i in range(num_objs):
            pos = np.where(masks[i])
            xmin = np.min(pos[1])
            xmax = np.max(pos[1])
            ymin = np.min(pos[0])
            ymax = np.max(pos[0])
            boxes.append([xmin, ymin, xmax, ymax])

        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        # there is only one class
        labels = torch.ones((num_objs,), dtype=torch.int64)
        masks = torch.as_tensor(masks, dtype=torch.uint8)

        image_id = torch.tensor([idx])
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        # suppose all instances are not crowd
        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)

        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["masks"] = masks
        target["image_id"] = image_id
        target["area"] = area
        target["iscrowd"] = iscrowd

        if self.transforms is not None:
            img, target = self.transforms(img, target)

        return img, target

    def __len__(self):
        return len(self.imgs)

dataset = PennFudanDataset('PennFudanPed/')
dataset[0]

最后一行返回:

(<PIL.Image.Image image mode=RGB size=559x536 at 0x7FCB4267C390>,
 {'area': tensor([35358., 36225.]), 'boxes': tensor([[159., 181., 301., 430.],
          [419., 170., 534., 485.]]), 'image_id': tensor([0]), 'iscrowd': tensor([0, 0]), 'labels': tensor([1, 1]), 'masks': tensor([[[0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           ...,
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0]],
  
          [[0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           ...,
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0],
           [0, 0, 0,  ..., 0, 0, 0]]], dtype=torch.uint8)})

当我用我的数据运行这段代码时,

...
dataset = four_chs('drive/MyDrive/chambers/')
dataset[0]

我收到此错误:

/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:38: DeprecationWarning: elementwise comparison failed; this will raise an error in the future.

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-17-12074ae9ab35> in <module>()
      1 len(dataset)
----> 2 dataset[0]

<ipython-input-1-99ab92a46ebe> in __getitem__(self, idx)
     42         boxes = []
     43         for i in range(num_objs):
---> 44             pos = np.where(masks[i])
     45             xmin = np.min(pos[1])
     46             xmax = np.max(pos[1])

TypeError: 'bool' object is not subscriptable

我不确定到底发生了什么,但我的掩码与测试数据中的掩码之间存在差异。 它们都是PNG文件类型,但似乎我的红色,蓝色,绿色通道与另一个通道或其他东西分开,但我不知道它是什么,基于Python中的object的形状。 这来自我制作的一个面具:

mask2 = np.array(mask1)
mask2.shape
(5312, 2988, 4)

对于测试数据掩码之一:

mask2 = np.array(mask)
mask2.shape
(536, 559)

好像只有一个频道? 因此,由于它们的形状不同,我想这就是为什么我会从中得到错误(这是我之前粘贴的代码的摘录)

...
        mask_path = os.path.join(self.root, "masks", self.masks[idx])
        # note that we haven't converted the mask to RGB,
        # because each color corresponds to a different instance
        # with 0 being background
        mask = Image.open(mask_path)

        mask = np.array(mask)
        # instances are encoded as different colors
        obj_ids = np.unique(mask)
        # first id is the background, so remove it
        obj_ids = obj_ids[1:]

        # split the color-encoded mask into a set
        # of binary masks
        masks = mask == obj_ids[:, None, None]

        # get bounding box coordinates for each mask
        num_objs = len(obj_ids)
for i in range(num_objs):
             pos = np.where(masks[i])
...

如何让我的掩码形状与测试数据中的掩码形状相匹配,以便我可以使用分段代码的 rest 创建与分段算法一起使用的 PyTorch 兼容数据集? 我不是想获得相同的高度和宽度,而是改变通道/层的数量,但我不认为我希望它是灰度的。

在 HansHirse 发表评论后进行编辑:

我回到 GIMP 并使用图像模式菜单将图像更改为灰度。 我使用该设置导出。 我尝试使用该文件运行代码,但它不起作用。

我还找到了一种在使用Image.open().convert("L")导入时将 R.BG 图像转换为灰度的方法。 这也不起作用。

在这两种情况下,问题都与我认为是分开的 colors 的斑点有关。 例如,我使用 HansHirse 的建议用 1、2、3 和 4 的灰色“颜色”填充感兴趣的区域,而背景保持为 0。导入创建的文件后,这些文件的值为 3, 5,8 和 10。虽然其中一个形状的值可能大部分为 3,但在其他形状中有具有该值的 vagrant 像素,因此没有值完全包含在一个形状中。 在这种情况下,代码会绘制包围所有 4 个形状的边界框,而不是围绕一个形状。

我知道使用色调、饱和度、值 (HSV) 颜色空间并尝试转换为该颜色空间。 这仍然不能解决我的问题。

我试图弄清楚如何使用类似的东西

np.where( mask[<buffered shape1 xmin>,<buffered shape1 xmax>, <buffered shape1 ymin>, <buffered shape1 ymax>,0] == <majority color value for shape>)

对遮罩进行四分之一排序,根据该季度中该形状的主颜色值进行过滤,并获取该季度中该形状的实际 x 和 y 值。 有了这些值,我想我可以使用实际值中的最小值和最大值来创建我的边界框。

另外需要注意的是,从 GIMP 导出时,导出 window 中有一个下拉菜单可以将文件设置为 8 位 R.GB 或 Gray。 Select 8bpc 灰色,用于所需格式。

以下是如何为分割任务或类似任务创建表示类的灰度图像的示例。

在一些黑色背景上,绘制一些填充值在1, ..., #classes范围内的形状。 出于可视化目的,此蒙版被绘制为感知为常规灰度图像并缩放到所述值范围 - 以强调蒙版通常看起来全黑,但其中包含实际内容。 此蒙版保存为无损 PNG 图像,然后使用 Pillow 打开,并转换模式P 最后一步是为所需数量的 colors 设置适当的调色板,并使用Image.putpalette应用该调色板。

import cv2
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

# Generate mask:  0 - Background  |  1 - Class 1  |  2 - Class 2, and so on.
mask = np.zeros((300, 300), np.uint8)
cv2.rectangle(mask, (30, 40), (75, 60), 1, cv2.FILLED)
cv2.circle(mask, (230, 50), 85, 2, cv2.FILLED)
cv2.ellipse(mask, (230, 230), (60, 40), 0, 0, 360, 3, cv2.FILLED)
cv2.line(mask, (20, 240), (80, 260), 4, 5)

# Save mask as lossless PNG image
cv2.imwrite('mask.png', mask)

# Visualization
plt.figure(1, figsize=(18, 6))
plt.subplot(1, 3, 1), plt.imshow(mask, vmin=0, vmax=255, cmap='gray')
plt.colorbar(), plt.title('Mask when shown as regular image')
plt.subplot(1, 3, 2), plt.imshow(mask, cmap='gray')
plt.colorbar(), plt.title('Mask when shown scaled to values 0 - 4')

# Open mask with Pillow, and convert to mode 'P'
mask = Image.open('mask.png').convert('P')

# Set up and apply palette data
mask.putpalette([  0,   0,   0,         # Background - Black
                 255,   0,   0,         # Class 1 - Red
                   0, 255,   0,         # Class 2 - Green
                   0,   0, 255,         # Class 3 - Blue
                 255, 255,   0])        # Class 4 - Yellow

# More visualization
plt.subplot(1, 3, 3), plt.imshow(mask)
plt.title('Mask when shown as indexed image')
plt.tight_layout(), plt.show()

输出

当然,生成实际蒙版的第一步可以在 GIMP 中完成。 请务必使用黑色背景,并在1, ..., #classes范围内填充值。 如果您因为这些 colors 几乎都是黑色而难以做到这一点,请在一些明亮、可区分的 colors 中绘制您的形状,然后用值12等填充这些形状。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Matplotlib:    3.4.2
NumPy:         1.20.3
OpenCV:        4.5.2
Pillow:        8.2.0
----------------------------------------

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM