Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Applying a Watershed Transform based on the Distance Transform will separate the objects:</p> <p><img src="https://i.stack.imgur.com/3MT86.png" alt="enter image description here"></p> <p>Handling objects at the border is always problematic, and often discarded, so that pink rectangle at top left not separated is not a problem at all.</p> <p>Given a binary image, we can apply the Distance Transform (DT) and from it obtain markers for the Watershed. Ideally there would be a ready function for finding regional minima/maxima, but since it isn't there, we can make a decent guess on how we can threshold DT. Based on the markers we can segment using Watershed, and the problem is solved. Now you can worry about distinguishing components that are rectangles from those that are not.</p> <pre><code>import sys import cv2 import numpy import random from scipy.ndimage import label def segment_on_dt(img): dt = cv2.distanceTransform(img, 2, 3) # L2 norm, 3x3 mask dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(numpy.uint8) dt = cv2.threshold(dt, 100, 255, cv2.THRESH_BINARY)[1] lbl, ncc = label(dt) lbl[img == 0] = lbl.max() + 1 lbl = lbl.astype(numpy.int32) cv2.watershed(cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), lbl) lbl[lbl == -1] = 0 return lbl img = cv2.cvtColor(cv2.imread(sys.argv[1]), cv2.COLOR_BGR2GRAY) img = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)[1] img = 255 - img # White: objects; Black: background ws_result = segment_on_dt(img) # Colorize height, width = ws_result.shape ws_color = numpy.zeros((height, width, 3), dtype=numpy.uint8) lbl, ncc = label(ws_result) for l in xrange(1, ncc + 1): a, b = numpy.nonzero(lbl == l) if img[a[0], b[0]] == 0: # Do not color background. continue rgb = [random.randint(0, 255) for _ in xrange(3)] ws_color[lbl == l] = tuple(rgb) cv2.imwrite(sys.argv[2], ws_color) </code></pre> <p>From the above image you can consider fitting ellipses in each component to determine rectangles. Then you can use some measurement to define whether the component is a rectangle or not. This approach has a greater chance to work for rectangles that are fully visible, and will likely produce bad results for partially visible ones. The following image shows the result of such approach considering that a component is a rectangle if the rectangle from the fitted ellipse is within 10% of component's area.</p> <p><img src="https://i.stack.imgur.com/wOxZU.png" alt="enter image description here"></p> <pre><code># Fit ellipse to determine the rectangles. wsbin = numpy.zeros((height, width), dtype=numpy.uint8) wsbin[cv2.cvtColor(ws_color, cv2.COLOR_BGR2GRAY) != 0] = 255 ws_bincolor = cv2.cvtColor(255 - wsbin, cv2.COLOR_GRAY2BGR) lbl, ncc = label(wsbin) for l in xrange(1, ncc + 1): yx = numpy.dstack(numpy.nonzero(lbl == l)).astype(numpy.int64) xy = numpy.roll(numpy.swapaxes(yx, 0, 1), 1, 2) if len(xy) &lt; 100: # Too small. continue ellipse = cv2.fitEllipse(xy) center, axes, angle = ellipse rect_area = axes[0] * axes[1] if 0.9 &lt; rect_area / float(len(xy)) &lt; 1.1: rect = numpy.round(numpy.float64( cv2.cv.BoxPoints(ellipse))).astype(numpy.int64) color = [random.randint(60, 255) for _ in xrange(3)] cv2.drawContours(ws_bincolor, [rect], 0, color, 2) cv2.imwrite(sys.argv[3], ws_bincolor) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload