掩码R-CNN用于对象检测和分割[训练自定义数据集]

时间:2018-04-06 02:45:36

标签: python machine-learning computer-vision object-detection semantic-segmentation

我正在研究" Mask R-CNN进行对象检测和分割"。所以我已经阅读了原始研究论文,该论文提出Mask R-CNN用于对象检测,而且我发现很少有Mask R-CNNherehere的实现(由Facebook AI研究小组调用) detectron)。但他们都使用coco数据集进行测试。

但是,对于使用具有大量图像的自定义数据集进行上述实现的培训,我感到非常困惑,并且对于每个图像,存在用于在相应图像中标记对象的掩模图像的子集。

如果有人可以为此任务发布有用的资源或代码示例,我很高兴。

注意:我的数据集具有以下结构,

  

它包含大量图像和每个图像   是单独的图像文件,将对象突出显示为a中的白色补丁   黑色图像。

以下是一个示例图片及其面具:

图像;

enter image description here

面具;

enter image description here enter image description here

3 个答案:

答案 0 :(得分:7)

我已经训练https://github.com/matterport/Mask_RCNN的模型进行实例细分以在我的数据集上运行。

我的假设是您完成了所有基本设置,并且模型已经使用默认数据集运行,现在您希望它运行自定义数据集。

以下是步骤

  1. 您需要拥有所有注释。
  2. 所有这些都需要转换为VGG Polygon架构(是的,我的意思是多边形)。我在本答案的最后添加了一个样本VGG Polygon格式。
  3. 您需要将自定义数据集划分为train,test和val
  4. 默认情况下,注释在单个数据集文件夹中以文件名via_region_data.json查找。例如,对于训练图像,它将查看train\via_region_data.json。如果需要,您也可以更改它。
  5. Inside Samples文件夹中,您可以找到Balloon,Nucleus,Shapes等文件夹。复制其中一个文件夹。优选气球。我们现在将尝试为自定义数据集修改此新文件夹。
  6. 在复制的文件夹中,您将有一个.py文件(对于气球,它将是balloon.py),更改以下变量
    • ROOT_DIR:克隆项目的绝对路径
    • DEFAULT_LOGS_DIR:此文件夹的大小会变大,因此请相应地更改此路径(如果您在低磁盘存储VM中运行代码)。它还将存储.h5文件。它将在日志文件夹中创建子文件夹,并附加时间戳。
    • .h5个文件大约每个时期200到300 MB。但是猜猜这个日志目录与Tensorboard兼容。您可以在运行tensorboard时将带时间戳的子文件夹作为--logdir参数传递。
  7. .py文件还有两个类 - 一个类后缀为Config,另一个类后缀为Dataset
  8. 在Config类中覆盖所需的内容
    • NAME:您项目的名称。
    • NUM_CLASSES:它应该比标签类多一个,因为背景也被视为一个标签
    • DETECTION_MIN_CONFIDENCE:默认为0.9(如果您的训练图像质量不高或者您没有太多的训练数据,请减少它)
    • STEPS_PER_EPOCH
  9. 在Dataset类中,重写以下方法。所有这些功能都已经过充分评论,因此您可以根据自己的需要跟踪评论。
    • load_(name_of_the_sample_project),例如load_balloon
    • load_mask(参见示例答案的最后一个)
    • image_reference
  10. 训练功能(数据集类外):如果你必须改变纪元数或学习率等等。
  11. 您现在可以直接从终端

    运行它
    python samples\your_folder_name\your_python_file_name.py train --dataset="location_of_custom_dataset" --weights=coco
    

    有关上述行的命令行参数的完整信息,您可以在此.py文件的顶部将其视为注释。

    这些是我记忆中的事情,我想在记忆中添加更多步骤。也许你可以告诉我,如果你遇到任何特定的步骤,我会详细说明这个步骤。

    VGG多边形架构

    宽度和高度是可选的

    [{
        "filename": "000dfce9-f14c-4a25-89b6-226316f557f3.jpeg",
        "regions": {
            "0": {
                "region_attributes": {
                    "object_name": "Cat"
                },
                "shape_attributes": {
                    "all_points_x": [75.30864197530865, 80.0925925925926, 80.0925925925926, 75.30864197530865],
                    "all_points_y": [11.672189112257607, 11.672189112257607, 17.72093488703078, 17.72093488703078],
                    "name": "polygon"
                }
            },
            "1": {
                "region_attributes": {
                    "object_name": "Cat"
                },
                "shape_attributes": {
                    "all_points_x": [80.40123456790124, 84.64506172839506, 84.64506172839506, 80.40123456790124],
                    "all_points_y": [8.114103362391036, 8.114103362391036, 12.205901974737595, 12.205901974737595],
                    "name": "polygon"
                }
            }
        },
        "width": 504,
        "height": 495
    }]
    

    示例load_mask功能

    def load_mask(self, image_id):
        """Generate instance masks for an image.
        Returns:
        masks: A bool array of shape [height, width, instance count] with
            one mask per instance.
        class_ids: a 1D array of class IDs of the instance masks.
        """
        # If not your dataset image, delegate to parent class.
        image_info = self.image_info[image_id]
        if image_info["source"] != "name_of_your_project":   //change your project name
            return super(self.__class__, self).load_mask(image_id)
    
        # Convert polygons to a bitmap mask of shape
        # [height, width, instance_count]
        info = self.image_info[image_id]
        mask = np.zeros([info["height"], info["width"], len(info["polygons"])], dtype=np.uint8)
        class_id =  np.zeros([mask.shape[-1]], dtype=np.int32)
    
        for i, p in enumerate(info["polygons"]):
            # Get indexes of pixels inside the polygon and set them to 1
            rr, cc = skimage.draw.polygon(p['all_points_y'], p['all_points_x'])
            # print(rr.shape, cc.shape, i, np.ones([mask.shape[-1]], dtype=np.int32).shape, info['classes'][i])
    
            class_id[i] = self.class_dict[info['classes'][i]]
            mask[rr, cc, i] = 1
    
    
        # Return mask, and array of class IDs of each instance. Since we have
        # one class ID only, we return an array of 1s
        return mask.astype(np.bool), class_id
    

