Sagar Bharadwaj commited on
Commit
68b9a41
·
1 Parent(s): 5461b2c

Added centroid calculation using polylabel

Browse files
colorbynumber/gen_islands.py CHANGED
@@ -1,5 +1,6 @@
1
  import cv2 as cv
2
  import numpy as np
 
3
 
4
  class GenerateIslands:
5
  def __init__(self, indices_color_choices,):
@@ -14,6 +15,12 @@ class GenerateIslands:
14
  self.island_fills = {}
15
  for color_index in np.unique(indices_color_choices):
16
  self.island_fills[color_index] = []
 
 
 
 
 
 
17
 
18
  def _is_valid_shape(self, contours, hierarchy, total_area, area_perc_threshold,
19
  arc_length_area_ratio_threshold):
@@ -64,14 +71,44 @@ class GenerateIslands:
64
  area_perc_threshold = area_perc_threshold,
65
  arc_length_area_ratio_threshold = arc_length_area_ratio_threshold
66
  )
 
 
 
 
67
  if is_valid_shape:
68
  for cntr_id, contour in enumerate(contours):
69
  area_fraction_perc = (cv.contourArea(contour) / total_area) * 100
70
  if area_fraction_perc >= area_perc_threshold:
71
  cv.drawContours(contours_image, contours, cntr_id, (0,255,0), 1)
 
 
72
 
73
  # If the shape is not valid, return a blank image
74
- return contours_image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
 
77
  def _get_islands_for_one_color(self, color_index, border_padding, area_perc_threshold,
@@ -90,12 +127,19 @@ class GenerateIslands:
90
 
91
 
92
  # Get cleaned up contours
93
- cleaned_up_contours = self._get_cleaned_up_contours(
94
  island_fill = this_component,
95
  area_perc_threshold = area_perc_threshold,
96
  arc_length_area_ratio_threshold = arc_length_area_ratio_threshold
97
  )
98
 
 
 
 
 
 
 
 
99
  contour_border_coords = np.where(cleaned_up_contours == 0)
100
  self.island_borders[color_index].append((color_index, contour_border_coords))
101
 
@@ -112,8 +156,11 @@ class GenerateIslands:
112
 
113
  # Flatten the list of borders
114
  island_borders_list = []
 
115
  for color_id in self.island_borders:
116
- island_borders_list += [border_coords for border_coords in self.island_borders[color_id]
117
- if len(border_coords[1][0]) > 0]
 
 
118
 
119
- return island_borders_list
 
1
  import cv2 as cv
2
  import numpy as np
3
+ from polylabel import polylabel
4
 
5
  class GenerateIslands:
6
  def __init__(self, indices_color_choices,):
 
15
  self.island_fills = {}
16
  for color_index in np.unique(indices_color_choices):
17
  self.island_fills[color_index] = []
18
+
19
+ # Coordinate of centroids of islands
20
+ self.island_centroids = {}
21
+ for color_index in np.unique(indices_color_choices):
22
+ self.island_centroids[color_index] = []
23
+
24
 
25
  def _is_valid_shape(self, contours, hierarchy, total_area, area_perc_threshold,
26
  arc_length_area_ratio_threshold):
 
71
  area_perc_threshold = area_perc_threshold,
72
  arc_length_area_ratio_threshold = arc_length_area_ratio_threshold
73
  )
74
+
75
+ contours_selected = []
76
+ hierarchy_selected = []
77
+
78
  if is_valid_shape:
79
  for cntr_id, contour in enumerate(contours):
80
  area_fraction_perc = (cv.contourArea(contour) / total_area) * 100
81
  if area_fraction_perc >= area_perc_threshold:
82
  cv.drawContours(contours_image, contours, cntr_id, (0,255,0), 1)
83
+ contours_selected.append(contour)
84
+ hierarchy_selected.append(hierarchy[0][cntr_id])
85
 
86
  # If the shape is not valid, return a blank image
87
+ return contours_image, \
88
+ contours_selected, \
89
+ np.array(hierarchy_selected)
90
+
91
+
92
+ def _get_centroid_for_island(self, contours, hierarchy):
93
+ if len(contours) == 0:
94
+ return np.array([np.nan, np.nan])
95
+
96
+ coordinates_for_polylabel = []
97
+
98
+ external_contours_ids = np.where(hierarchy[:,-1] == -1)[0]
99
+ for external_contour_id in external_contours_ids:
100
+ epsilon = 0.01 * cv.arcLength(contours[external_contour_id],True)
101
+ approx_contour = cv.approxPolyDP(contours[external_contour_id], epsilon, True)
102
+ coordinates_for_polylabel.append(approx_contour.squeeze())
103
+
104
+ holes_contours_ids = np.where(hierarchy[:,-1] != -1)[0]
105
+ for hole_contour_id in holes_contours_ids:
106
+ epsilon = 0.01 * cv.arcLength(contours[hole_contour_id],True)
107
+ approx_contour = cv.approxPolyDP(contours[hole_contour_id], epsilon, True)
108
+ coordinates_for_polylabel.append(approx_contour.squeeze())
109
+
110
+ centroid_coords = polylabel(coordinates_for_polylabel)
111
+ return [int(centroid_coords[0]), int(centroid_coords[1])]
112
 
