11from __future__ import annotations
2- from typing import Tuple , Union
2+ from typing import Any , Dict , Iterable , List , Tuple , Union
33import cv2
44import math
55import numpy as np
1919logger = logging .getLogger (__name__ )
2020
2121
22- def np_arr_img_to_bytes (arr , format = 'JPEG' ) -> bytes :
22+ def np_arr_img_to_bytes (arr , format : str = 'JPEG' ) -> bytes :
23+ """
24+ **Convert a NumPy array to bytes**
25+
26+ Args:
27+ arr: The NumPy array to convert
28+ format: The format of the image. Defaults to "JPEG".
29+
30+ Returns:
31+ bytes: The image as bytes
32+ """
2333 return image_to_bytes (Image .fromarray (arr , 'RGB' ), format = format )
2434
2535
26- def image_to_bytes (image : Image , format = "JPEG" ) -> bytes :
36+ def image_to_bytes (image : Image , format : str = "JPEG" ) -> bytes :
37+ """
38+ **Convert an image to bytes**
39+
40+ Args:
41+ image (PIL.Image): The image to convert
42+ format (str, optional): The format of the image. Defaults to "JPEG".
43+
44+ Returns:
45+ bytes: The image as bytes
46+ """
2747 with BytesIO () as bytes :
2848 image .save (bytes , format = format )
2949 return bytes .getvalue ()
3050
3151
32- def rotate (points , angle , c_x = None , c_y = None ):
52+ def rotate (points , angle , c_x = 0 , c_y = 0 ):
3353 """
3454 **Rotate a set of points around a center**
55+
56+ Args:
57+ points: The points to rotate; iterable of (x, y) pairs
58+ angle: The angle of counterclockwise rotation in degrees
59+ c_x: The x coordinate of the center of rotation
60+ c_y: The y coordinate of the center of rotation
61+
62+ Returns:
63+ points: The rotated points as a NumPy array of shape (n,2) and type int
3564 """
3665 ANGLE = np .deg2rad (angle )
3766 return np .array (
3867 [
3968 [
40- c_x + np .cos (ANGLE ) * (px - c_x ) - np .sin (ANGLE ) * (py - c_x ),
41- c_y + np .sin (ANGLE ) * (px - c_y ) + np .cos (ANGLE ) * (py - c_y )
69+ c_x + np .cos (ANGLE ) * (px - c_x ) - np .sin (ANGLE ) * (py - c_y ),
70+ c_y + np .sin (ANGLE ) * (px - c_x ) + np .cos (ANGLE ) * (py - c_y )
4271 ]
4372 for px , py in points
4473 ]
@@ -49,12 +78,15 @@ def resolve(points: np.array, image_meta, operations) -> np.array:
4978 """
5079 **Resolve the coordinates of a bounding box to the original image size**
5180
81+ Given an array of (x,y) points with respect to the coordinates of an image, returns the corresponding coordinates with respect to a the resized or rotated image that resulted from a series of operations.
82+
5283 Args:
53- coordinates (dict ): The coordinates of the bounding box
84+ points (NumPy array ): The coordinates of the bounding box; shape (...,2)
5485 image (dict): The image properties
86+ operations (list): The operations applied to the image
5587
5688 Returns:
57- dict : The resolved coordinates
89+ resolved_points (NumPy array) : The resolved coordinates, same shape as points
5890 """
5991 resolved = points .copy ()
6092 if image_meta ["adb_image_width" ] and image_meta ["adb_image_height" ]:
@@ -94,6 +126,9 @@ class Images(Entities):
94126 ***It includes utility methods to visualize image and annotations**
95127 Inter convert the representation into NumPy matrices and find similar images,
96128 related bounding boxes, etc.
129+
130+ Args:
131+ db: The database connector, perhaps as returned by `Utils.create_connector`
97132 """
98133 db_object = "_Image"
99134
@@ -153,27 +188,27 @@ def __init__(self, db, batch_size=100, response=None, **kwargs):
153188
154189 self .db_connector = db
155190
156- self .images = {}
157- self .images_ids = []
158- self .image_sizes = []
159- self .images_bboxes = {}
191+ self .images = {}
192+ self .images_ids = []
193+ self .image_sizes = []
194+ self .images_bboxes = {}
160195 self .images_polygons = {}
161196 self .overlays = []
162197 self .color_for_tag = {}
163198
164199 self .constraints = None
165- self .operations = None
166- self .format = None
167- self .limit = None
168- self .query = None
200+ self .operations = None
201+ self .format = None
202+ self .limit = None
203+ self .query = None
169204
170205 self .adjacent = {}
171206
172207 self .batch_size = batch_size
173208 self .total_cached_images = 0
174209 self .display_limit = 20
175210
176- self .img_id_prop = "_uniqueid"
211+ self .img_id_prop = "_uniqueid"
177212 self .bbox_label_prop = "_label"
178213 self .get_image = True
179214
@@ -204,10 +239,10 @@ def __retrieve_batch(self, index):
204239 # for that batch
205240
206241 total_batches = math .ceil (len (self .images_ids ) / self .batch_size )
207- batch_id = int (math .floor (index / self .batch_size ))
242+ batch_id = int (math .floor (index / self .batch_size ))
208243
209244 start = batch_id * self .batch_size
210- end = min (start + self .batch_size , len (self .images_ids ))
245+ end = min (start + self .batch_size , len (self .images_ids ))
211246
212247 query = []
213248
@@ -290,8 +325,8 @@ def __retrieve_polygons(self, index, constraints, tag_key, tag_format):
290325 res , _ = self .db_connector .query (query )
291326
292327 polygons = []
293- bounds = []
294- tags = []
328+ bounds = []
329+ tags = []
295330 meta = []
296331 polys = res [1 ]["FindPolygon" ]["entities" ]
297332 operations = self .query ["operations" ] if self .query and "operations" in self .query else [
@@ -380,7 +415,7 @@ def __retrieve_bounding_boxes(self, index, constraints):
380415 try :
381416 res , images = self .db_connector .query (query )
382417 bboxes = []
383- tags = []
418+ tags = []
384419 meta = []
385420 bounds = []
386421 if "entities" in res [1 ]["FindBoundingBox" ]:
@@ -403,8 +438,8 @@ def __retrieve_bounding_boxes(self, index, constraints):
403438 f"Cannot retrieve bounding boxes for image { uniqueid } " , exc_info = True )
404439 finally :
405440 self .images_bboxes [uniqueid_str ]["bboxes" ] = bboxes
406- self .images_bboxes [uniqueid_str ]["tags" ] = tags
407- self .images_bboxes [uniqueid_str ]["meta" ] = meta
441+ self .images_bboxes [uniqueid_str ]["tags" ] = tags
442+ self .images_bboxes [uniqueid_str ]["meta" ] = meta
408443 self .images_bboxes [uniqueid_str ]["bounds" ] = bounds
409444
410445 def total_results (self ) -> int :
@@ -493,9 +528,9 @@ def search(self, constraints=None, operations=None, format=None, limit=None, sor
493528 """
494529
495530 self .constraints = constraints
496- self .operations = operations
497- self .format = format
498- self .limit = limit
531+ self .operations = operations
532+ self .format = format
533+ self .limit = limit
499534
500535 self .images = {}
501536 self .images_ids = []
@@ -745,9 +780,9 @@ def __draw_polygon_and_tag(self, image, polygon, tag, bounds, meta, deferred_tag
745780 self .__draw_polygon (image , polygon , color )
746781
747782 if tag :
748- left = bounds ["x" ]
749- top = bounds ["y" ]
750- right = bounds ["x" ] + bounds ["width" ]
783+ left = bounds ["x" ]
784+ top = bounds ["y" ]
785+ right = bounds ["x" ] + bounds ["width" ]
751786 FONT_WIDTH = 10
752787 FONT_HEIGHT = 16
753788
@@ -769,23 +804,25 @@ def display(self,
769804 limit : Union [int , object ] = None ,
770805 polygon_constraints : Constraints = None ,
771806 polygon_tag_key : str = "_label" ,
772- polygon_tag_format : str = "{}" ):
807+ polygon_tag_format : str = "{}" ) -> None :
773808 """
774809 **Display images with annotations**
775- show_bboxes: bool, optional
776- Show bounding boxes, by default False
777- bbox_constraints: Constraints, optional
778- Constraints for bounding boxes, by default None
779- show_polygons: bool, optional
780- Show polygons, by default False
781- limit: Union[int, object], optional
782- Number of images to display, by default None
783- polygon_constraints: Constraints, optional
784- Constraints for polygons, by default None
785- polygon_tag_key: str, optional
786- Key for the polygon tag, by default "_label"
787- polygon_tag_format: str, optional
788- Format for the polygon tag, by default "{}"
810+
811+ Args:
812+ show_bboxes: bool, optional
813+ Show bounding boxes, by default False
814+ bbox_constraints: Constraints, optional
815+ Constraints for bounding boxes, by default None
816+ show_polygons: bool, optional
817+ Show polygons, by default False
818+ limit: Union[int, object], optional
819+ Number of images to display, by default None
820+ polygon_constraints: Constraints, optional
821+ Constraints for polygons, by default None
822+ polygon_tag_key: str, optional
823+ Key for the polygon tag, by default "_label"
824+ polygon_tag_format: str, optional
825+ Format for the polygon tag, by default "{}"
789826 """
790827 if not limit :
791828 limit = self .display_limit
@@ -803,7 +840,7 @@ def display(self,
803840 limit -= 1
804841
805842 uniqueid = str (self .images_ids [i ])
806- image = self .get_image_by_index (i )
843+ image = self .get_image_by_index (i )
807844
808845 # Just decode the image from buffer
809846 nparr = np .frombuffer (image , dtype = np .uint8 )
@@ -815,7 +852,7 @@ def display(self,
815852 self .__retrieve_bounding_boxes (i , bbox_constraints )
816853
817854 bboxes = self .images_bboxes [uniqueid ]["bboxes" ]
818- tags = self .images_bboxes [uniqueid ]["tags" ]
855+ tags = self .images_bboxes [uniqueid ]["tags" ]
819856 meta = self .images_bboxes [uniqueid ]["meta" ]
820857 bounds = self .images_bboxes [uniqueid ]["bounds" ]
821858
@@ -860,8 +897,13 @@ def display(self,
860897 fig1 , ax1 = plt .subplots ()
861898 plt .imshow (image )
862899
863- def get_props_names (self ):
900+ def get_props_names (self ) -> List [str ]:
901+ """
902+ **Get the names of the properties that apply to images**
864903
904+ Returns:
905+ properties (List[str]): The names of the properties of the images
906+ """
865907 dbutils = Utils .Utils (self .db_connector )
866908 schema = dbutils .get_schema ()
867909
@@ -874,8 +916,16 @@ def get_props_names(self):
874916
875917 return props_array
876918
877- def get_properties (self , prop_list = []):
919+ def get_properties (self , prop_list : Iterable [str ] = []) -> Dict [str , Any ]:
920+ """
921+ **Get the properties of the images**
922+
923+ Args:
924+ prop_list (List[str], optional): The list of properties to retrieve. Defaults to [].
878925
926+ Returns:
927+ property_values Dict[str, Any]: The properties of the images
928+ """
879929 if len (prop_list ) == 0 :
880930 return {}
881931
0 commit comments