• 自动生成VGG图像注释文件


    c0af27aa852e272f4f2e5f01f516f73a.jpeg

    在计算机视觉领域,实例分割是当今最热门的话题之一。

    它包括图像中对象的检测/分割,即特定对象的定位及其所属像素的关联。像任何一种机器学习系统一样,训练主干结构需要大量图像。更具体地说,需要大量注释来训练神经网络的定位功能。

    注释是一项耗时的活动,可以决定项目是否会成功。因此,必须谨慎处理,以提高生产率。

    在卫星图像领域,可以利用免费数据集来利用研究人员或注释人员以前所做的工作。这些数据集通常是由研究人员在从开源图像构建数据集、进行前后处理并用于训练和测试自己的人工智能研究系统后发布的。

    语义分割和实例分割有点不同,但在建筑物的情况下,一个可以帮助另一个。

    事实上,建筑物通常是独特的,可以在任何图像上进行分离。利用这种考虑,可以从二值标签图像中为每个建筑生成单独的遮罩,然后用于更快地训练实例分割算法,如Mask RCNN。注释不必手动执行,这是该技术的主要优点。下面是一些如何做的提示!


    JSON文件格式

    Mask RCNN Matterport实现以及FAIR Detectron2平台使用JSON文件为训练图像数据集加载注释。这种文件格式用于许多计算机科学应用,因为它允许以成对属性值的格式轻松存储和共享字母数字信息。

    它是为JavaScript语言构建的,但如今,它被用于许多其他编程语言,如Python。专门的库已经建立起来,能够在Python代码中以文本文件的形式生成和解析JSON格式的数据。VGG注释工具格式中Mask RCNN使用的典型JSON文件将具有以下形状:

    1. {
    2.   "image1.png9259408": {
    3.     "filename""image1.png",
    4.     "size"9259408,
    5.     "regions": [
    6.       {
    7.         "shape_attributes": {
    8.           "name""polygon",
    9.           "all_points_x": [
    10.             314,
    11.             55,
    12.             71,
    13.             303,
    14.             318,
    15.             538,
    16.           ],
    17.           "all_points_y": [
    18.             1097,
    19.             1093,
    20.             1450,
    21.             1450,
    22.             1505,
    23.             1474,
    24.           ]
    25.         },
    26.         "region_attributes": {
    27.           "class""building"
    28.         }
    29.       },
    30.       {
    31.         "shape_attributes": {
    32.           "name""rect",
    33.           "x"515,
    34.           "y"1808,
    35.           "width"578,
    36.           "height"185
    37.         },
    38.         "region_attributes": {
    39.           "class""apple"
    40.         }
    41.       }
    42.     ],
    43.     "file_attributes": {}
    44.   },
    45.   "0030fd0e6378.png236322": {
    46.     "filename""0030fd0e6378.png",
    47.     "size"236322,
    48.     "regions": [
    49.       {
    50.         "shape_attributes": {
    51.           "name""polygon",
    52.           "all_points_x": [
    53.             122,
    54.             294,
    55.             258,
    56.             67,
    57.             32
    58.           ],
    59.           "all_points_y": [
    60.             92,
    61.             113,
    62.             231,
    63.             221,
    64.             132
    65.           ]
    66.         },
    67.         "region_attributes": {
    68.           "class""apple"
    69.         }
    70.       },
    71.       {
    72.         "shape_attributes": {
    73.           "name""circle",
    74.           "cx"210,
    75.           "cy"303,
    76.           "r"47
    77.         },
    78.         "region_attributes": {
    79.           "class""swan"
    80.         }
    81.       }
    82.     ],
    83.     "file_attributes": {}
    84.   }
    85. }

    一个JSON注释文件收集所有注释数据。每个图像注释都堆积在一个大的JSON文件中。

    • 一个图像由其标识符标识。该标识符由四个属性描述:图像的名称(文件名)、其在磁盘上的大小(大小)、注释的形状(区域)和图像上的一些元数据(文件属性)。

    • 每个注释都可以由两个元素来描述:形状描述(形状属性)和注释数据(区域属性)。形状属性描述由注释的形状(名称)和两个整数的有序列表(所有点x和所有点y)组成,它们表示构成遮罩注释的点的x和y坐标。注释数据region_attributes可以调整,注释类可以保存以用于多类分割。

    • 第四个标识符属性名为file_attributes,可用于存储注释图像上的任何信息。

    在语法方面,让我们注意到大括号{}通常用于分隔相同类型的元素,以及引用描述一个元素的属性。方括号[]用于表示参数列表。

    幸运的是,Python有一个库供我们读写JSON文件。使用带有通用语法的import json代码片段可以轻松加载它,以读取和写入文本文件。

    在下一章中,我们将讨论如何将二进制标签图像转换为VGG注释,尤其是如何使用JSON语法编写注释文件。

    生成注释JSON文件

    本文提出的主要思想是将二进制标签图像转换为VGG注释格式的掩码JSON文件。对二值标签图像的每个形状进行个性化处理,以将其转化为遮罩元素,例如分割。

    转换主要使用著名的OpenCV图形库执行,该库在Python中易于使用。

    1. def Annot(preprocess_path, res=0.6, surf=100, eps=0.01):
    2.   """
    3.   preprocess_path : path to folder with gt and images subfolder containing ground truth binary label image and visual imagery
    4.   res : spatial resolution of images in meter 
    5.   surf : the minimum surface of roof considered in the study in square meter
    6.   eps : the index for Ramer–Douglas–Peucker (RDP) algorithm for contours approx to decrease nb of points describing a contours
    7.   """
    8.   
    9.     jsonf = {} # only one big annotation file
    10.     with open(os.path.join(preprocess_path,'via_region_data.json'), 'w') as js_file:
    11.         gt_path = os.path.join(preprocess_path, 'gt')
    12.         images_path = os.path.join(preprocess_path, 'images')
    13.         
    14.         # All the elements in the images folders
    15.         lst = os.listdir(images_path)
    16.         for elt in tqdm(lst, desc='lst'):
    17.         
    18.             # Read the binary mask, and find the contours associated
    19.             gray = cv2.imread(os.path.join(gt_path, elt))
    20.             imgray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
    21.             _, thresh = cv2.threshold(imgray, 1272550)
    22.             contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    23.             
    24.             # https://www.pyimagesearch.com/2021/10/06/opencv-contour-approximation/
    25.             # Contours approximation based on Ramer–Douglas–Peucker (RDP) algorithm
    26.             areas = [cv2.contourArea(contours[idx])*res*res for idx in range(len(contours))]
    27.             large_contour = []
    28.             for i in range(len(areas)):
    29.                 if areas[i]>surf:
    30.                     large_contour.append(contours[i])
    31.             approx_contour = [cv2.approxPolyDP(c, eps * cv2.arcLength(c, True), True) for c in large_contour]
    32.             
    33.             # -------------------------------------------------------------------------------
    34.             # BUILDING VGG ANNTOTATION TOOL ANNOTATIONS LIKE 
    35.             if len(approx_contour) > 0:
    36.                 regions = [0 for i in range(len(approx_contour))]
    37.                 for i in range(len(approx_contour)):
    38.                     shape_attributes = {}
    39.                     region_attributes = {}
    40.                     region_attributes['class'] = 'roof'
    41.                     regionsi = {}
    42.                     shape_attributes['name'] = 'polygon'
    43.                     shape_attributes['all_points_x'] = approx_contour[i][:, 0][:, 0].tolist()
    44.                     # https://stackoverflow.com/questions/26646362/numpy-array-is-not-json-serializable
    45.                     shape_attributes['all_points_y'] = approx_contour[i][:, 0][:, 1].tolist()
    46.                     regionsi['shape_attributes'] = shape_attributes
    47.                     regionsi['region_attributes'] = region_attributes
    48.                     regions[i] = regionsi
    49.                 size = os.path.getsize(os.path.join(images_path, elt))
    50.                 name = elt + str(size)
    51.                 json_elt = {}
    52.                 json_elt['filename'] = elt
    53.                 json_elt['size'] = str(size)
    54.                 json_elt['regions'] = regions
    55.                 json_elt['file_attributes'] = {}
    56.                 jsonf[name] = json_elt
    57.                 
    58.         json.dump(jsonf, js_file)
    • 第一行是为真实标签和图像文件夹构建正确的文件夹路径,并创建JSON文件注释。

    • 首先,使用cv2.findContours将二进制遮罩切割成轮廓。大多数转换(阈值、灰度转换)实际上并不需要,因为数据已经是二值图像。cv2.findContours函数提供一个等高线列表,作为一个点列表,这些点的坐标在图像的参考系中表示。

    • 在大型建筑屋顶项目中,可以使用自定义OpenCV函数来导出屋顶表面,然后将其转换为平方米,并仅选择具有足够面积的屋顶。在这种情况下,可以使用Ramer–Douglas–Peucker(RDP)算法来简化和近似检测到的轮廓,以便更紧凑地存储注释数据。此时,你应该有一个点列表,这些点代表在二值图像上检测到的轮廓。

    • 现在,你需要将整个轮廓点列表转换为一个大的用于掩码RCNN算法的via_region_data.json文件。对于JSON注释,数据需要具有第一段中指定的格式。字典主要在将数据推送到JSON文件之前使用。

    • 根据轮廓[]的数量,需要特定数量的 [:,0]才能获取正确的数据。描述轮廓的整数数组必须转换为JSON可序列化数据。制作VGG注释JSON文件与制作俄罗斯玩偶非常相似。你可以创建一个空字典,指定其一个(或多个)属性的值,然后将其作为更高级别属性的值传递,以将其封装到更大的字典中。我们注意到,对于多类分割或对象检测,region_attributes可以包含一个属性类,该属性类的掩码在shape_attributes参数中指定。

    • 最后,在将所有图像数据放入JSON文件之前,每个图像数据都存储在一个大的“json”元素中,其名称+大小字符串作为标识符。这一点非常重要,因为如果每次运行新图像时都写入JSON文件,JSON文件的掩码RCNN导入将失败。这是因为json.load只读取第一组大括号{}的内容,无法解释下一组大括号。

    就这样!让我们看看这个过程的结果是什么!

    检查注释显示

    这一小章将展示上述过程的图形化使用。使用的主要是美国地质调查局通过国家地图服务公开发布的美国城市图像(芝加哥、奥斯汀、旧金山)。

    美国地质调查局国家地理空间计划提供的地图服务和数据。该服务是开源的,所以你可以对数据做任何你想做的事情!

    在这篇文章中,处理了德克萨斯州奥斯汀附近的高分辨率图像(空间分辨率=0.3米/像素)。

    • 第一个图像是视觉彩色图像,通常以GeoTiff格式提供,它也包含嵌入的地理空间数据。它以美国城市环境的城市场景为特色。渲染由三个光谱视觉图像构建:通常的蓝色、绿色和红色。但在更复杂的图像中,图像供应商可以提供近红外图像,以便能够生成CNIR(彩色+近红外图像),以分析光谱图像的不同方面。

    61ae8deb7293a95c1201ebc3d7b4d019.jpeg

    • 第二个图像显示二进制标签图像。可以看出,标签包含了与建筑物相关的每一个像素,即使是最小的弯曲形状的像素。每个建筑都可以单独识别,因为建筑不能重叠,这就证明了整个过程的合理性。

    491a7881c77afead58f6770e45b1867a.jpeg

    • 第三幅图像由二值标签1和cv2检测到的轮廓组成,以红色突出显示。显示的等高线是来自OpenCV函数的原始数据,没有被过滤掉,因此即使是最小的建筑也会被显示出来。需要注意的是,cv2.findContours是一种像素级的转换:由一个像素连接的两座建筑将被分割在一起,而只有一行暗像素就足以将两座相邻的建筑分别分割。

    1002b7760dfa2b8bcb69d1076c868c3e.jpeg

    • 第四幅图像显示具有过滤后的近似轮廓的二值标签图像。正如第二章所说,就屋顶项目而言,对面积小于100平方米的建筑不感兴趣。它还将执行轮廓近似以减小注释文件的大小。因此,仅在大型建筑周围绘制轮廓,在某些情况下,轮廓与建筑形状不完全匹配,无法启发轮廓近似。

    97de64331b72e143fd0fb8a2d73d4353.jpeg

    • 第五张也是最后一张图像显示了通常的实例分割可视化,可以使用inspect_roof_data等工具绘制。大型建筑的屋顶被单独分割。

    c82539b5e34a786bc05d7d92b51661f8.png

    结论

    本文展示的过程展示了如何将语义数据集转换为实例分割训练数据集。然后可以使用它来有效地训练Mask-RCNN算法。该过程也可以重复使用和修改,以适应具有不同输入标签形状的数据集。

    ☆ END ☆

    如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

    扫描二维码添加小编↓

    7195ec3b2678f3d62c4d442c9b1f94ee.jpeg

  • 相关阅读:
    leetCode 63.不同路径II 动态规划 + 空间复杂度优化 一维dp
    OpenCV自学笔记八:几何变换
    51单片机外设篇:点阵式LCD
    C 练习实例10 打印楼梯,同时在楼梯上方打印两个笑脸。
    第3章 并发编程
    2017 KDD | metapath2vec: Scalable Representation Learning for Heterogeneous
    9.2.3 DATE类型
    详解Object类和抽象类
    个人电脑好用必备软件(使用过)
    企业注销的债权债务如何处理
  • 原文地址:https://blog.csdn.net/woshicver/article/details/125567996