Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Visualization Initial Scaffold #245

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from .instance_segmentation import MaskRCNNModel
from .keypoint_detection import KeypointDetectionModel, TopDownKeypointDetectionPipeline
from .model import Model
from .result_types import (
from .result import (
AnomalyResult,
ClassificationResult,
Contour,
Expand Down
4 changes: 2 additions & 2 deletions model_api/python/model_api/models/action_classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import numpy as np

from model_api.adapters.utils import RESIZE_TYPES, InputTransform
from model_api.models.result_types import Label
from model_api.models.result import Label

from .model import Model
from .result_types import ClassificationResult
from .result import ClassificationResult
from .types import BooleanValue, ListValue, NumericalValue, StringValue
from .utils import load_labels

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/anomaly.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import numpy as np

from model_api.models.image_model import ImageModel
from model_api.models.result_types import AnomalyResult
from model_api.models.result import AnomalyResult
from model_api.models.types import ListValue, NumericalValue, StringValue

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from openvino.runtime import opset10 as opset

from model_api.models.image_model import ImageModel
from model_api.models.result_types import ClassificationResult, Label
from model_api.models.result import ClassificationResult, Label
from model_api.models.types import BooleanValue, ListValue, NumericalValue, StringValue
from model_api.models.utils import softmax

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/detection_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np

from .image_model import ImageModel
from .result_types import DetectionResult
from .result import DetectionResult
from .types import ListValue, NumericalValue, StringValue
from .utils import load_labels

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/instance_segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from model_api.adapters.inference_adapter import InferenceAdapter

from .image_model import ImageModel
from .result_types import InstanceSegmentationResult
from .result import InstanceSegmentationResult
from .types import BooleanValue, ListValue, NumericalValue, StringValue
from .utils import load_labels

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/keypoint_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import numpy as np

from .image_model import ImageModel
from .result_types import DetectedKeypoints, DetectionResult
from .result import DetectedKeypoints, DetectionResult
from .types import ListValue


Expand Down
36 changes: 36 additions & 0 deletions model_api/python/model_api/models/result/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Model results."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from .types import (
AnomalyResult,
ClassificationResult,
Contour,
DetectedKeypoints,
DetectionResult,
ImageResultWithSoftPrediction,
InstanceSegmentationResult,
Label,
PredictedMask,
Result,
RotatedSegmentationResult,
VisualPromptingResult,
ZSLVisualPromptingResult,
)

__all__ = [
"AnomalyResult",
"ClassificationResult",
"Contour",
"DetectionResult",
"DetectedKeypoints",
"ImageResultWithSoftPrediction",
"InstanceSegmentationResult",
"Label",
"PredictedMask",
"Result",
"VisualPromptingResult",
"ZSLVisualPromptingResult",
"RotatedSegmentationResult",
]
4 changes: 4 additions & 0 deletions model_api/python/model_api/models/result/scene/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Result visualization Scene."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# SPDX-License-Identifier: Apache-2.0

from .anomaly import AnomalyResult
from .base import Result
from .classification import ClassificationResult, Label
from .detection import DetectionResult
from .keypoint import DetectedKeypoints
Expand All @@ -25,6 +26,7 @@
"ImageResultWithSoftPrediction",
"InstanceSegmentationResult",
"PredictedMask",
"Result",
"VisualPromptingResult",
"ZSLVisualPromptingResult",
"RotatedSegmentationResult",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

import numpy as np

from .base import Result

class AnomalyResult:

class AnomalyResult(Result):
"""Results for anomaly models."""

def __init__(
Expand Down
10 changes: 10 additions & 0 deletions model_api/python/model_api/models/result/types/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Base result type"""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from abc import ABC


class Result(ABC):
"""Base result type."""
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from typing import TYPE_CHECKING, Generator

from .base import Result
from .utils import array_shape_to_str

if TYPE_CHECKING:
Expand Down Expand Up @@ -35,7 +36,7 @@ def __str__(self) -> str:
return f"{self.id} ({self.name}): {self.confidence:.3f}"


class ClassificationResult:
class ClassificationResult(Result):
"""Results for classification models."""

def __init__(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

import numpy as np

from .base import Result
from .utils import array_shape_to_str


class DetectionResult:
class DetectionResult(Result):
"""Result for detection model.

Args:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

import numpy as np

from .base import Result

class DetectedKeypoints:

class DetectedKeypoints(Result):
def __init__(self, keypoints: np.ndarray, scores: np.ndarray) -> None:
self.keypoints = keypoints
self.scores = scores
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import cv2
import numpy as np

from .base import Result
from .detection import DetectionResult
from .utils import array_shape_to_str

Expand Down Expand Up @@ -157,7 +158,7 @@ def __str__(self):
return f"{self.label}: {self.probability:.3f}, {len(self.shape)}"


class ImageResultWithSoftPrediction:
class ImageResultWithSoftPrediction(Result):
def __init__(
self,
resultImage: np.ndarray,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

import numpy as np

from .base import Result

class VisualPromptingResult:

class VisualPromptingResult(Result):
def __init__(
self,
upscaled_masks: list[np.ndarray] | None = None,
Expand Down Expand Up @@ -79,7 +81,7 @@ def __str__(self) -> str:
return obj_str.strip()


class ZSLVisualPromptingResult:
class ZSLVisualPromptingResult(Result):
def __init__(self, data: dict[int, PredictedMask]) -> None:
self.data = data

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import numpy as np

from model_api.models.image_model import ImageModel
from model_api.models.result_types import Contour, ImageResultWithSoftPrediction
from model_api.models.result import Contour, ImageResultWithSoftPrediction
from model_api.models.types import BooleanValue, ListValue, NumericalValue, StringValue
from model_api.models.utils import load_labels

Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/ssd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np

from .detection_model import DetectionModel
from .result_types import DetectionResult
from .result import DetectionResult

BBOX_AREA_THRESHOLD = 1.0
SALIENCY_MAP_NAME = "saliency_map"
Expand Down
4 changes: 2 additions & 2 deletions model_api/python/model_api/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
import cv2
import numpy as np

from model_api.models.result_types import Contour, InstanceSegmentationResult, RotatedSegmentationResult
from model_api.models.result import Contour, InstanceSegmentationResult, RotatedSegmentationResult

if TYPE_CHECKING:
from model_api.models.result_types.detection import DetectionResult
from model_api.models.result.detection import DetectionResult


def add_rotated_rects(inst_seg_result: InstanceSegmentationResult) -> RotatedSegmentationResult:
Expand Down
2 changes: 1 addition & 1 deletion model_api/python/model_api/models/yolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from model_api.adapters.utils import INTERPOLATION_TYPES, resize_image_ocv

from .detection_model import DetectionModel
from .result_types import DetectionResult
from .result import DetectionResult
from .types import BooleanValue, ListValue, NumericalValue
from .utils import clip_detections, multiclass_nms, nms

Expand Down
9 changes: 9 additions & 0 deletions model_api/python/model_api/visualizer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Visualizer."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from .scene import Scene
from .visualizer import Visualizer

__all__ = ["Scene", "Visualizer"]
28 changes: 28 additions & 0 deletions model_api/python/model_api/visualizer/layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Visualization Layout"""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

from abc import ABC
from typing import TYPE_CHECKING

if TYPE_CHECKING:
import PIL

from model_api.visualizer.primitive import Primitive

from .scene import Scene


class Layout(ABC):
"""Base class for layouts."""

def _compute_on_primitive(self, primitive: Primitive, image: PIL.Image, scene: Scene) -> PIL.Image | None:
if scene.has_primitives(type(primitive)):
primitives = scene.get_primitives(type(primitive))
for primitive in primitives:
image = primitive.compute(image)
return image
return None
20 changes: 20 additions & 0 deletions model_api/python/model_api/visualizer/primitive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Base class for primitives."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

if TYPE_CHECKING:
import PIL


class Primitive(ABC):
"""Primitive class."""

@abstractmethod
def compute(self, image: PIL.Image, **kwargs) -> PIL.Image:
pass
40 changes: 40 additions & 0 deletions model_api/python/model_api/visualizer/scene.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Scene object."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from abc import abstractmethod
from typing import Type, Union

import PIL

from .layout import Layout
from .primitive import Primitive


class Scene:
"""Scene object.

Used by the visualizer to render.
"""

def __init__(
self,
base: PIL.Image,
layout: Union[Layout, list[Layout], None] = None,
) -> None: ...

def show(self) -> PIL.Image: ...

def save(self, path: str) -> None: ...

def has_primitives(self, primitive: Type[Primitive]) -> bool:
return False

def get_primitives(self, primitive: Type[Primitive]) -> list[Primitive]:
return []

@property
@abstractmethod
def default_layout(self) -> Layout:
"""Default layout for the media."""
12 changes: 12 additions & 0 deletions model_api/python/model_api/visualizer/visualizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Visualizer for modelAPI."""

# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

import PIL

from model_api.models.result import Result


class Visualizer:
def show(self, image: PIL.Image, result: Result) -> PIL.Image: ...
1 change: 1 addition & 0 deletions model_api/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies = [
"openvino>=2024.0",
"openvino-dev>=2024.0",
"omz_tools @ git+https://github.com/openvinotoolkit/open_model_zoo.git@master#egg=omz_tools&subdirectory=tools/model_tools",
"pillow",
]

[project.optional-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion tests/python/unit/results/test_cls_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

import numpy as np
from model_api.models.result_types import ClassificationResult, Label
from model_api.models.result import ClassificationResult, Label


def test_cls_result():
Expand Down
Loading