Beispiel #1
0
    def test_load_dicts(self):
        with open(annotations_path, "r") as f:
            annotations = Annotation.from_dicts(json.load(f))

        for annotation in annotations:
            assert isinstance(
                annotation, Annotation
            ), f"Expected component annotation but found: {type(annotation)}"
Beispiel #2
0
    def test_rotate(self):
        with open(annotations_path, "r") as f:
            components = Annotation.from_dicts(json.load(f))

        c1 = next((c for c in components if c.id == "C1"))
        rotated = deepcopy(c1)

        expected = [(253, 32), (249, 36)]
        for pt in expected:
            rotated.rotate()
            x, y, _, _ = rotated.bounding_box()
            assert pt[0] == x and pt[1] == y, f"Expected {pt} but found ({x}, {y})"
Beispiel #3
0
    def test_move_to(self):
        with open(annotations_path, "r") as f:
            components = Annotation.from_dicts(json.load(f))

        c1 = next((c for c in components if c.id == "C1"))

        _, _, w, h = c1.bounding_box()
        c1.move_to(0, 0)
        new_x, new_y, new_w, new_h = c1.bounding_box()
        assert new_x == 0
        assert new_y == 0
        assert w == new_w, f"Width was changed from {w} to {new_w}"
        assert h == new_h, f"Width was changed from {h} to {new_h}"
Beispiel #4
0
    def test_move_ports(self):
        with open(annotations_path, "r") as f:
            components = Annotation.from_dicts(json.load(f))

        c1 = next((c for c in components if c.id == "C1"))

        c1x, c1y, _, _ = c1.bounding_box()
        port = c1.children[0]
        x, y, _, _ = port.bounding_box()
        expected = (x - c1x + 10, y - c1y + 10)
        c1.move_to(10, 10)
        x, y, _, _ = port.bounding_box()
        assert (
            expected[0] == x and expected[1] == y
        ), f"Expected {expected} but found ({x}, {y})"
Beispiel #5
0
    def test_rotate_ports(self):
        with open(annotations_path, "r") as f:
            components = Annotation.from_dicts(json.load(f))

        c1 = next((c for c in components if c.id == "C1"))
        c1.children = c1.children[0:1]

        expected = [(0, -14), (-14, -4)]
        c1.move_to(0, 0)
        port = c1.children[0]
        for pt in expected:
            c1.rotate(90, np.array([0, 0]))
            x, y, _, _ = port.bounding_box()
            assert (
                abs(pt[0] - x) < 0.00001 and abs(pt[1] - y) < 0.00001
            ), f"Expected {pt} but found ({x}, {y})"
Beispiel #6
0
    def test_move_to_ports_size(self):
        with open(annotations_path, "r") as f:
            components = Annotation.from_dicts(json.load(f))

        c1 = next((c for c in components if c.id == "C1"))
        port = c1.children[0]

        x, y, _, _ = c1.bounding_box()
        px, py, w, h = port.bounding_box()
        offset_x = px - x
        offset_y = py - y

        c1.move_to(0, 0)
        x, y, new_w, new_h = port.bounding_box()
        assert offset_x == x, f"Port x offset changed from {offset_x} to {x}"
        assert offset_y == y, f"Port y offset changed from {offset_y} to {y}"
        assert w == new_w, f"Width was changed from {w} to {new_w}"
        assert h == new_h, f"Width was changed from {h} to {new_h}"
Beispiel #7
0
async def detect_connections(annotation_dicts: List[Dict[str, Any]]):
    try:
        annotations = Annotation.from_dicts(annotation_dicts)
    except Exception as e:
        raise HTTPException(status_code=400, detail=e.args[0])

    get_image_url = lambda ann: ann.target["source"]
    annotations.sort(key=get_image_url)
    results = []
    for (image_url, annotations) in groupby(annotations, get_image_url):
        annotations = list(annotations)
        image = clean_image(cv2.imread(get_image_path(image_url), cv2.IMREAD_UNCHANGED))
        edges = connect.collect_edges(image, annotations)
        edges = connect.unique_edges(edges)
        results.append(
            {
                "components": Annotation.to_dicts(annotations),
                "edges": [edge.to_dict() for edge in edges],
                "image_url": image_url,
            }
        )

    return results
