def merge_classes(cur_meta: sly.ProjectMeta, res_meta: sly.ProjectMeta, ann: sly.Annotation):
    existing_names = set([obj_class.name for obj_class in res_meta.obj_classes])
    mapping = {}
    for obj_class in cur_meta.obj_classes:
        obj_class: sly.ObjClass
        if obj_class.name in mapping:
            continue
        dest_class = res_meta.get_obj_class(obj_class.name)
        if dest_class is None:
            res_meta = res_meta.add_obj_class(obj_class)
            dest_class = obj_class
        elif obj_class != dest_class:
            new_name = generate_free_name(existing_names, obj_class.name)
            dest_class = obj_class.clone(name=new_name)
            res_meta = res_meta.add_obj_class(dest_class)
        mapping[obj_class.name] = dest_class

    new_labels = []
    for label in ann.labels:
        if label.obj_class.name not in mapping:
            new_labels.append(label)
        else:
            new_labels.append(label.clone(obj_class=mapping[label.obj_class.name]))

    new_ann = ann.clone(labels=new_labels)
    return (res_meta, res_meta, new_ann)
 def _check_and_add_class(meta: sly.ProjectMeta,
                          target_class: sly.ObjClass):
     cls: sly.ObjClass = meta.get_obj_class(target_class.name)
     if cls is None:
         meta = meta.add_obj_class(target_class)
     elif cls != target_class:
         raise RuntimeError(
             f"Project already has class '{cls.name}' with shape {cls.geometry_type.geometry_name()}. "
             f"Shape conflict: shape should be of typy {target_class.geometry_type.geometry_name()}"
         )
     return meta
Exemple #3
0
def convert_to_nonoverlapping(meta: sly.ProjectMeta, ann: sly.Annotation) -> (sly.ProjectMeta, sly.Annotation):
    common_img = np.zeros(ann.img_size, np.int32)  # size is (h, w)
    for idx, lbl in enumerate(ann.labels, start=1):
        if need_convert(lbl.obj_class.geometry_type):
            if allow_render_for_any_shape(lbl) is True:
                lbl.draw(common_img, color=idx)
            else:
                sly.logger.warn(
                    "Object of class {!r} (shape: {!r}) has non spatial shape {!r}. It will not be rendered."
                        .format(lbl.obj_class.name,
                                lbl.obj_class.geometry_type.geometry_name(),
                                lbl.geometry.geometry_name()))

    new_classes = sly.ObjClassCollection()
    new_labels = []
    for idx, lbl in enumerate(ann.labels, start=1):
        if not need_convert(lbl.obj_class.geometry_type):
            new_labels.append(lbl.clone())
        else:
            if allow_render_for_any_shape(lbl) is False:
                continue
            # @TODO: get part of the common_img for speedup
            mask = common_img == idx
            if np.any(mask):  # figure may be entirely covered by others
                g = lbl.geometry
                new_bmp = sly.Bitmap(data=mask)
                if new_classes.get(lbl.obj_class.name) is None:
                    new_classes = new_classes.add(lbl.obj_class.clone(geometry_type=sly.Bitmap))

                new_lbl = lbl.clone(geometry=new_bmp, obj_class=new_classes.get(lbl.obj_class.name))
                new_labels.append(new_lbl)

    new_meta = meta.clone(obj_classes=new_classes)
    new_ann = ann.clone(labels=new_labels)
    return (new_meta, new_ann)
def get_empty_gallery(meta: sly.ProjectMeta = sly.ProjectMeta()):
    CNT_GRID_COLUMNS = 2
    empty_gallery = {
        "content": {
            "projectMeta": meta.to_json(),
            "annotations": {},
            "layout": [[] for i in range(CNT_GRID_COLUMNS)]
        },
    }
    return CNT_GRID_COLUMNS, empty_gallery
