0

I have multiple image with different background,

i need to ignore background and extract Number from my image. ex:

Original

Original with different background

Original diff 3

after test, i have this result :

thresh

because of background color, it's very difficult to extract text..

i'm using this code:

image = cv2.imread('AA.png')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 165, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]



# Invert image and perform morphological operations
inverted = 255 - thresh
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,3))
close = cv2.morphologyEx(inverted, cv2.MORPH_CLOSE, kernel, iterations=1)

# Find contours and filter using aspect ratio and area
cnts = cv2.findContours(close, 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)
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.01 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    aspect_ratio = w / float(h)
    if (aspect_ratio >= 2.5 or area < 75):
        cv2.drawContours(thresh, [c], -1, (255,255,255), -1)

# Blur and perform text extraction
thresh = cv2.GaussianBlur(thresh, (3,3), 0)
data = pytesseract.image_to_string(thresh, lang='eng',config='tessedit_char_whitelist=0123456789 --psm 6')
print(data)


cv2.imshow('close', close)
cv2.imshow('thresh', thresh)
cv2.waitKey()

How i can extract number from this image with accuracy even if background color change?

Edit result after modification:

comment

Kate
  • 320
  • 1
  • 6
  • 19
  • Your thresholding is not very good. Remove `gray[gray < 100] = 255`. The try cv2.threshold at 165. Then get contours and remove contours that are too small. Then invert the thresh image as (255 - thresh) so that the letters are black on a white background. – fmw42 Oct 26 '19 at 18:09
  • @fmw42, you right about gray, i have updated my first post with your parameter on the last image, i lost the text number "1" on top of image, how i fix it? – Kate Oct 26 '19 at 19:22

1 Answers1

2

Your thresholding is your problem. Here is how I would process the image in Python/OpenCV before doing OCR.

I simply threshold at 165 to make the letters white and the background black. Then filter contours on area to remove the small extraneous white regions. Then invert the results so that you have black letters on white background.

Input:

enter image description here

import cv2
import numpy as np

# load image as HSV and select saturation
img = cv2.imread("numbers.png")
hh, ww, cc = img.shape

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

# threshold the grayscale image
ret, thresh = cv2.threshold(gray,165,255,0)

# create black image to hold results
results = np.zeros((hh,ww))

# find contours
cntrs = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]

# Contour filtering and copy contour interior to new black image.
for c in cntrs:
    area = cv2.contourArea(c)
    if area > 1000:
        x,y,w,h = cv2.boundingRect(c)
        results[y:y+h,x:x+w] = thresh[y:y+h,x:x+w]

# invert the results image so that have black letters on white background
results = (255 - results)

# write results to disk
cv2.imwrite("numbers_extracted.png", results)

cv2.imshow("THRESH", thresh)
cv2.imshow("RESULTS", results)
cv2.waitKey(0)
cv2.destroyAllWindows()


Thresholded Image Before Contour Filtering:

enter image description here

Results after contour filtering and inversion:

enter image description here

P.S. cv2.inRange() may be an alternative to cv2.threshold.

And of course this solution may be limited to this one image, since other images may need different values for the threshold and area limits.

fmw42
  • 46,825
  • 10
  • 62
  • 80
  • Ok, thank you i understand my problem now! i'll test for cleaning contour of number for better result in OCR because 1 is detected "i" on another image. – Kate Oct 26 '19 at 19:49
  • @frmw42, actually with 160 in the threshold value, OCR working correctly! i don't know if is possible to test automactly multiple value for better accuracy in the threshold? – Kate Oct 26 '19 at 19:59
  • Sorry, OCR is beyond me. I have never done that. I suppose you could write a loop in your script and vary the threshold, do the OCR and see which result is best. Perhaps, try using cv2.inRange in place of simple thresholding and test it over a number of your images to see what range you need. Also perhaps thresholding or inRange in HSV colorspace on one or all channels might be worth testing. That might help to eliminate the colored regions. – fmw42 Oct 26 '19 at 22:13