From 05b7f0b0642274a60bc32221e64726e9019a144b Mon Sep 17 00:00:00 2001 From: Mathieu Beligon <mathieu@feedly.com> Date: Mon, 30 Mar 2020 00:53:24 -0400 Subject: [PATCH] [runes] (blend) Add way to save and load annotations --- common/polystar/common/models/image.py | 4 ++ .../dataset/blend/examples/.gitignore | 4 +- .../research/dataset/blend/examples/logo.xml | 10 ++++ .../research/dataset/blend/image_blender.py | 5 +- .../research/dataset/labeled_image.py | 46 ++++++++++++++++++- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 robots-at-runes/research/dataset/blend/examples/logo.xml diff --git a/common/polystar/common/models/image.py b/common/polystar/common/models/image.py index 1bf4fc6..33d63c2 100644 --- a/common/polystar/common/models/image.py +++ b/common/polystar/common/models/image.py @@ -8,3 +8,7 @@ class Image(Array[int, ..., ..., 3]): @staticmethod def from_path(image_path: Path) -> "Image": return cv2.cvtColor(cv2.imread(str(image_path)), cv2.COLOR_BGR2RGB) + + def save(self, image_path: Path): + image_path.parent.mkdir(exist_ok=True, parents=True) + cv2.imwrite(str(image_path), cv2.cvtColor(self, cv2.COLOR_RGB2BGR)) diff --git a/robots-at-runes/research/dataset/blend/examples/.gitignore b/robots-at-runes/research/dataset/blend/examples/.gitignore index 5a10d97..a13af16 100644 --- a/robots-at-runes/research/dataset/blend/examples/.gitignore +++ b/robots-at-runes/research/dataset/blend/examples/.gitignore @@ -1,2 +1,2 @@ -/image_*.jpg -/labels.xml \ No newline at end of file +/image +/image_annotation \ No newline at end of file diff --git a/robots-at-runes/research/dataset/blend/examples/logo.xml b/robots-at-runes/research/dataset/blend/examples/logo.xml new file mode 100644 index 0000000..3257c42 --- /dev/null +++ b/robots-at-runes/research/dataset/blend/examples/logo.xml @@ -0,0 +1,10 @@ +<annotation> + <point> + <x>432</x> + <y>76</y> + </point> + <point> + <x>432</x> + <y>13</y> + </point> +</annotation> diff --git a/robots-at-runes/research/dataset/blend/image_blender.py b/robots-at-runes/research/dataset/blend/image_blender.py index 969394a..8e30abd 100644 --- a/robots-at-runes/research/dataset/blend/image_blender.py +++ b/robots-at-runes/research/dataset/blend/image_blender.py @@ -76,7 +76,7 @@ if __name__ == "__main__": _obj = LabeledImage( cv2.cvtColor(cv2.imread(str(EXAMPLES_DIR / "logo.png"), cv2.IMREAD_UNCHANGED), cv2.COLOR_BGRA2RGBA), - [PointOfInterest(432, 76), PointOfInterest(432, 13)], + PointOfInterest.from_annotation_file(EXAMPLES_DIR / "logo.xml"), ) _bg = cv2.cvtColor(cv2.imread(str(EXAMPLES_DIR / "back1.jpg")), cv2.COLOR_BGR2RGB) @@ -86,9 +86,10 @@ if __name__ == "__main__": for i in range(10): res = _blender.blend(_bg, _obj) + res.save(EXAMPLES_DIR, f"test_{i}") + plt.imshow(res.image) plt.plot([poi.x for poi in res.point_of_interests], [poi.y for poi in res.point_of_interests], "r.") plt.axis("off") plt.tight_layout() - plt.savefig(str(EXAMPLES_DIR / f"image_{i}.jpg")) plt.show() diff --git a/robots-at-runes/research/dataset/labeled_image.py b/robots-at-runes/research/dataset/labeled_image.py index fec3912..2d66cc3 100644 --- a/robots-at-runes/research/dataset/labeled_image.py +++ b/robots-at-runes/research/dataset/labeled_image.py @@ -1,5 +1,10 @@ from dataclasses import dataclass, field -from typing import List +from pathlib import Path +from typing import List, Dict, Any +from xml.dom.minidom import parseString + +import xmltodict +from dicttoxml import dicttoxml from polystar.common.models.image import Image @@ -9,8 +14,47 @@ class PointOfInterest: x: int y: int + def to_dict(self) -> Dict[str, int]: + return self.__dict__ + + @classmethod + def from_dict(cls, d: Dict[str, Any]): + return cls(x=int(d["x"]), y=int(d["y"])) + + @classmethod + def from_annotation_file(cls, annotation_path: Path) -> List["PointOfInterest"]: + points = xmltodict.parse(annotation_path.read_text())["annotation"]["point"] + return [PointOfInterest.from_dict(p) for p in points] + @dataclass class LabeledImage: image: Image point_of_interests: List[PointOfInterest] = field(default_factory=list) + + def save(self, directory_path: Path, name: str): + Image.save(self.image, directory_path / "image" / f"{name}.jpg") + self._save_annotation(directory_path / "image_annotation" / f"{name}.xml") + + def _save_annotation(self, annotation_path: Path): + annotation_path.parent.mkdir(exist_ok=True, parents=True) + xml = parseString( + dicttoxml( + {"annotation": {"point": [p.to_dict() for p in self.point_of_interests]}}, + attr_type=False, + root="annotation", + item_func=lambda x: x, + ) + .replace(b"<point><point>", b"<point>") + .replace(b"</point></point>", b"</point>") + ).toprettyxml() + annotation_path.write_text(xml) + + @staticmethod + def from_directory(directory_path: Path, name: str) -> "LabeledImage": + return LabeledImage( + image=Image.from_path(directory_path / "image" / f"{name}.jpg"), + point_of_interests=PointOfInterest.from_annotation_file( + directory_path / "image_annotation" / f"{name}.xml" + ), + ) -- GitLab