Exemple #5
0
def inference(model, half, device, imgsz, stride, image: np.ndarray, meta: sly.ProjectMeta, conf_thres=0.25, iou_thres=0.45,
              augment=False, agnostic_nms=False, debug_visualization=False) -> sly.Annotation:
    names = model.module.names if hasattr(model, 'module') else model.names

    img0 = image # RGB
    # Padded resize
    img = letterbox(img0, new_shape=imgsz, stride=stride)[0]
    img = img.transpose(2, 0, 1)  # to 3x416x416
    img = np.ascontiguousarray(img)

    img = torch.from_numpy(img).to(device)
    img = img.half() if half else img.float()  # uint8 to fp16/32
    img /= 255.0  # 0 - 255 to 0.0 - 1.0
    if img.ndimension() == 3:
        img = img.unsqueeze(0)

    inf_out = model(img, augment=augment)[0]

    # Apply NMS
    labels = []
    output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, agnostic=agnostic_nms)
    for i, det in enumerate(output):
        if det is not None and len(det):
            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()

            for *xyxy, conf, cls in reversed(det):
                top, left, bottom, right = int(xyxy[1]), int(xyxy[0]), int(xyxy[3]), int(xyxy[2])
                rect = sly.Rectangle(top, left, bottom, right)
                obj_class = meta.get_obj_class(names[int(cls)])
                tag = sly.Tag(meta.get_tag_meta(CONFIDENCE), round(float(conf), 4))
                label = sly.Label(rect, obj_class, sly.TagCollection([tag]))
                labels.append(label)

    height, width = img0.shape[:2]
    ann = sly.Annotation(img_size=(height, width), labels=labels)

    if debug_visualization is True:
        # visualize for debug purposes
        vis = np.copy(img0)
        ann.draw_contour(vis, thickness=2)
        sly.image.write("vis.jpg", vis)

    return ann.to_json()
def highlight_instances(meta: sly.ProjectMeta, ann: sly.Annotation) -> (sly.ProjectMeta, sly.Annotation):
    new_classes = []
    new_labels = []
    for idx, label in enumerate(ann.labels):
        new_cls = label.obj_class.clone(name=str(idx), color=sly.color.random_rgb())
        new_lbl = label.clone(obj_class=new_cls)

        new_classes.append(new_cls)
        new_labels.append(new_lbl)

    res_meta = meta.clone(obj_classes=sly.ObjClassCollection(new_classes))
    res_ann = ann.clone(labels=new_labels)
    return (res_meta, res_ann)
def transform_for_instance_segmentation(meta: sly.ProjectMeta, ann: sly.Annotation) -> (sly.ProjectMeta, sly.Annotation):
    new_classes = {}
    for obj_class in meta.obj_classes:
        obj_class: sly.ObjClass
        new_class = obj_class.clone(name=obj_class.name + "-mask")
        new_classes[obj_class.name] = new_class

    new_class_collection = sly.ObjClassCollection(list(new_classes.values()))
    new_labels = []
    for label in ann.labels:
        obj_class = new_classes[label.obj_class.name]
        new_labels.append(label.clone(obj_class=obj_class))

    res_meta = meta.clone(obj_classes=new_class_collection)
    res_ann = ann.clone(labels=new_labels)
    return (res_meta, res_ann)
def rename_meta_and_annotations(meta: sly.ProjectMeta, ann: sly.Annotation, suffix="original"):
    def _get_new_name(current_name):
        return f"{current_name}-{suffix}"

    new_classes = []
    for obj_class in meta.obj_classes:
        obj_class: sly.ObjClass
        new_classes.append(obj_class.clone(name=_get_new_name(obj_class.name)))
    new_meta = meta.clone(obj_classes=sly.ObjClassCollection(new_classes))

    new_labels = []
    for label in ann.labels:
        dest_name = _get_new_name(label.obj_class.name)
        dest_class = new_meta.get_obj_class(dest_name)
        new_labels.append(label.clone(obj_class=dest_class))
    new_ann = ann.clone(labels=new_labels)
    return new_meta, new_ann
def transform_for_detection(meta: sly.ProjectMeta, ann: sly.Annotation) -> (sly.ProjectMeta, sly.Annotation):
    new_classes = sly.ObjClassCollection()
    new_labels = []
    for label in ann.labels:
        new_class = label.obj_class.clone(name=label.obj_class.name + "-bbox", geometry_type=sly.Rectangle)
        if label.obj_class.geometry_type is sly.Rectangle:
            new_labels.append(label.clone(obj_class=new_class))
            if new_classes.get(new_class.name) is None:
                new_classes = new_classes.add(new_class)
        else:
            bbox = label.geometry.to_bbox()
            if new_classes.get(new_class.name) is None:
                new_classes = new_classes.add(new_class)
            new_labels.append(label.clone(bbox, new_class))
    res_meta = meta.clone(obj_classes=new_classes)
    res_ann = ann.clone(labels=new_labels)
    return (res_meta, res_ann)
def merge_metas(project_meta: sly.ProjectMeta, model_meta: sly.ProjectMeta,
                keep_model_classes, keep_model_tags, suffix):
    res_meta = project_meta.clone()

    def _merge(keep_names, res_meta, project_collection, model_collection, is_class=False):
        mapping = {}  # old name to new meta
        for name in keep_names:
            model_item = model_collection.get(name)
            res_item, res_name = find_item(project_collection, model_item, suffix)
            if res_item is None:
                res_item = model_item.clone(name=res_name)
                res_meta = res_meta.add_obj_class(res_item) if is_class else res_meta.add_tag_meta(res_item)
            mapping[model_item.name] = res_item
        return res_meta, mapping

    res_meta, class_mapping = _merge(keep_model_classes, res_meta, res_meta.obj_classes, model_meta.obj_classes, is_class=True)
    res_meta, tag_mapping = _merge(keep_model_tags, res_meta, res_meta.tag_metas, model_meta.tag_metas, is_class=False)
    return res_meta, class_mapping, tag_mapping
