2
votes

[![enter image description here][1]][1]I have a really noisy image that I have to perform OCR on. The snippet attached is part of a bigger image. How would I go about pre-processing this image in the most optimal way?

I have already tried pre-processing the image using Otsu Binarization, smoothing the image using various filters and Erosion-Dilation. I've also used connectedComponentWithStats to remove the noise in the image. But none of this helps with the processing of the smudged text

Edit - This text needs to be pre-processed in order to perform OCR

img = cv2.imread(file,0)
gaus = cv2.GaussianBlur(img,(5,5),0)

_, blackAndWhite = cv2.threshold(gaus, 127, 255, cv2.THRESH_BINARY_INV)

nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(blackAndWhite, None, None, None, 8, cv2.CV_32S)
sizes = stats[1:, -1] 
img2 = np.zeros((labels.shape), np.uint8)

for i in range(0, nlabels - 1):
    if sizes[i] >= 50:  
        img2[labels == i + 1] = 255

res = cv2.bitwise_not(img2)

(thresh, img_bin) = cv2.threshold(img, 128, 255,cv2.THRESH_BINARY|     cv2.THRESH_OTSU)

img_bin = 255-img_bin 

kernel_length = np.array(img).shape[1]//80

verticle_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, kernel_length))

hori_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_length, 1))

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

img_temp1 = cv2.erode(img_bin, verticle_kernel, iterations=3)
verticle_lines_img = cv2.dilate(img_temp1, verticle_kernel, iterations=3)

img_temp2 = cv2.erode(img_bin, hori_kernel, iterations=3)
horizontal_lines_img = cv2.dilate(img_temp2, hori_kernel, iterations=3)

alpha = 0.5
beta = 1.0 - alpha

img_final_bin = cv2.addWeighted(verticle_lines_img, alpha, horizontal_lines_img, beta, 0.0)

img_final_bin = cv2.erode(~img_final_bin, kernel, iterations=2)
(thresh, img_final_bin) = cv2.threshold(img_final_bin, 128,255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
1
post original image - lucians

1 Answers

2
votes

Here's an approach to remove the noise

  • Convert image to grayscale and Otsu's threshold
  • Perform morphological transformations to smooth image
  • Find contours and filter using contour area
  • Invert image

After converting to grayscale, we Otsu's threshold to obtain a binary image

[![enter image description here][1]][1]

From here we create a kernel and perform morphological opening to smooth the image. You could try using different kernels sizes here to remove more noise but increasing the kernel size will also remove text detail

[![enter image description here][2]][2]

Next we find contours and filter using contour area with a maximum threshold area to remove the small particles. We fill in the contour to effectively remove the noise

[![enter image description here][3]][3]

Finally we invert the image to get our result

[![enter image description here][4]][4]

import cv2
import numpy as np

image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)

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:
    area = cv2.contourArea(c)
    if area < 150:
        cv2.drawContours(opening, [c], -1, (0,0,0), -1)

result = 255 - opening 
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('result', result)
cv2.waitKey()