Example #1
0
def parse_json(json_file):
    annotations = mmcv.load(json_file)['annotations']

    roofs, footprints, ignores, offsets = [], [], [], []
    for annotation in annotations:
        roofs.append(wwtool.mask2polygon(annotation['roof']))
        footprints.append(wwtool.mask2polygon(annotation['footprint']))
        # ignore = annotation['ignore']
        # offset = annotation['offset']

    roof_polygons = geopandas.GeoSeries(roofs)
    footprint_polygons = geopandas.GeoSeries(footprints)

    if True:
        fig, ax = plt.subplots(1, 1)
        
        roof_df = geopandas.GeoDataFrame({'geometry': roof_polygons, 'foot_df':range(len(roof_polygons))})
        footprint_df = geopandas.GeoDataFrame({'geometry': footprint_polygons, 'foot_df':range(len(footprint_polygons))})

        roof_df.plot(ax=ax, color='red')
        footprint_df.plot(ax=ax, color='green')
        # plt.axis('off')

        # plt.savefig('./a.png', bbox_inches='tight', dpi=600, pad_inches=0.5)

        plt.show()
Example #2
0
    def mask_ratio(self):
        obb_ratio = []
        hbb_ratio = []
        for idx, _ in enumerate(self.imgIds):
            img = self.coco.loadImgs(self.imgIds[idx])[0]
            annIds = self.coco.getAnnIds(imgIds=img['id'],
                                         catIds=self.catIds,
                                         iscrowd=None)
            anns = self.coco.loadAnns(annIds)  # per image
            for ann in anns:
                bbox = ann['bbox']
                segmentation = ann['segmentation']
                polygon = wwtool.mask2polygon(segmentation[0])
                rbbox = polygon.minimum_rotated_rectangle
                polygon_area = polygon.area
                rbbox_area = rbbox.area

                bbox_area = bbox[2] * bbox[3]

                obb_ratio.append(polygon_area / rbbox_area)
                hbb_ratio.append(polygon_area / bbox_area)

        obb_ratio = np.array(obb_ratio)
        hbb_ratio = np.array(hbb_ratio)

        print("mean obb ratio: {}, mean hbb ratio: {}".format(
            obb_ratio.mean(), hbb_ratio.mean()))
Example #3
0
    def __simpletxt_parse__(self, label_file, image_file):
        """
        (xmin, ymin, xmax, ymax)
        """
        annotations = mmcv.load(label_file)['annotations']
        # roof_mask, footprint_mask, roof_bbox, building_bbox, label, ignore, offset
        objects = []
        for annotation in annotations:
            object_struct = {}
            roof_mask = annotation['roof']
            roof_polygon = wwtool.mask2polygon(roof_mask)
            roof_bound = roof_polygon.bounds  # xmin, ymin, xmax, ymax
            footprint_mask = annotation['footprint']
            footprint_polygon = wwtool.mask2polygon(footprint_mask)
            footprint_bound = footprint_polygon.bounds
            building_xmin = np.minimum(roof_bound[0], footprint_bound[0])
            building_ymin = np.minimum(roof_bound[1], footprint_bound[1])
            building_xmax = np.maximum(roof_bound[2], footprint_bound[2])
            building_ymax = np.maximum(roof_bound[3], footprint_bound[3])

            building_bound = [
                building_xmin, building_ymin, building_xmax, building_ymax
            ]

            xmin, ymin, xmax, ymax = list(roof_bound)
            bbox_w = xmax - xmin
            bbox_h = ymax - ymin
            object_struct['bbox'] = [xmin, ymin, bbox_w, bbox_h]
            object_struct['roof_bbox'] = object_struct['bbox']
            xmin, ymin, xmax, ymax = list(building_bound)
            bbox_w = xmax - xmin
            bbox_h = ymax - ymin
            object_struct['building_bbox'] = [xmin, ymin, bbox_w, bbox_h]

            object_struct['roof_mask'] = roof_mask
            object_struct['footprint_mask'] = footprint_mask
            object_struct['ignore_flag'] = annotation['ignore']
            object_struct['offset'] = annotation['offset']

            object_struct['segmentation'] = roof_mask
            object_struct['label'] = 1
            object_struct['iscrowd'] = object_struct['ignore_flag']

            objects.append(object_struct)

        return objects
