title: How to detect paragraphs in a text document image for a non-consistent text structure in Python OpenCV
body: <p>I am trying to identify paragraphs of text in a <code>.pdf</code> document by first converting it into an image then using OpenCV. But I am getting bounding boxes on lines of text instead of paragraphs. How can I set some threshold or some other limit to get paragraphs instead of lines?</p>
  
  <p>Here is the sample input image:</p>
  
  <p><a href="https://i.stack.imgur.com/Zufql.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Zufql.png" alt="input"></a></p>
  
  <p>Here is the output I am getting for the above sample: </p>
  
  <p><a href="https://i.stack.imgur.com/NQlUh.png" rel="noreferrer"><img src="https://i.stack.imgur.com/NQlUh.png" alt="output"></a></p>
  
  <p>I am trying to get a single bounding box on the paragraph in the middle. I am using <a href="https://stackoverflow.com/questions/23506105/extracting-text-opencv">this</a> code.</p>
  
  <pre><code>import cv2
  import numpy as np
  
  large = cv2.imread('sample image.png')
  rgb = cv2.pyrDown(large)
  small = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
  
  # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
  kernel = np.ones((5, 5), np.uint8)
  grad = cv2.morphologyEx(small, cv2.MORPH_GRADIENT, kernel)
  
  _, bw = cv2.threshold(grad, 0.0, 255.0, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
  
  kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
  connected = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel)
  
  # using RETR_EXTERNAL instead of RETR_CCOMP
  contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  #For opencv 3+ comment the previous line and uncomment the following line
  #_, contours, hierarchy = cv2.findContours(connected.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
  
  mask = np.zeros(bw.shape, dtype=np.uint8)
  
  for idx in range(len(contours)):
      x, y, w, h = cv2.boundingRect(contours[idx])
      mask[y:y+h, x:x+w] = 0
      cv2.drawContours(mask, contours, idx, (255, 255, 255), -1)
      r = float(cv2.countNonZero(mask[y:y+h, x:x+w])) / (w * h)
  
      if r &gt; 0.45 and w &gt; 8 and h &gt; 8:
          cv2.rectangle(rgb, (x, y), (x+w-1, y+h-1), (0, 255, 0), 2)
  
  
  cv2.imshow('rects', rgb)
  cv2.waitKey(0)
  </code></pre>