Beispiel #8
0
parser = ArgumentParser()
parser.add_argument("annotations", nargs="+")
parser.add_argument("--components", required=True)
parser.add_argument("--outdir", default=".")
args = parser.parse_args()

with open(args.components, "r") as f:
    components = json.load(f)
    if type(components) is dict:
        components = sorted(components["components"].keys())

for annotations_path in args.annotations:
    print(annotations_path)
    with open(annotations_path, "r") as f:
        annotations = Annotation.from_dicts(json.load(f))

    if len(annotations) == 0:
        continue

    url = annotations[0].target["source"]
    name = url.split("/").pop()

    image_path = get_image_path(url)
    out_image = f"{args.outdir}/images/{name}"
    os.makedirs(os.path.dirname(out_image), exist_ok=True)

    if image_path != out_image:
        shutil.copyfile(image_path, out_image)

    ext_regex = re.compile("\.[^.]+$")
Beispiel #9
0
 def test_missing_parent(self, missing_parent_dicts):
     with pytest.raises(ValueError):
         Annotation.from_dicts(missing_parent_dicts)
Beispiel #10
0
 def multi_level_annotation(self):
     with open(get_test_asset_path("bq25700a.json"), "r") as f:
         return Annotation.from_dicts(json.load(f))
Beispiel #11
0
 def test_from_annotation_port_parent_id(self):
     with open(annotations_path, "r") as f:
         annotation = Annotation.from_dicts(json.load(f))[0]
     other_anno = Annotation.from_annotation(annotation)
     for child in other_anno.children:
         assert child.parent_id == other_anno.id
Beispiel #12
0
 def test_isclose(self):
     with open(annotations_path, "r") as f:
         annotation = Annotation.from_dicts(json.load(f))[0]
     other_anno = Annotation.from_annotation(annotation)
     assert annotation.isclose(other_anno)
Beispiel #13
0
 def test_isclose_diff_images(self):
     with open(annotations_path, "r") as f:
         annotation = Annotation.from_dicts(json.load(f))[0]
     other_anno = Annotation.from_annotation(annotation)
     other_anno.target["source"] += "2"
     assert not annotation.isclose(other_anno)
Beispiel #14
0
async def detect_components(body: ComponentRecognitionRequest):
    """
    Given a list of annotations and set of image URLs, find approximate matches using
    template matching. The annotations are represented as lists of IDs. The first ID
    is the annotation to match; the rest are the children to copy on the new match (ie, ports).

    If an annotation is a child annotation, restrict matches to the parent's bounding box.
    """

    try:
        existing = Annotation.from_dicts(body.annotations)
        all_annotations = [
            anno for parent_anno in existing for anno in parent_anno.flat()
        ]
        anno_dict = {anno.id: anno for anno in all_annotations}
    except Exception as e:
        raise HTTPException(status_code=400, detail=e.args[0])

    target_images = (
        AnnotationImage(
            source=url,
            content=cv2.imread(get_image_path(url), cv2.IMREAD_UNCHANGED),
        )
        for url in body.image_urls
    )

    annotations = []
    for anno_ids in body.match_ids:
        parent_id, children_ids = anno_ids[0], anno_ids[1:]
        parent = anno_dict[parent_id]
        annotations.append(parent.with_descendents(children_ids))

    annotations, child_annos = partition(lambda a: a.parent_id is None, annotations)

    # Match top-level annotation in the target images
    annotated_snippets = [
        (annotation, image_snippet(annotation)) for annotation in annotations
    ]
    matches = chain.from_iterable(
        (
            recognition.find_unique_matches(image, annotated_snippets)
            for image in target_images
        )
    )

    # If the annotation has a parent, search within the parent's bbox
    child_matches = chain.from_iterable(
        (
            detect_child_components(anno_dict[anno.parent_id], anno)
            for anno in child_annos
        )
    )

    new_annotations = []
    for match in chain(matches, child_matches):
        exists = any((match.isclose(ann) for ann in all_annotations))

        if not exists:  # Keep the closest match
            index = next(
                (i for (i, a) in enumerate(new_annotations) if match.isclose(a)), -1
            )
            if index > -1:
                existing_match = new_annotations[index]
                new_annotations[index] = (
                    match
                    if match.confidence > existing_match.confidence
                    else existing_match
                )
            else:
                new_annotations.append(match)

    return Annotation.to_dicts(new_annotations)