3

I am doing OCR to extract information from the ID card. However, accuracy is quite low.

My assumption is that removing the background will make OCR more accurate.

I use the ID scanner machine (link) to obtain the grey image below. It seems that the machine uses IR instead of image processing.

Does anyone knows how to get the same result by using Opencv or tools (photoshop, gimp, etc)?

Thanks in advance.

original processed

Sơn Ninh
  • 331
  • 1
  • 10

2 Answers2

2

Here are two more methods: adaptive thresholding and division normalization.

Input:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread("green_card.jpg")

# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# do adaptive threshold on gray image
thresh1 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 51, 25)

# write results to disk
cv2.imwrite("green_card_thresh1.jpg", thresh1)


# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (11,11))
morph = cv2.morphologyEx(gray, cv2.MORPH_DILATE, kernel)

# divide gray by morphology image
division = cv2.divide(gray, morph, scale=255)

# threshold
thresh2 = cv2.threshold(division, 0, 255, cv2.THRESH_OTSU )[1] 

# write results to disk
cv2.imwrite("green_card_thresh2.jpg", thresh2)

# display it
cv2.imshow("thresh1", thresh1)
cv2.imshow("thresh2", thresh2)
cv2.waitKey(0)


Adaptive Thresholding Result:

enter image description here

Division Normalization Result:

enter image description here

fmw42
  • 46,825
  • 10
  • 62
  • 80
1

EDIT:

since there are different lighting conditions, contrast adjustment is added here.

The simple approache in my mind to solve your issue is that: since the undesired background colours are Green and Red, and the desired font colour is Black, simply suppress the Red and green colours as following:

import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread, imsave
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
from skimage import exposure


def adjustContrast(img):
    p2, p98 = np.percentile(img, (2, 98))
    img_rescale = exposure.rescale_intensity(img, in_range=(p2, p98))
    return img_rescale

# Read the image
img = imread('ID_OCR.jpg')

# Contrast Adjustment for each channel

img[:,:,0] = adjustContrast(img[:,:,0]) # R
img[:,:,1] = adjustContrast(img[:,:,1]) # G
img[:,:,2] = adjustContrast(img[:,:,2]) # B

# # Supress unwanted colors

img[img[...,0] > 100] = 255 # R
img[img[...,1] > 100] = 255 # B


# Convert the image to graylevel
img = rgb2gray(img)

# Rescale into 0-255
img = 255*img.astype(np.uint8)

# Save the results
imsave('Result.png', img)

The image will look like:

image

The Results are not optimal, because also your image resolution isn't high.

At the end, there are many solutions, and improvements, also you can use Morphology to make it look nicer, this is just a simple proposal to solve the problem.

Bilal
  • 3,191
  • 4
  • 21
  • 49