def transform_for_segmentation(meta: sly.ProjectMeta, ann: sly.Annotation) -> (sly.ProjectMeta, sly.Annotation):
    new_classes = {}
    class_masks = {}
    for obj_class in meta.obj_classes:
        obj_class: sly.ObjClass
        new_class = obj_class.clone(name=obj_class.name + "-mask")
        new_classes[obj_class.name] = new_class
        class_masks[obj_class.name] = np.zeros(ann.img_size, np.uint8)

    new_class_collection = sly.ObjClassCollection(list(new_classes.values()))
    for label in ann.labels:
        label.draw(class_masks[label.obj_class.name], color=255)

    new_labels = []
    for class_name, white_mask in class_masks.items():
        mask = white_mask == 255
        obj_class = new_classes[class_name]
        bitmap = sly.Bitmap(data=mask)
        new_labels.append(sly.Label(geometry=bitmap, obj_class=obj_class))

    res_meta = meta.clone(obj_classes=new_class_collection)
    res_ann = ann.clone(labels=new_labels)
    return (res_meta, res_ann)
Exemple #12
0
    def make_output_meta(self, input_metas_dict):
        if len(self.cls_mapping) == 0:
            raise RuntimeError('Empty cls_mapping for layer: {}'.format(Layer.action))

        full_input_meta = ProjectMeta()
        for inp_meta in input_metas_dict.values():
            full_input_meta.update(inp_meta)

        res_meta = deepcopy(full_input_meta)
        in_class_titles = set((x['title'] for x in full_input_meta.classes.py_container))

        # __other__ -> smth
        if ClassConstants.OTHER in self.cls_mapping:
            other_classes = in_class_titles - set(self.cls_mapping.keys())
            for oclass in other_classes:
                self.cls_mapping[oclass] = self.cls_mapping[ClassConstants.OTHER]
            del self.cls_mapping[ClassConstants.OTHER]

        missed_classes = in_class_titles - set(self.cls_mapping.keys())
        if len(missed_classes) != 0:
            raise RuntimeError("Some classes in mapping are missed: {}".format(missed_classes))

        for src_class_title, dst_class in self.cls_mapping.items():

            # __new__ -> [ list of classes ]
            if src_class_title == ClassConstants.NEW:
                if type(dst_class) is not list:
                    raise RuntimeError('Internal class mapping error in layer (NEW spec).')
                for new_cls in dst_class:
                    res_meta.classes.add(new_cls)

            # __clone__ -> dict {parent_cls_name: child_cls_name}
            elif src_class_title == ClassConstants.CLONE:
                if type(dst_class) is not dict:
                    raise RuntimeError('Internal class mapping error in layer (CLONE spec).')

                for src_title, dst_title in dst_class.items():
                    real_src_cls = full_input_meta.classes[src_title]
                    if real_src_cls is None:
                        raise RuntimeError('Class mapping error, source class "{}" not found.'.format(src_title))
                    real_dst_cls = {**real_src_cls, 'title': dst_title}
                    res_meta.classes.add(real_dst_cls)

            # smth -> __default__
            elif dst_class == ClassConstants.DEFAULT:
                pass

            # smth -> __ignore__
            elif dst_class == ClassConstants.IGNORE:
                res_meta.classes.delete(src_class_title)

            # smth -> new name
            elif type(dst_class) is str:
                res_meta.classes.rename(src_class_title, dst_class)

            # smth -> new cls description
            elif type(dst_class) is dict:
                res_meta.classes.replace(src_class_title, dst_class)

        rm_imtags = self.get_removed_tags()
        if rm_imtags is not None:
            res_meta.img_tags.difference(rm_imtags)

        new_imtags = self.get_added_tags()
        if new_imtags is not None:
            res_meta.img_tags.update(new_imtags)

        return res_meta
