Coverage for backpack/annotation/driver.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-30 23:12 +0000

1import logging 

2from .annotation import Annotation 

3from typing import Iterable, Optional, Any 

4from abc import ABC, abstractmethod 

5 

6from ..geometry import Point 

7from .annotation import ( 

8 MarkerAnnotation, RectAnnotation, LabelAnnotation, LineAnnotation, PolyLineAnnotation, 

9 BoundingBoxAnnotation 

10) 

11 

12class AnnotationDriverBase(ABC): 

13 ''' Base class for annotating drawing drivers. 

14 

15 Annotation drivers provide an unified API to draw annotations on images of different backends. 

16 All annotation driver should derive from `AnnotationDriverBase`. 

17 

18 Args: 

19 parent_logger: If you want to connect the logger of the annotation driver to a parent, 

20 specify it here. 

21 ''' 

22 def __init__(self, parent_logger: Optional[logging.Logger] = None): 

23 self.logger = ( 

24 logging.getLogger(self.__class__.__name__) if parent_logger is None else 

25 parent_logger.getChild(self.__class__.__name__) 

26 ) 

27 

28 def render(self, 

29 annotations: Iterable[Annotation], 

30 context: Any 

31 ) -> Any: 

32 ''' Renders a collection of annotations on a context. 

33 

34 Args: 

35 annotations: An iterable collection of annotation type defined in this module. 

36 context: The context of the backend. Type is implementation-specific. 

37 

38 Returns: 

39 The context. 

40 ''' 

41 for anno in annotations: 

42 if isinstance(anno, LabelAnnotation): 

43 self.add_label(anno, context) 

44 elif isinstance(anno, RectAnnotation): 

45 self.add_rect(anno, context) 

46 elif isinstance(anno, MarkerAnnotation): 

47 self.add_marker(anno, context) 

48 elif isinstance(anno, LineAnnotation): 

49 self.add_line(anno, context) 

50 elif isinstance(anno, PolyLineAnnotation): 

51 self.add_polyline(anno, context) 

52 elif isinstance(anno, BoundingBoxAnnotation): 

53 self.add_bounding_box(anno, context) 

54 else: 

55 raise ValueError(f'Unknown annotation type: {type(anno)}') 

56 return context 

57 

58 @abstractmethod 

59 def add_rect(self, rect: RectAnnotation, context: Any) -> None: 

60 ''' Renders a rectangle on the frame. 

61 

62 Args: 

63 rect: A rectangle annotation. 

64 context: A backend-specific context object that was passed to the :meth:`render` method. 

65 ''' 

66 

67 @abstractmethod 

68 def add_label(self, label: LabelAnnotation, context: Any) -> None: 

69 ''' Renders a label on the frame. 

70 

71 Args: 

72 label: A label annotation. 

73 context: A backend-specific context object that was passed to the :meth:`render` method. 

74 ''' 

75 

76 @abstractmethod 

77 def add_marker(self, marker: MarkerAnnotation, context: Any) -> None: 

78 ''' Renders a marker on the frame. 

79 

80 Args: 

81 marker: A marker annotation. 

82 context: A backend-specific context object that was passed to the :meth:`render` method. 

83 ''' 

84 

85 @abstractmethod 

86 def add_line(self, label: LineAnnotation, context: Any) -> None: 

87 ''' Renders a line on the frame. 

88 

89 Args: 

90 line: A line annotation. 

91 context: A backend-specific context object that was passed to the :meth:`render` method. 

92 ''' 

93 

94 @abstractmethod 

95 def add_polyline(self, polyline: PolyLineAnnotation, context: Any) -> None: 

96 ''' Renders a polyline. 

97 

98 Args: 

99 polyline: A polyline annotation. 

100 context: A backend-specific context object that was passed to the :meth:`render` method. 

101 ''' 

102 

103 def add_bounding_box(self, bounding_box: BoundingBoxAnnotation, context: Any) -> None: 

104 ''' Renders a bounding box. 

105 

106 Args: 

107 bounding_box: A bounding box annotation. 

108 context: A backend-specific context object that was passed to the :meth:`render` method. 

109 ''' 

110 rect = bounding_box.rectangle 

111 annos = [RectAnnotation(rect=rect, color=bounding_box.color)] 

112 if bounding_box.top_label: 

113 annos.append( 

114 LabelAnnotation( 

115 point=rect.pt_min, 

116 text=bounding_box.top_label, 

117 color=bounding_box.color, 

118 horizontal_anchor=LabelAnnotation.HorizontalAnchor.LEFT, 

119 vertical_anchor=LabelAnnotation.VerticalAnchor.BOTTOM 

120 ) 

121 ) 

122 if bounding_box.bottom_label: 

123 annos.append( 

124 LabelAnnotation( 

125 point=Point(rect.pt_min.x, rect.pt_max.y), 

126 text=bounding_box.bottom_label, 

127 color=bounding_box.color, 

128 horizontal_anchor=LabelAnnotation.HorizontalAnchor.LEFT, 

129 vertical_anchor=LabelAnnotation.VerticalAnchor.TOP 

130 ) 

131 ) 

132 self.render(annos, context)