答案 1 :(得分:0)

首先,您需要提取每个图像的边界框。该任务必须手动完成,或者您可以使用OpenCV

等工具

编辑open cv

对于白色的片段,你必须使用你选择的任何工具做最好的技术,我会用OpenCV做。代码可能非常具体,因为可以使用不同的技术来处理它。没有其他办法,因为你没有注释而是掩盖。

现在你的图像和盒子的格式(x,y,宽度,高度)。

Detectron有一个JSON文件格式,例如: https://pastebin.com/ewaaC5Bm

现在,您可以使用images值创建类似的JSON,因为您已获得该信息。

由于我们没有任何细分(在您的示例中),让我们澄清annotations正在采取的参数:

  • category_id:这是该类别的ID。您可以在pastebin中看到我展示的唯一类别id = 32。您需要根据数据集添加更多类别。

  • bbox:这是我们上面谈到的方框:[x,y,width,height]

现在,对于iscrowdareasegmentation,我们显然可以采用两种方法:thisthis

这样就不会考虑细分(或者会被考虑但会被忽略)。

祝你好运。

答案 2 :(得分:-1)

对于图像分割任务,有两种向训练代码提供蒙版图像的方法。

  1. 整个图像的蒙版图像。
  2. 图像中每个对象的遮罩图像。

在Mask R-CNN中,您必须遵循2。

我们的Mac OS X应用程序RectLabel可以导出两个蒙版图像。

  1. 索引色图像,其颜色表与对象类ID相对应。

  2. 每个对象的灰色图像,其中包括0:背景和255:前景。

我们提供了有关如何加载蒙版图像并设置为Mask R-CNN代码的TFRecord文件的python代码示例。

将COCO JSON文件转换为带有蒙版图像的TFRecord

https://github.com/ryouchinsa/Rectlabel-support/blob/master/rectlabel_create_coco_tf_record.py

python object_detection/dataset_tools/rectlabel_create_coco_tf_record.py \
--train_image_dir="${TRAIN_IMAGE_DIR}" \
--val_image_dir="${VAL_IMAGE_DIR}" \
--train_annotations_file="${TRAIN_ANNOTATIONS_FILE}" \
--val_annotations_file="${VAL_ANNOTATIONS_FILE}" \
--output_dir="${OUTPUT_DIR}" \
--include_masks

将PASCAL VOC XML文件转换为带有蒙版图像的TFRecord

https://github.com/ryouchinsa/Rectlabel-support/blob/master/rectlabel_create_pascal_tf_record.py

python object_detection/dataset_tools/rectlabel_create_pascal_tf_record.py \
--images_dir="${IMAGES_DIR}" \
--label_map_path="${LABEL_MAP_PATH}" \
--output_path="${OUTPUT_PATH}" \
--include_masks

我们希望这会有所帮助。