Exemple #13
0
def synthesize(api: sly.Api,
               task_id,
               state,
               meta: sly.ProjectMeta,
               image_infos,
               labels,
               bg_images,
               cache_dir,
               preview=True):
    progress_cb = refresh_progress_preview
    if preview is False:
        progress_cb = refresh_progress

    augs = yaml.safe_load(state["augs"])
    sly.logger.info("Init augs from yaml file")
    aug.init_fg_augs(augs)
    visibility_threshold = augs['objects'].get('visibility', 0.8)

    classes = state["selectedClasses"]

    bg_info = random.choice(bg_images)
    sly.logger.info("Download background")
    bg = api.image.download_np(bg_info.id)
    sly.logger.debug(f"BG shape: {bg.shape}")

    res_image = bg.copy()
    res_labels = []

    # sequence of objects that will be generated
    res_classes = []
    to_generate = []
    for class_name in classes:
        original_class: sly.ObjClass = meta.get_obj_class(class_name)
        res_classes.append(original_class.clone(geometry_type=sly.Bitmap))

        count_range = augs["objects"]["count"]
        count = random.randint(*count_range)
        for i in range(count):
            to_generate.append(class_name)
    random.shuffle(to_generate)
    res_meta = sly.ProjectMeta(obj_classes=sly.ObjClassCollection(res_classes))

    progress = sly.Progress("Processing foregrounds", len(to_generate))
    progress_cb(api, task_id, progress)

    progress_every = max(10, int(len(to_generate) / 20))

    cover_img = np.zeros(res_image.shape[:2], np.int32)  # size is (h, w)
    objects_area = defaultdict(lambda: defaultdict(float))

    cached_images = {}
    # generate objects
    for idx, class_name in enumerate(to_generate, start=1):
        if class_name not in labels:
            progress.iter_done_report()
            continue
        image_id = random.choice(list(labels[class_name].keys()))
        label: sly.Label = random.choice(labels[class_name][image_id])

        if image_id in cached_images:
            source_image = cached_images[image_id]
        else:
            image_info = image_infos[image_id]
            source_image = _get_image_using_cache(api, cache_dir, image_id,
                                                  image_info)
            cached_images[image_id] = source_image

        label_img, label_mask = get_label_foreground(source_image, label)
        #sly.image.write(os.path.join(cache_dir, f"{index}_label_img.png"), label_img)
        #sly.image.write(os.path.join(cache_dir, f"{index}_label_mask.png"), label_mask)

        label_img, label_mask = aug.apply_to_foreground(label_img, label_mask)
        #sly.image.write(os.path.join(cache_dir, f"{index}_aug_label_img.png"), label_img)
        #sly.image.write(os.path.join(cache_dir, f"{index}_aug_label_mask.png"), label_mask)

        label_img, label_mask = aug.resize_foreground_to_fit_into_image(
            res_image, label_img, label_mask)

        #label_area = g.area
        find_place = False
        for attempt in range(3):
            origin = aug.find_origin(res_image.shape, label_mask.shape)
            g = sly.Bitmap(label_mask[:, :, 0].astype(bool),
                           origin=sly.PointLocation(row=origin[1],
                                                    col=origin[0]))
            difference = count_visibility(cover_img, g, idx, origin[0],
                                          origin[1])

            allow_placement = True
            for object_idx, diff in difference.items():
                new_area = objects_area[object_idx]['current'] - diff
                visibility_portion = new_area / objects_area[object_idx][
                    'original']
                if visibility_portion < visibility_threshold:
                    #sly.logger.warn(f"Object '{idx}', attempt {attempt + 1}: "
                    #                f"visible portion ({visibility_portion}) < threshold ({visibility_threshold})")
                    allow_placement = False
                    break

            if allow_placement is True:
                find_place = True
                break
            else:
                continue

        if find_place is False:
            sly.logger.warn(
                f"Object '{idx}' is skipped: can not be placed to satisfy visibility threshold"
            )
            continue

        try:
            aug.place_fg_to_bg(label_img, label_mask, res_image, origin[0],
                               origin[1])
            g.draw(cover_img, color=idx)

            for object_idx, diff in difference.items():
                objects_area[object_idx]['current'] -= diff

            current_obj_area = g.area
            objects_area[idx]['current'] = current_obj_area
            objects_area[idx]['original'] = current_obj_area
            res_labels.append(sly.Label(g, res_meta.get_obj_class(class_name)))

        except Exception as e:
            #sly.logger.warn(repr(e))
            sly.logger.warn(
                f"FG placement error:: label shape: {label_img.shape}; mask shape: {label_mask.shape}",
                extra={"error": repr(e)})

        progress.iter_done_report()
        if idx % progress_every == 0:  # progress.need_report():
            progress_cb(api, task_id, progress)

    progress_cb(api, task_id, progress)

    res_ann = sly.Annotation(img_size=bg.shape[:2], labels=res_labels)

    # debug visualization
    # sly.image.write(os.path.join(cache_dir, "__res_img.png"), res_image)
    #res_ann.draw(res_image)
    #sly.image.write(os.path.join(cache_dir, "__res_ann.png"), res_image)

    res_meta, res_ann = rasterize.convert_to_nonoverlapping(res_meta, res_ann)

    return res_image, res_ann, res_meta