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 part 2 #248

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
45 changes: 24 additions & 21 deletions model_api/python/model_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,47 @@

__all__ = [
"ActionClassificationModel",
"add_rotated_rects",
"AnomalyDetection",
"AnomalyResult",
"classification_models",
"ClassificationModel",
"ClassificationResult",
"Contour",
"detection_models",
"DetectedKeypoints",
"DetectionModel",
"DetectionResult",
"get_contours",
"ImageModel",
"ImageResultWithSoftPrediction",
"InstanceSegmentationResult",
"VisualPromptingResult",
"ZSLVisualPromptingResult",
"PredictedMask",
"SAMVisualPrompter",
"SAMLearnableVisualPrompter",
"KeypointDetectionModel",
"TopDownKeypointDetectionPipeline",
"Label",
"MaskRCNNModel",
"Model",
"OutputTransform",
"PredictedMask",
"Prompt",
"RotatedSegmentationResult",
"SAMDecoder",
"SAMImageEncoder",
"SAMLearnableVisualPrompter",
"SAMVisualPrompter",
"SalientObjectDetectionModel",
"segmentation_models",
"SegmentationModel",
"SSD",
"TopDownKeypointDetectionPipeline",
"VisualPromptingResult",
"YOLO",
"YoloV3ONNX",
"YoloV4",
"YOLOF",
"YOLOv3ONNX",
"YOLOv4",
"YOLOv5",
"YOLOv8",
"YOLOF",
"YOLOX",
"SAMDecoder",
"SAMImageEncoder",
"ClassificationResult",
"Prompt",
"DetectionResult",
"DetectedKeypoints",
"classification_models",
"detection_models",
"segmentation_models",
"RotatedSegmentationResult",
"add_rotated_rects",
"get_contours",
"ZSLVisualPromptingResult",
"YoloV3ONNX",
"YoloV4",
]
3 changes: 1 addition & 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,9 @@
import numpy as np

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

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

Expand Down
22 changes: 7 additions & 15 deletions model_api/python/model_api/models/result/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,13 @@
# 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,
)
from .anomaly import AnomalyResult
from .base import Result
from .classification import ClassificationResult, Label
from .detection import DetectionResult
from .keypoint import DetectedKeypoints
from .segmentation import Contour, ImageResultWithSoftPrediction, InstanceSegmentationResult, RotatedSegmentationResult
from .visual_prompting import PredictedMask, VisualPromptingResult, ZSLVisualPromptingResult

__all__ = [
"AnomalyResult",
Expand Down
33 changes: 0 additions & 33 deletions model_api/python/model_api/models/result/types/__init__.py

This file was deleted.

4 changes: 3 additions & 1 deletion model_api/python/model_api/visualizer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

from .layout import Flatten, Layout
from .primitive import Overlay
from .scene import Scene
from .visualizer import Visualizer

__all__ = ["Scene", "Visualizer"]
__all__ = ["Overlay", "Scene", "Visualizer", "Layout", "Flatten"]
37 changes: 30 additions & 7 deletions model_api/python/model_api/visualizer/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

from __future__ import annotations

from abc import ABC
from typing import TYPE_CHECKING
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Type

if TYPE_CHECKING:
import PIL
Expand All @@ -19,10 +19,33 @@
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)
def _compute_on_primitive(self, primitive: Type[Primitive], image: PIL.Image, scene: Scene) -> PIL.Image | None:
if scene.has_primitives(primitive):
primitives = scene.get_primitives(primitive)
for _primitive in primitives:
image = _primitive.compute(image)
return image
return None

@abstractmethod
def __call__(self, scene: Scene) -> PIL.Image:
"""Compute the layout."""


class Flatten(Layout):
"""Put all primitives on top of each other.

Args:
*args (Type[Primitive]): Primitives to be applied.
"""

def __init__(self, *args: Type[Primitive]) -> None:
self.children = args

def __call__(self, scene: Scene) -> PIL.Image:
_image: PIL.Image = scene.base.copy()
for child in self.children:
output = self._compute_on_primitive(child, _image, scene)
if output is not None:
_image = output
return _image
31 changes: 27 additions & 4 deletions model_api/python/model_api/visualizer/primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,38 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

if TYPE_CHECKING:
import PIL
import numpy as np
import PIL


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

@abstractmethod
def compute(self, image: PIL.Image, **kwargs) -> PIL.Image:
def compute(self, image: PIL.Image) -> PIL.Image:
pass


class Overlay(Primitive):
"""Overlay primitive.

Useful for XAI and Anomaly Maps.

Args:
image (PIL.Image | np.ndarray): Image to be overlaid.
opacity (float): Opacity of the overlay.
"""

def __init__(self, image: PIL.Image | np.ndarray, opacity: float = 0.4) -> None:
self.image = self._to_pil(image)
self.opacity = opacity

def _to_pil(self, image: PIL.Image | np.ndarray) -> PIL.Image:
if isinstance(image, np.ndarray):
return PIL.Image.fromarray(image)
return image

def compute(self, image: PIL.Image) -> PIL.Image:
_image = self.image.resize(image.size)
return PIL.Image.blend(image, _image, self.opacity)
40 changes: 0 additions & 40 deletions model_api/python/model_api/visualizer/scene.py

This file was deleted.

22 changes: 22 additions & 0 deletions model_api/python/model_api/visualizer/scene/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Result visualization Scene."""

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

from .anomaly import AnomalyScene
from .classification import ClassificationScene
from .detection import DetectionScene
from .keypoint import KeypointScene
from .scene import Scene
from .segmentation import SegmentationScene
from .visual_prompting import VisualPromptingScene

__all__ = [
"AnomalyScene",
"ClassificationScene",
"DetectionScene",
"KeypointScene",
"Scene",
"SegmentationScene",
"VisualPromptingScene",
]
24 changes: 24 additions & 0 deletions model_api/python/model_api/visualizer/scene/anomaly.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Anomaly Scene."""

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

from PIL import Image

from model_api.models.result import AnomalyResult
from model_api.visualizer.layout import Flatten, Layout
from model_api.visualizer.primitive import Overlay

from .scene import Scene


class AnomalyScene(Scene):
"""Anomaly Scene."""

def __init__(self, image: Image, result: AnomalyResult) -> None:
self.image = image
self.result = result

@property
def default_layout(self) -> Layout:
return Flatten(Overlay)
24 changes: 24 additions & 0 deletions model_api/python/model_api/visualizer/scene/classification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Classification Scene."""

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

from PIL import Image

from model_api.models.result import ClassificationResult
from model_api.visualizer.layout import Flatten, Layout
from model_api.visualizer.primitive import Overlay

from .scene import Scene


class ClassificationScene(Scene):
"""Classification Scene."""

def __init__(self, image: Image, result: ClassificationResult) -> None:
self.image = image
self.result = result

@property
def default_layout(self) -> Layout:
return Flatten(Overlay)
18 changes: 18 additions & 0 deletions model_api/python/model_api/visualizer/scene/detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Detection Scene."""

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

from PIL import Image

from model_api.models.result import DetectionResult

from .scene import Scene


class DetectionScene(Scene):
"""Detection Scene."""

def __init__(self, image: Image, result: DetectionResult) -> None:
self.image = image
self.result = result
Loading
Loading