Extract digit from noisy image - python

Extract digit from noisy image
I want to extract text from an image taken by mobile phone camera.
First I try to convert the image to greyscale by using this code:
imgg = Image.open('originale.jpg').convert('LA')
Second i try to threshold the grey image to get image with only black and white with this code ::
retval, threshold = cv2.threshold(grayscaled, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imwrite("threshold.png", threshold)
Third i try to extract text with pytesseract but i have not the correct result with this code.
result5 = pytesseract.image_to_string(Image.open("threshold.png"))
This is the image which I want to extract digits number for example:
My expected output is: 111 2 11 4 1 23 2 3.
and this is my image :
originale.jpg
threshold.png
And this is my full code:
import cv2
import numpy as np
import pytesseract
from PIL import Image
img = cv2.imread('originale.jpg')
grayscaled = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
retval, threshold = cv2.threshold(grayscaled, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imwrite("threshold.png", threshold)
result = pytesseract.image_to_string(Image.open("threshold.png"))
print(result)

You can use Otsu method to determine optimal threshold value to exact your digits.
import cv2
img # this is your original image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv2.imwrite("threshold.png", threshold)
Result:

Related

Can't get numbers from image with python, Tesseract and opencv

i have to get numbers from a water-meter image usign python tesseract and opencv.
I have tried to change the --psm but it's doesn't work.
Here the image without modification :
enter image description here
Here the outpout image :
enter image description here
I need your help guys, i'm starting python and i'm already blocked :'(
My code :
from PIL import Image
import pytesseract
import cv2
import numpy as np
import urllib
import requests
pytesseract.pytesseract.tesseract_cmd = r'C:\Users\Hymed\AppData\Local\Tesseract-OCR\tesseract.exe'
col = Image.open("pts.jpg")
gray = col.convert('L')
bw = gray.point(lambda x: 0 if x<128 else 255, '1')
bw.save("cp19.png")
image = cv2.imread('cp19.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = 255 - cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Blur and perform text extraction
thresh = cv2.GaussianBlur(thresh, (3,3), 0)
img1 = np.array(thresh)
data = pytesseract.image_to_string(img1, config='--psm 11 digits')
print(data)
cv2.imshow('thresh', thresh)
cv2.waitKey()
You have nearly finished the task.
I use the divide operation, after the GaussianBlur.
div = cv2.divide(gray, thresh, scale=192)
Result:
When I read from the image:
data = pytesseract.image_to_string(div, config='--psm 11 digits')
print(data)
Result:
00000161
Code: (Just added div = cv2.divide(gray, thresh, scale=192) rest are your code)
from PIL import Image
import pytesseract
import cv2
import numpy as np
col = Image.open("TOaEW.jpg")
gray = col.convert('L')
bw = gray.point(lambda x: 0 if x < 128 else 255, '1')
bw.save("cp19.png")
image = cv2.imread('cp19.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = 255 - cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Blur and perform text extraction
thresh = cv2.GaussianBlur(thresh, (3, 3), 0)
div = cv2.divide(gray, thresh, scale=192) # added
data = pytesseract.image_to_string(div, config='--psm 11 digits')
print(data)
I tried to read the number from an image using Tesseract. Except the numbers shown in the first line, it also returned an unidentified symbol in the second line. I don't understand what I did wrong. Here is the code and the results
code and output
This is the image I extracted the number from:
Image used for number extraction

is it possible to extracting text inside colored background region using opencv in python?

I having the following table area from the original image:
I'm trying extract the text,from this table.But when using threshold the whole gray regions get darkening.For example like below,
The threshold type which i did used,
thresh_value = cv2.threshold(original_gray, 128, 255, cv2.THRESH_BINARY_INV +cv2.THRESH_OTSU)[1]
is it possible to extract and change gray background into white and lets remain text pixel as it is if black then?
You should use adaptive thresholding in Python/OpenCV.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread("text_table.jpg")
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do adaptive threshold on gray image
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 11)
# write results to disk
cv2.imwrite("text_table_thresh.jpg", thresh)
# display it
cv2.imshow("thresh", thresh)
cv2.waitKey(0)
Result

Tesseract detecting 1 and 0 as L and O

In this image tesseract is detecting the text as LOOOPCS but it is 1000PCS. Command I am using is
tesseract "item_04.png" stdout --psm 6
I have tried all psm values 0 to 13
As per suggestions by other blogs and questions on SO and internet following clipping of image as well as thresholding is also tried.
Also tried -c tessedit_char_whitelist=PCS0123456789 but that gives 00PCS.
But I am not getting 1000PCS. Can someone try these and let me know what am I missing?
Edit:
As per suggestion given by #nathancy, tried using - cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU which worked on this 1 and 0 but failed for below image. It is being detected as LL8gPcs:
You need to preprocess the image. A simple approach is to Otsu's threshold then invert the image so the text is in black with the background in white. Here's the processed image and the result using Pytesseract OCR with --psm 6.
Result
1000PCS
Code
import cv2
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
# Grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Invert and perform text extraction
thresh = 255 - thresh
data = pytesseract.image_to_string(thresh, lang='eng',config='--psm 6')
print(data)
cv2.imshow('thresh', thresh)
cv2.waitKey()

How to OCR image with Tesseract

I am starting to learn OpenCV and Tesseract, and have trouble with what seems to be a very simple example.
Here is an image that I am trying to OCR, that reads "171 m":
I do some preprocessing. Since blue is the dominant color of the text, I extract the blue channel and apply simple thresholding.
img = cv2.imread('171_m.png')[y, x, 0]
_, thresh = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY_INV)
The resulting image looks like this:
Then throw that into Tesseract, with psm 7 for single line:
text = pytesseract.image_to_string(thresh, config='--psm 7')
print(text)
>>> lim
I also tried to restrict possible characters, and it gets a bit better, but not quite.
text = pytesseract.image_to_string(thresh, config='--psm 7 -c tessedit_char_whitelist=1234567890m')
print(text)
>>> 17m
OpenCV v4.1.1.
Tesseract v5.0.0-alpha.20190708
Any help appreciated.
Before throwing the image into Pytesseract, preprocessing can help. The desired text should be in black while the background should be in white. Here's an approach
Convert image to grayscale and enlarge image
Gaussian blur
Otsu's threshold
Invert image
After converting to grayscale, we enlarge the image using imutils.resize() and Gaussian blur. From here we Otsu's threshold to get a binary image
If you have noisy images, an additional step would be to use morphological operations to smooth or remove noise. But since your image is clean enough, we can simply invert the image to get our result
Output from Pytesseract using --psm 6
171m
import cv2
import pytesseract
import imutils
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
image = cv2.imread('1.png',0)
image = imutils.resize(image, width=400)
blur = cv2.GaussianBlur(image, (7,7), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
result = 255 - thresh
data = pytesseract.image_to_string(result, lang='eng',config='--psm 6')
print(data)
cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey()
Disclaimer : This is not a solution, just a trial to partially solve this.
This process works only if you have knowledge of the number of the characters present in the image beforehand. Here is the trial code :
img0 = cv2.imread('171_m.png', 0)
adap_thresh = cv2.adaptiveThreshold(img0, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
text_adth = pytesseract.image_to_string(adap_thresh, config='--psm 7')
After adaptive thresholding, the produced image is like this :
Pytesseract gives output as :
171 mi.
Now, if you know, in advance, the number of characters present, you can slice the string read by pytesseract and get the desired output as '171m'.
I thought your image was not sharp enough, hence I applied the process described at How do I increase the contrast of an image in Python OpenCV to first sharpen your image and then proceed by extracting the blue layer and running the tesseract.
I hope this helps.
import cv2
import pytesseract
img = cv2.imread('test.png') #test.png is your original image
s = 128
img = cv2.resize(img, (s,int(s/2)), 0, 0, cv2.INTER_AREA)
def apply_brightness_contrast(input_img, brightness = 0, contrast = 0):
if brightness != 0:
if brightness > 0:
shadow = brightness
highlight = 255
else:
shadow = 0
highlight = 255 + brightness
alpha_b = (highlight - shadow)/255
gamma_b = shadow
buf = cv2.addWeighted(input_img, alpha_b, input_img, 0, gamma_b)
else:
buf = input_img.copy()
if contrast != 0:
f = 131*(contrast + 127)/(127*(131-contrast))
alpha_c = f
gamma_c = 127*(1-f)
buf = cv2.addWeighted(buf, alpha_c, buf, 0, gamma_c)
return buf
out = apply_brightness_contrast(img,0,64)
b, g, r = cv2.split(out) #spliting and using just the blue
pytesseract.image_to_string(255-b, config='--psm 7 -c tessedit_char_whitelist=1234567890m') # the 255-b here because the image has black backgorund and white numbers, 255-b switches the colors

Incorrect thresholding before string recognition

I'm trying to recognize some text with pytesseract, but before that I have to turn the picture I have into a binary one.
Note that I first resize the picture to make it easier to read for pytesseract.
See below the original picture, the resized one, my code and the result I get, so you can understand my issue..
Original picture
image = cv2.imread('original.png',0)
image = cv2.resize(image,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
cv2.imwrite("resized.png", image)
thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
result = 255 - thresh
cv2.imwrite("after_threshold.png", result)
Resized picture
Picture after threshold
Thank you for your help :)
If you remove the resize, it seems to work
Output from Pytesseract
32 Force
120 Initiative
Prospection
25 agilité
53 Vitalité
5 Dommages
1 Résistance Neutre
1 Portée
7% Résistance Feu
import cv2
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
image = cv2.imread('1.png', 0)
thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
result = 255 - thresh
data = pytesseract.image_to_string(result, lang='eng',config='--psm 6')
print(data)
cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey()

Categories