Example #4
0
    def simpletxt2json(self, image_fn):
        # 1. open the ignore file and get the polygons
        base_name = wwtool.get_basename(image_fn)
        sub_fold = base_name.split("__")[0].split('_')[0]
        ori_image_fn = "_".join(base_name.split("__")[0].split('_')[1:])
        # if ori_image_fn in self.wrong_shp_file_dict[sub_fold]:
        #     print("Skip this wrong shape file")
        #     return
        coord_x, coord_y = base_name.split("__")[1].split(
            '_')  # top left corner
        coord_x, coord_y = int(coord_x), int(coord_y)
        print(
            f"splitted items: {self.city}, {sub_fold}, {ori_image_fn}, {(coord_x, coord_y)}"
        )

        ignore_file = './data/buildchange/{}/{}/{}/pixel_anno_v2/{}'.format(
            src_version, self.city, sub_fold, ori_image_fn + '.png')
        # print("ignore file name: ", ignore_file)
        roof_shp_file = './data/buildchange/{}/{}/{}/roof_shp_4326/{}'.format(
            src_version, self.city, sub_fold, ori_image_fn + '.shp')
        geo_info_file = './data/buildchange/{}/{}/{}/geo_info/{}'.format(
            src_version, self.city, sub_fold, ori_image_fn + '.png')

        objects = shp_parser(roof_shp_file, geo_info_file)
        roof_polygon_4326 = [obj['converted_polygon'] for obj in objects]
        roof_property = [obj['converted_property'] for obj in objects]

        pixel_anno = cv2.imread(ignore_file)
        if pixel_anno is None:
            return
        objects = mask_parser(pixel_anno[coord_y:coord_y + sub_img_h,
                                         coord_x:coord_x + sub_img_w, :],
                              category=255)
        if objects == []:
            return
        ignore_polygons = [obj['polygon'] for obj in objects]
        # print("ignore polygon: ", ignore_polygons)

        # 2. read the simpletxt file and convert to polygons
        objects = self.simpletxt_parse(
            os.path.join(self.splitted_label_dir, base_name + '.txt'))
        roof_polygons = [
            wwtool.mask2polygon(obj['polygon']) for obj in objects
        ]
        # print("roof polygon: ", roof_polygons)

        _, ignore_indexes = wwtool.cleaning_polygon_by_polygon(
            roof_polygons[:], ignore_polygons, show=False)
        ignore_list = len(roof_polygons) * [0]
        for ignore_index in ignore_indexes:
            ignore_list[ignore_index] = 1

        new_anno_objects = []
        for idx, roof_polygon in enumerate(roof_polygons):
            footprint_polygon, xoffset, yoffset = self.get_footprint(
                roof_polygon, [coord_x, coord_y], roof_polygon_4326,
                roof_property)
            object_struct = dict()
            ignore_flag = ignore_list[idx]
            object_struct['roof'] = wwtool.polygon2mask(roof_polygon)
            object_struct['footprint'] = wwtool.polygon2mask(footprint_polygon)
            object_struct['offset'] = [xoffset, yoffset]
            object_struct['ignore'] = ignore_flag
            new_anno_objects.append(object_struct)

        image_info = {
            "ori_filename": ori_image_fn + '.jpg',
            "subimage_filename": image_fn,
            "width": 1024,
            "height": 1024,
            "city": self.city,
            "sub_fold": sub_fold,
            "coordinate": [coord_x, coord_y]
        }

        json_data = {"image": image_info, "annotations": new_anno_objects}

        json_file = os.path.join(self.json_dir, f'{base_name}.json')
        with open(json_file, "w") as jsonfile:
            json.dump(json_data, jsonfile, indent=4)
    def drop_subimage(self,
                      subimages,
                      subimage_coordinate,
                      subimage_masks,
                      center_area=2,
                      small_object=64,
                      show=False):
        """judge whether to drop the overlap image

        Arguments:
            subimages {dict} -- dict which contains all subimages (value)
            subimage_coordinate {tuple} -- the coordinate of subimage in original image
            subimage_masks {list} -- list of masks in subimages

        Keyword Arguments:
            center_area {int} -- the area of center line (default: {2})
            show {bool} -- whether to show center line (default: {False})

        Returns:
            drop flag -- True: drop the subimage, False: keep the subimage
        """
        # black image
        if np.mean(subimages[subimage_coordinate]) == 0:
            return True

        # no object
        if len(subimage_masks) == 0:
            return True

        # keep the main subimage, just drop the overlap part
        if abs(subimage_coordinate[0] - subimage_coordinate[1]) in (
                0, 1024) and (subimage_coordinate[0] != 512
                              and subimage_coordinate[1] != 512):
            return False

        subimage_mask_area = []
        subimage_mask_polygons = []
        for subimage_mask in subimage_masks:
            subimage_mask_polygon = wwtool.mask2polygon(subimage_mask)
            subimage_mask_polygons.append(subimage_mask_polygon)
            subimage_mask_area.append(subimage_mask_polygon.area)

        # (horizontal, vertical)
        center_lines = [
            Polygon([(0, 512 - center_area), (0, 512 + center_area),
                     (1023, 512 + center_area), (1023, 512 - center_area),
                     (0, 512 - center_area)]),
            Polygon([(512 - center_area, 0), (512 + center_area, 0),
                     (512 + center_area, 1023), (512 - center_area, 1023),
                     (512 - center_area, 0)])
        ]

        if subimage_coordinate[0] == 512 and subimage_coordinate[1] != 512:
            center_lines = [center_lines[1]]
        elif subimage_coordinate[0] != 512 and subimage_coordinate[1] == 512:
            center_lines = [center_lines[0]]
        else:
            center_lines = center_lines

        subimage_mask_polygons = wwtool.clean_polygon(subimage_mask_polygons)
        subimage_mask_df = geopandas.GeoDataFrame({
            'geometry':
            subimage_mask_polygons,
            'submask_df':
            range(len(subimage_mask_polygons))
        })
        center_line_df = geopandas.GeoDataFrame({
            'geometry':
            center_lines,
            'center_df':
            range(len(center_lines))
        })

        image_border_polygon = [
            Polygon([(0, 0), (1024 - 1, 0), (1024 - 1, 1024 - 1),
                     (0, 1024 - 1), (0, 0)])
        ]
        border_line_df = geopandas.GeoDataFrame({
            'geometry':
            image_border_polygon,
            'border_df':
            range(len(image_border_polygon))
        })

        if show:
            fig, ax = plt.subplots()

            subimage_mask_df.plot(ax=ax, color='red')
            center_line_df.plot(ax=ax, facecolor='none', edgecolor='g')
            border_line_df.plot(ax=ax, facecolor='none', edgecolor='k')
            ax.set_title('{}_{}'.format(subimage_coordinate[0],
                                        subimage_coordinate[1]))
            plt.xticks([])
            plt.yticks([])
            plt.axis('off')

            # plt.show()
            plt.savefig('./{}_{}_{}.png'.format(
                self.image_fn.replace('.jpg', ''), subimage_coordinate[0],
                subimage_coordinate[1]),
                        bbox_inches='tight',
                        dpi=600,
                        pad_inches=0.0)

        res_intersection = geopandas.overlay(subimage_mask_df,
                                             center_line_df,
                                             how='intersection')
        inter_dict = res_intersection.to_dict()
        ignore_indexes = list(set(inter_dict['submask_df'].values()))

        inter_areas = []
        for ignore_index in ignore_indexes:
            inter_areas.append(subimage_mask_polygons[ignore_index].area)

        if len(inter_areas
               ) == 0 or max(inter_areas) < small_object * small_object:
            return True
        else:
            return False
    def split_image(self, image_fn):
        self.image_fn = image_fn
        if not image_fn.endswith('.jpg'):
            return
        image_file = os.path.join(self.image_path, image_fn)
        shp_file = os.path.join(self.merged_shp_path,
                                image_fn.replace('jpg', 'shp'))
        geo_file = os.path.join(self.geo_path, image_fn.replace('jpg', 'png'))
        pixel_anno_file = os.path.join(self.pixel_anno_path,
                                       image_fn.replace('jpg', 'png'))

        file_name = os.path.splitext(os.path.basename(image_file))[0]

        if not os.path.exists(shp_file):
            return

        img = cv2.imread(image_file)
        geo_info = rio.open(geo_file)
        print(pixel_anno_file)
        objects = self.shp_parser(shp_file,
                                  geo_info,
                                  ignore_file=pixel_anno_file,
                                  show_ignored_polygons=False)

        masks = np.array([obj['segmentation'] for obj in objects])

        subimages = wwtool.split_image(img,
                                       subsize=self.subimage_size,
                                       gap=self.gap)
        subimage_coordinates = list(subimages.keys())

        if masks.shape[0] == 0:
            return

        mask_centroids = []
        for obj in objects:
            geometry = obj['converted_polygon'].centroid
            geo = geojson.Feature(geometry=geometry, properties={})
            coordinate = geo.geometry["coordinates"]
            coordinate[0], coordinate[1] = abs(coordinate[0]), abs(
                coordinate[1])
            mask_centroids.append(coordinate)

        mask_centroids = np.array(mask_centroids)
        mask_centroids_ = mask_centroids.copy()

        for subimage_coordinate in subimage_coordinates:
            objects = []

            mask_centroids_[:,
                            0] = mask_centroids[:, 0] - subimage_coordinate[0]
            mask_centroids_[:,
                            1] = mask_centroids[:, 1] - subimage_coordinate[1]

            cx_bool = np.logical_and(mask_centroids_[:, 0] >= 0,
                                     mask_centroids_[:, 0] < subimage_size)
            cy_bool = np.logical_and(mask_centroids_[:, 1] >= 0,
                                     mask_centroids_[:, 1] < subimage_size)

            subimage_masks = masks[np.logical_and(cx_bool, cy_bool)]

            subimage_masks_ = []
            for subimage_mask in subimage_masks:
                if wwtool.mask2polygon(subimage_mask).area < 5:
                    continue
                subimage_mask_np = np.array(subimage_mask)
                subimage_mask_np[
                    0::2] = subimage_mask_np[0::2] - subimage_coordinate[0]
                subimage_mask_np[
                    1::2] = subimage_mask_np[1::2] - subimage_coordinate[1]
                subimage_masks_.append(subimage_mask_np.tolist())

            subimage_masks = subimage_masks_
            # cut the polygons by image boundary
            subimage_masks = wwtool.clip_mask(subimage_masks,
                                              image_size=(1024, 1024))

            # judge whether to drop this subimage
            drop_flag = self.drop_subimage(subimages,
                                           subimage_coordinate,
                                           subimage_masks,
                                           show=self.show)
            if drop_flag:
                continue

            img = subimages[subimage_coordinate]

            label_save_file = os.path.join(
                self.label_save_path,
                '{}__{}_{}.txt'.format(file_name, subimage_coordinate[0],
                                       subimage_coordinate[1]))
            image_save_file = os.path.join(
                self.image_save_path,
                '{}__{}_{}.png'.format(file_name, subimage_coordinate[0],
                                       subimage_coordinate[1]))
            cv2.imwrite(image_save_file, img)

            for subimage_mask in subimage_masks:
                subimage_objects = dict()
                subimage_objects['mask'] = subimage_mask
                subimage_objects['label'] = 'building'
                objects.append(subimage_objects)
            wwtool.simpletxt_dump(objects, label_save_file, encode='mask')
Example #7
0
                                                cv2.CHAIN_APPROX_SIMPLE)
                    contours = contours[0] if len(
                        contours) == 2 else contours[1]

                    if contours != []:
                        cnt = max(contours, key=cv2.contourArea)
                        if cv2.contourArea(cnt) < 5:
                            continue
                        mask = np.array(cnt).reshape(1, -1).tolist()[0]
                        if len(mask) < 8:
                            continue
                    else:
                        continue

                    # TODO: convert to wkt format
                    polygon = wwtool.mask2polygon(mask)
                    roof_masks.append(mask)
                    polygons.append(polygon)
                    bbox = bboxes[i][0:4]
                    w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
                    transform_matrix = [
                        1, 0, 0, 1, -1.0 * offset[0], -1.0 * offset[1]
                    ]
                    footprint_polygon = affinity.affine_transform(
                        polygon, transform_matrix)

                    footprint_mask = wwtool.polygon2mask(footprint_polygon)
                    footprint_masks.append(footprint_mask)
                    footprint_polygons.append(footprint_polygon)

            print(img['file_name'])
Example #8
0
    for key in keywords:
        csv_file = './data/buildchange/v2/xian_fine/xian_fine_{}_gt.csv'.format(
            key)
        first_in = True

        json_dir = './data/buildchange/v2/xian_fine/labels_json'
        rgb_img_dir = './data/buildchange/v2/xian_fine/images'

        for json_fn in os.listdir(json_dir):
            base_name = wwtool.get_basename(json_fn)

            rgb_img_file = os.path.join(rgb_img_dir, base_name + '.png')
            json_file = os.path.join(json_dir, json_fn)

            annotations = mmcv.load(json_file)['annotations']

            masks = [wwtool.mask2polygon(anno[key]) for anno in annotations]

            csv_image = pandas.DataFrame({
                'ImageId': base_name,
                'BuildingId': range(len(masks)),
                'PolygonWKT_Pix': masks,
                'Confidence': 1
            })
            if first_in:
                csv_dataset = csv_image
                first_in = False
            else:
                csv_dataset = csv_dataset.append(csv_image)

        csv_dataset.to_csv(csv_file, index=False)
Example #9
0
            rgb_img_file = os.path.join(rgb_img_dir, base_name + '.jpg')
            shp_file = os.path.join(shp_dir, shp_fn)

            rgb_img = cv2.imread(rgb_img_file)
            geo_info = rio.open(rgb_img_file)

            shp_parser = wwtool.ShpParse()
            objects = shp_parser(shp_file,
                                 geo_info,
                                 coord='pixel',
                                 merge_flag=True,
                                 connection_mode='floor')

            gt_polygons = [
                wwtool.mask2polygon(obj['segmentation']) for obj in objects
            ]

            # wwtool.show_polygons_on_image(gt_masks, rgb_img, output_file=None)

            csv_image = pandas.DataFrame({
                'ImageId': sub_fold + '_' + base_name,
                'BuildingId': range(len(gt_polygons)),
                'PolygonWKT_Pix': gt_polygons,
                'Confidence': 1
            })
            if first_in:
                csv_dataset = csv_image
                first_in = False
            else:
                csv_dataset = csv_dataset.append(csv_image)