6

I'm trying to detect all the rectangles from the relational database. But some of the boxes are not being detected by my script. Please help me to do that. Thank you.

The Image: This is the image that I want to detect.

My Code:

#!/usr/bin/python
import cv2
import numpy as np

im = cv2.imread("table.png")

image = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(image,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

edge = cv2.Canny(thresh,30,200)
cont = cv2.findContours(edge,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]

for j,i in enumerate(cont):
   x,y,w,h = cv2.boundingRect(i)

   if (w*h>900):
     cv2.drawContours(image,[i],0,(0,0,255),3)

cv2.imshow("Image",image)

cv2.waitKey(0)  

OUTPUT:

My output

nathancy
  • 42,661
  • 14
  • 115
  • 137
  • Arrows also create some rectangles, detecting them is a problem for you ? – Yunus Temurlenk Jan 30 '20 at 06:01
  • which rectangles ? are they always the same, or does it change each try ? – sxeros Jan 30 '20 at 06:19
  • Yunus Temurlenk I don't want to detect those arrows.and in some of the rectangle and some the rectangles are incompletely recognized. – Naveen Kumar J Jan 30 '20 at 06:26
  • 1
    @NaveenKumarJ you can use [houghline](https://docs.opencv.org/3.4/d9/db0/tutorial_hough_lines.html) but first you should find a way to get rid of the arrows. – Yunus Temurlenk Jan 30 '20 at 07:04
  • Please search this forum or Google for other similar questions and their answers. – fmw42 Jan 30 '20 at 07:25
  • Does this answer your question? [Finding location of rectangles in an image with OpenCV](https://stackoverflow.com/questions/2068013/finding-location-of-rectangles-in-an-image-with-opencv) – Rick M. Jan 30 '20 at 12:11

1 Answers1

11

Here's an simple approach using thresholding + morphological operations.

  1. Obtain binary image. Load image, convert to grayscale, then adaptive threshold

  2. Fill rectangular contours. Find contours and fill the contours to create filled rectangular blocks.

  3. Perform morph open. We create a rectangular structuring element and morph open to remove the lines

  4. Draw rectangle. Find contours and draw bounding rectangles.


Here's each step visualized:

Using this screenshotted image (contains more border since the provided image has the rectangles too close to the border). You could add a border to the input image instead of screenshotting for more border area. Take a look at add border to image

Binary image

Filled rectangular contours

Morph open

Result


Code

import cv2

# Load iamge, grayscale, adaptive threshold
image = cv2.imread('1.png')
result = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,51,9)

# Fill rectangular contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(thresh, [c], -1, (255,255,255), -1)

# Morph open
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=4)

# Draw rectangles
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)

cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()

Note: Depending on the image, you may have to modify the kernel size. For instance, it may be necessary to increase the kernel from (5, 5) to say (11, 11). In addition, you could increase or decrease the number of iterations when performing cv2.morphologyEx(). There is a trade-off when increasing or decreasing the kernel size as you may remove more or less of the lines. Again, it all varies depending on the input image.

nathancy
  • 42,661
  • 14
  • 115
  • 137