Rectangle coordinates from treemap image

Hi there,

how could I get the x and y coordinates defining the rectangles in a treemap image?


calculate gradient so you get edges (or draw the map with gaps). for your picture, that will be difficult because there’s hardly any contrast between some rectangles. if you assume the data is synthetic (no noise), it’ll be tolerable because you can assume that any gradient is of interest, and the magnitude isn’t.

then numpy - Python Split Treemap Image into Constituent Parts - Stack Overflow

@crackwitz Thank you! I have absolutely no noise so the gradient method sounds doable.
Could you provide me any starting point?

Sobel and a simple differentiation kernel:

image image

I’m sure you can find plenty of resources that explain how to call cv.Sobel() or cv.filter2D()


Wow! Thank you so much for this. I will find out!

I now did using canny on the cropped (white borders removed) image:

img = cv.imread('contour_treemap_test_trim.png',0)
plt.figure(figsize=(10, 6), dpi=80)
edges = cv.Canny(img,15,15)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

giving me the desired result. Now I have a 2x2634 numpy array with coordinates of the points building the white lines.

Now I am struggling with detecting/extracting the rectangle coordinates from this? Could you give me a hint how that can be achieved?

Bildschirmfoto 2021-12-15 um 09.52.05

yeah no, that’s the wrong way. Canny is a newbie trap. it might work but I’m not a fan of it.

but then turning that into a list of points is totally the wrong way to go. that’s useless data.


Switched back to the approach as you suggested:

import os
import sys
from math import *
import numpy as np
import cv2 as cv
import pprint
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
import imutils

# load trimmed image without border
src = cv.imread('contour_treemap_test_trimmed.png',0)

# add 1 pixel border around
thick = 1
src = cv.copyMakeBorder(src, thick, thick,thick,thick, cv.BORDER_CONSTANT);

scale = 1
delta = 0
ddepth = cv.CV_16S


grad_x = cv.Sobel(gray, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
grad_y = cv.Sobel(gray, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
abs_grad_x = cv.convertScaleAbs(grad_x)
abs_grad_y = cv.convertScaleAbs(grad_y)
grad = cv.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)

cnts, hierarchy= cv.findContours(grad.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_NONE)

res = []
min_len = []
for c in cnts:
    peri = cv.arcLength(c, True)
    approx = cv.approxPolyDP(c, 0.021 * peri, True)
    if len(approx) == 4:
        x,y,w,h = cv.boundingRect(approx)
        cv.rectangle(gray,(x,y),(x+w,y+h),(251, 206, 177),2)

plt.imshow(cv.rectangle(gray,(x,y),(x+w,y+h),(251, 206, 177),2))

X = np.arange(src.shape[0]*src.shape[1]).reshape(src.shape[0], src.shape[1])
#it = 44
# highlight some feature in the
# middle boxes.
fig = plt.figure(figsize=(20, 6))
ax = fig.add_subplot(111)
for it in range(0,len(res)-1):
    ax.add_patch(Rectangle((res[it][0], res[it][1]),
                        res[it][2], res[it][3],
                        fc ='none', 
                        ec ='g',
                        lw = 2))
    ax.annotate(it+1, (res[it][0]+res[it][2]/2, res[it][1]+res[it][3]/2), color='black', weight='bold', 
                fontsize=10, ha='center', va='center')

So almost there - the only thing is the missing rectangle on the right (below rectangle 18) which is not recognized accordingly because disturbed by the small contour (artifact) contained in the input image. So I would need to get rid of that small structure? How could that be achieved?

with a photo editor. because it’s clearly not part of whatever drew the treemap, but a defect added afterwards.

It actually is an artifact generated by the function generating the treemap.

a single example is very much not enough to say how to handle that in general, other than “use photoshop”

Sure - photo editor would be one option. But I want this in a scripted way. Here I paste some examples. Its always the same structure at the same place but the background changes. So the aim would be to replace the white pixels with the color of the tile it belongs to.