113
 
114
  def _get_islands_for_one_color(self, color_index, border_padding, area_perc_threshold,
 
127
 
128
 
129
  # Get cleaned up contours
130
+ cleaned_up_contours, contours_selected, hierarchies_selected = self._get_cleaned_up_contours(
131
  island_fill = this_component,
132
  area_perc_threshold = area_perc_threshold,
133
  arc_length_area_ratio_threshold = arc_length_area_ratio_threshold
134
  )
135
 
136
+ # Get the centroid of the island
137
+ centroid_coords = self._get_centroid_for_island(
138
+ contours_selected,
139
+ hierarchies_selected
140
+ )
141
+ self.island_centroids[color_index].append(centroid_coords)
142
+
143
  contour_border_coords = np.where(cleaned_up_contours == 0)
144
  self.island_borders[color_index].append((color_index, contour_border_coords))
145
 
 
156
 
157
  # Flatten the list of borders
158
  island_borders_list = []
159
+ centroid_coords_list = []
160
  for color_id in self.island_borders:
161
+ for idx, border_coords in enumerate(self.island_borders[color_id]):
162
+ if len(border_coords[1][0]) > 0:
163
+ island_borders_list.append(self.island_borders[color_id][idx])
164
+ centroid_coords_list.append(self.island_centroids[color_id][idx])
165
 
166
+ return island_borders_list, centroid_coords_list
colorbynumber/numbered_islands.py CHANGED
@@ -8,7 +8,7 @@ def _get_centroid(coordinates):
8
  return (int(np.mean(rows)), int(np.mean(cols)))
9
 
10
 
11
- def _add_text_to_image(image, text, position, font_size=1, font_color=(0, 0, 0)):
12
  """Add text to an image.
13
 
14
  Args:
@@ -22,8 +22,7 @@ def _add_text_to_image(image, text, position, font_size=1, font_color=(0, 0, 0))
22
  """
23
  font = cv2.FONT_HERSHEY_SIMPLEX
24
  font_scale = font_size
25
- font_thickness = 4
26
- position = (position[1], position[0])
27
  return cv2.putText(
28
  image,
29
  text,
@@ -36,7 +35,9 @@ def _add_text_to_image(image, text, position, font_size=1, font_color=(0, 0, 0))
36
  )
37
 
38
 
39
- def create_numbered_islands(islands, image_shape, border_color=[0, 0, 0],
 
 
40
  padding=2, show_numbers=True, binary = False):
41
  """Create a new image with the islands numbered.
42
 
@@ -52,12 +53,15 @@ def create_numbered_islands(islands, image_shape, border_color=[0, 0, 0],
52
  numbered_islands = np.ones((width + padding*2, height + padding*2, channels),
53
  dtype=np.uint8) * 255
54
 
55
- for color_id, island_coordinates in islands:
56
  numbered_islands[island_coordinates] = border_color
57
 
58
  # Add the number to the centroid of the island
59
  if show_numbers:
60
- centroid = _get_centroid(island_coordinates)
 
 
 
61
  if not np.isnan(centroid).any():
62
  numbered_islands = _add_text_to_image(
63
  numbered_islands,
 
8
  return (int(np.mean(rows)), int(np.mean(cols)))
9
 
10
 
11
+ def _add_text_to_image(image, text, position, font_size=0.5, font_color=(0, 0, 0)):
12
  """Add text to an image.
13
 
14
  Args:
 
22
  """
23
  font = cv2.FONT_HERSHEY_SIMPLEX
24
  font_scale = font_size
25
+ font_thickness = 2
 
26
  return cv2.putText(
27
  image,
28
  text,
 
35
  )
36
 
37
 
38
+ def create_numbered_islands(islands, image_shape,
39
+ centroid_coords_list = None,
40
+ border_color=[0, 0, 0],
41
  padding=2, show_numbers=True, binary = False):
42
  """Create a new image with the islands numbered.
43
 
 
53
  numbered_islands = np.ones((width + padding*2, height + padding*2, channels),
54
  dtype=np.uint8) * 255
55
 
56
+ for idx, (color_id, island_coordinates) in enumerate(islands):
57
  numbered_islands[island_coordinates] = border_color
58
 
59
  # Add the number to the centroid of the island
60
  if show_numbers:
61
+ if centroid_coords_list:
62
+ centroid = centroid_coords_list[idx]
63
+ else:
64
+ centroid = _get_centroid(island_coordinates)
65
  if not np.isnan(centroid).any():
66
  numbered_islands = _add_text_to_image(
67
  numbered_islands,