如何标注mask用于图像分割模型训练(VIA标注semantic segmentation数据集的mask)

更多文章,请访问嗨大卫博客

近几年深度学习发展非常迅猛,深度学习用于图像识别、分割等方面效果非常好,像mask rcnn这类网络已经可以做到对象分割了(instance segmentation)。再不跟进就落伍了!!

下图直观的区分了这四种不同处理任务的效果。Instance segmentation的任务不单把cube这个物体找到了,还要分割出不同cube对象。
在这里插入图片描述
网上看别人的研究成果都觉得效果很好,实践起来到底怎么样了?

最近尝试下github上的Image Segmentation Keras

训练前,首先要准备数据集,需要标注大量mask图片,找了几款标注工具,只能导出json文件,下面分享下如何把json文件转化成mask 图片。

首先,使用VIA标注工具,标注物体轮廓,导出json文件。json文件里包括了图片中物体的轮廓坐标信息。

标注工具比较多,比如有名的像labelme、VIA等,而VIA是网页版的,用起来比较简单方便,而且流畅,无需安装。

在这里插入图片描述

导出的json文件长这样儿的:

{
  "_via_settings": {...},
  "_via_img_metadata": {
    "1.png19539": {
      "filename": "1.png",
      "size": 19539,
      "regions": [
        {
          "shape_attributes": {
            "name": "polyline",
            "all_points_x": [
              138,
              149,
              265,
              347,
              364,
              367,
              362,
              352,
              257,
              222,
              162,
              151,
              136
            ],
            "all_points_y": [
              246,
              226,
              198,
              208,
              218,
              258,
              468,
              489,
              552,
              560,
              542,
              524,
              248
            ]
          },
          "region_attributes": {}
        }
      ],
      "file_attributes": {}
    },
    "2.png34896": {...},
    "3.png65485": {...}
  }
}    

运行下面python代码,加载刚才的json文件,解析出轮廓坐标,通过opencv的pointPolygonTest方法,区分物体内还是物体外的像素点,附上不同颜色数值,如该例中,背景像素为0,物体像素为1。保存成图片。

import os
import json
import numpy as np
import skimage.draw
import cv2

IMAGE_FOLDER = "./train/"
MASK_FOLOER = "./mask/"
PATH_ANNOTATION_JSON = 'box.json'

# 加载VIA导出的json文件
annotations = json.load(open(PATH_ANNOTATION_JSON, 'r'))
imgs = annotations["_via_img_metadata"]

for imgId in imgs:
    filename = imgs[imgId]['filename']
    regions = imgs[imgId]['regions']
    if len(regions) <= 0:
        continue

    # 取出第一个标注的类别,本例只标注了一个物件
    polygons = regions[0]['shape_attributes']

    # 图片路径
    image_path = os.path.join(IMAGE_FOLDER, filename)
    # 读出图片,目的是获取到宽高信息
    image = cv2.imread(image_path)  # image = skimage.io.imread(image_path)
    height, width = image.shape[:2]

    # 创建空的mask
    maskImage = np.zeros((height,width), dtype=np.uint8)
    countOfPoints = len(polygons['all_points_x'])
    points = [None] * countOfPoints
    for i in range(countOfPoints):
        x = int(polygons['all_points_x'][i])
        y = int(polygons['all_points_y'][i])
        points[i] = (x, y)

    contours = np.array(points)

    # 遍历图片所有坐标
    for i in range(width):
        for j in range(height):
            if cv2.pointPolygonTest(contours, (i, j), False) > 0:
                maskImage[j,i] = 1

    savePath = MASK_FOLOER + filename
    # 保存mask
    cv2.imwrite(savePath, maskImage)

生成图片保存在mask的文件夹里,每张mask png图片跟原图名字一样,方便后面做训练。

正常来说,导出的mask图片用肉眼看是黑色的,为了看到mask效果,把背景像素设置成0,物体像素设置成255,这样就能看到效果了。下图是行李箱mask的直观效果。
在这里插入图片描述

### sscanf 函数导致单片机死机的原因 当 `sscanf` 函数处理输入字符串时,如果遇到不匹配的格式说明符或超出缓冲区大小的内容,可能会引发异常行为甚至导致系统崩溃。具体来说,在 STM32 单片机平台上使用 `sscanf` 可能会因为以下几个方面出现问题: - **栈溢出风险**:由于 `sscanf` 需要在堆栈中分配临时空间来解析参数列表中的各个部分,如果传递给它的源串过长或者存在恶意构造的数据,就容易造成栈溢出,进而使程序陷入无限循环或是直接挂起[^1]。 - **未初始化指针**:当目标变量是指向字符数组或其他类型的指针时,如果没有正确地为其分配内存并设置初始值为空(NULL),那么一旦尝试写入这些未经初始化的位置,将会触发非法访问错误,最终引起系统的不稳定乃至冻结状态。 - **格式化字符串漏洞**:不当使用的格式控制字符串可以被攻击者利用来进行各种形式的安全威胁,比如读取任意地址处的信息、执行任意代码等操作;即使是在正常情况下也可能因为误配而导致意外的结果发生,从而影响整个应用程序的工作流程。 针对上述提到的各种潜在隐患,下面给出一些预防措施以及解决方案: #### 解决方案 ##### 合理规划数据长度与边界条件判断 确保每次调用前都已知确切的最大可能输入尺寸,并据此调整接收缓存容量。对于不确定长度的情况应采用动态分配方式获取适当的空间资源。同时增加必要的验证逻辑以防止越界情况的发生。 ```c #define MAX_INPUT_LENGTH 80 char inputBuffer[MAX_INPUT_LENGTH]; // ... 获取inputString ... if (strlen(inputString) >= sizeof(inputBuffer)) { // 处理过长输入... } else { strcpy(inputBuffer, inputString); } int result; result = sscanf(inputBuffer, "%d", &number); // 安全地转换整数 ``` ##### 初始化所有指向可变存储区域的指针 无论何时何地创建新的指针对象之前都要先设定其默认值为 NULL 或其他安全选项,之后再根据实际需求逐步填充有效内容。这有助于减少悬空指针带来的不确定性因素。 ```c char *strPtr = NULL; size_t bufferSize = strlen(sourceStr)+1; strPtr = malloc(bufferSize); if(strPtr != NULL){ strncpy(strPtr , sourceStr , bufferSize ); }else{ // 错误处理... } free(strPtr); ``` ##### 使用更严格的格式限定符 尽可能选用带有宽度限制的功能修饰词作为附加项加入到格式描述里边去,这样可以在一定程度上规避掉那些由外部供给不良造成的麻烦事端。 ```c char str[5]; sscanf("hello world","%4s",str); // 最多只读取四个字符进入str[] printf("%s\n",str); // 输出 "hell" ```
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DvLee1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值