I'll assume that it's indeed a "tree" of nested areas, delineated by thin black boundaries. A tree is trivially 2-colorable so if this isn't, the solution would be less obvious.
Approach:
- connected components labeling
- walk the tree from the "root" (label of top left pixel)
- find neighboring components by dilating a mask and intersecting with other components
(nlabels, labelmap, stats, centroids) = cv.connectedComponentsWithStats(im, connectivity=4, ltype=cv.CV_32S)
root_label = labelmap[0,0]
area_coloring = { root_label: False } # label -> color
work = [ root_label ]
while work:
area_label = work.pop(0)
assert area_label in area_coloring
color = area_coloring[area_label]
# adjacent areas by dilating mask and finding unique labels
mask = (labelmap == area_label).astype(np.uint8)
mask_dilated = cv.dilate(mask, kernel=None, iterations=3) # 3 iterations to bridge boundaries (1-2 pixels)
adjacent_areas = set(np.unique(labelmap[mask_dilated.astype(bool)])) - {0, area_label} # excluding background and self
areas_to_color = adjacent_areas - set(area_coloring) # - already colored
for adjacent_area in areas_to_color:
area_coloring[adjacent_area] = not color
work += areas_to_color
canvas = cv.cvtColor(im, cv.COLOR_GRAY2BGR)
for (label, color) in area_coloring.items():
if not color: continue
mask = (labelmap == label)
canvas[mask] = 186 # gray
