How to remove extra whitespace from image in opencv?
Here's a simple approach:
Obtain binary image. Load the image, convert to grayscale, apply a large Gaussian blur, and then Otsu's threshold
Perform morphological operations. We first morph open with a small kernel to remove noise then morph close with a large kernel to combine the contours
Find enclosing bounding box and crop ROI. We find the coordinates of all non-zero points, find the bounding rectangle, and crop the ROI.
Here's the detected ROI to crop highlighted in green
Cropped ROI
import cv2
# Load image, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (25,25), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Perform morph operations, first open to remove noise, then close to combine
noise_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, noise_kernel, iterations=2)
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, close_kernel, iterations=3)
# Find enclosing boundingbox and crop ROI
coords = cv2.findNonZero(close)
x,y,w,h = cv2.boundingRect(coords)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
crop = original[y:y+h, x:x+w]
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.imshow('crop', crop)
cv2.waitKey()
I am the original author of the code that you tried. The reason why it didn't work was because you have some noisy pixels that are surrounding the text that is throwing off the algorithm. If you remove the noise with a simple opening morphological operation, you get the result you need. This was in fact done in the second version of my answer which you unfortunately didn't try:
import cv2
import numpy as np
gray = load_image(IMG_FILE) # image file
# Threshold the image so that black text is white
gray = 255*(gray < 128).astype(np.uint8)
# Additionally do an opening operation with a 2 x 2 kernel
O = np.ones(2, dtype=np.uint8)
gray_morph = cv2.morphologyEx(gray, cv2.MORPH_OPEN, O)
# Continue where we left off
coords = cv2.findNonZero(gray_morph) # Find all non-zero points (text)
x, y, w, h = cv2.boundingRect(coords) # Find minimum spanning bounding box
rect = load_image(IMG_FILE)[y:y+h, x:x+w] # Crop the image
We thus get: