Recognize numbers from an image python - python

I am trying to extract numbers from in game screenshots.
I'm trying to extract:
98
3430
5/10
from PIL import Image
import pytesseract
image="D:/img/New folder (2)/1.png"
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract.exe'
text = pytesseract.image_to_string(Image.open(image),lang='eng',config='--psm 5')
print(text)
output is gibberish
‘t hl) keteeeees
ek pSlaerenen
JU) pgrenmnreserenny
Rates B
d dali eas. 5
cle aM (Sores
|, S| pgranmrerererecons
a cee 3
pea 3
oS :
(geo eenee
ey
=
es A

okay, so I tried changing it into grayscale, reverse contrast or use different treshold, but it all seems to be fairly inaccurate.
The issue seems to be the tilted and smaller numbers. You do not happen to have any hiher res image?
Most accurate I could get was the following code.
import cv2
import pytesseract
import imutils
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
img = cv2.imread('D:/img/New folder (2)/1.png') #test.png is your original image
img = imutils.resize(img, width=1400)
crop = img[340:530, 100:400]
data = pytesseract.image_to_string(crop,config=' --psm 1 --oem 3 -c tessedit_char_whitelist=0123456789/')
print(data)
cv2.imshow('crop', crop)
cv2.waitKey()
Otherwise I recommend one of these methods as described in the similar question
or in this one.

if the text is surrounded with the designs, tesseract suffers a lot
insted of tesseract try using findcontours in opencv (after little blurring, dilating)
you will get bounding boxes, then it might cover that text also

Related

How can I crop an image by a filter?

I want to crop a gray image by a mask. The gray image contains a digit that I want to process further for OCR.
The gray image in the following code snippet is only an excerpt of a bigger image but I took only the relevant part out of it (both for the image and the mask).
I thought that the cv2 function bitwise_and() should do the job, but I am apparently wrong (at least in the way I am doing it).
How can I achieve that my result contains these parts of the gray image that represent the digit 5 and all other parts of it are set to 0? Is this really something that cv2 should do, or is it better to use numpy for that? I have to keep the shades of gray as binarizing it would lead to errors in a further tesseract step.
So effectively it seems that everything equal/below the threshold 133 has to be set to 0.
The result:
The code:
import pandas as pd
import io
import cv2
maskString = \
"""
0,0,0,0,0,0,0,0,0,0
0,0,2,2,2,2,2,2,0,0
0,0,2,2,2,2,2,2,0,0
0,0,2,2,0,0,0,0,0,0
0,0,2,2,0,0,0,0,0,0
0,2,2,2,2,2,0,0,0,0
0,2,2,2,2,2,2,2,0,0
0,2,2,0,0,0,2,2,0,0
0,0,0,0,0,0,2,2,2,0
0,2,2,0,0,0,2,2,0,0
0,2,2,0,0,0,2,2,0,0
0,0,2,2,2,2,2,2,0,0
0,0,0,2,2,2,0,0,0,0
0,0,0,0,0,0,0,0,0,0
"""
grayedString = \
"""
133,133,133,133,133,133,133,133,133,133
133,132,168,201,201,201,201,185,132,133
133,132,225,232,201,201,201,185,132,133
133,132,247,185,132,132,132,132,132,133
133,142,255,168,132,132,132,132,132,133
133,168,255,159,201,193,151,132,132,133
133,193,255,232,201,217,255,177,132,133
133,168,193,132,132,132,201,255,132,133
133,132,132,132,132,132,168,255,168,133
133,185,168,132,132,132,168,255,151,133
133,217,247,132,132,132,210,247,132,133
133,142,240,232,201,232,255,159,132,133
133,132,142,185,201,185,142,132,132,133
133,133,133,133,133,133,133,133,133,133"""
grayed = pd.read_csv(io.StringIO(grayedString), sep=',', header=None).values.astype('uint8')
mask = pd.read_csv(io.StringIO(maskString), sep=',', header=None).values.astype('uint8')
result = cv2.bitwise_and(grayed,mask)

Why will tesseract not detect this letter?

I am trying to detect this letter but it doesn't seem to recognize it.
import cv2
import pytesseract as tess
img = cv2.imread("letter.jpg")
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(tess.image_to_string(imggray))
this is the image in question:
Preprocessing of the image (e.g. inverting it) should help, and also you could take advantage of pytesseract image_to_string config options.
For instance, something along these lines:
import pytesseract
import cv2 as cv
import requests
import numpy as np
import io
# I read this directly from imgur
response = requests.get('https://i.stack.imgur.com/LGFAu.jpg')
nparr = np.frombuffer(response.content, np.uint8)
img = cv.imdecode(nparr, cv.IMREAD_GRAYSCALE)
# simple inversion as preprocessing
neg_img = cv.bitwise_not(img)
# invoke tesseract with options
text = pytesseract.image_to_string(neg_img, config='--psm 7')
print(text)
should parse the letter correctly.
Have a look at related questions for some additional info about preprocessing and tesseract options:
Why does pytesseract fail to recognise digits from image with darker background?
Why does pytesseract fail to recognize digits in this simple image?
Why does tesseract fail to read text off this simple image?
#Davide Fiocco 's answer is definitely correct.
I just want to show another way of doing it with adaptive-thresholding
When you apply adaptive-thesholding result will be:
Now when you read it:
txt = pytesseract.image_to_string(thr, config="--psm 7")
print(txt)
Result:
B
Code:
import cv2
import pytesseract
img = cv2.imread("LGFAu.jpg")
gry = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.adaptiveThreshold(gry, 252, cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY_INV, 11, 2)
txt = pytesseract.image_to_string(thr, config="--psm 7")
print(txt)

Python cannot read text from an image [Python OCR with Tesseract]

I have this issue with reading exactly two lines of numbers (each line contains max of 3 digits) from an image.
My Python code has a big problem with reading a data from images like the ones below:
Most of the times it is just printing random numbers.
What should I do to make this work?
This is my Python code:
from PIL import ImageGrab, Image
from datetime import datetime
from pytesseract import pytesseract
import numpy as nm
pytesseract.tesseract_cmd = 'F:\\Tesseract\\tesseract'
while True:
screenshot = ImageGrab.grab(bbox=(515, 940, 560, 990))
datetime = datetime.now()
filename = 'pic_{}.{}.png'.format(datetime.strftime('%H%M_%S'), datetime.microsecond / 500000)
gray = screenshot.convert('L')
bw = nm.asarray(gray).copy()
bw[bw < 160] = 0
bw[bw >= 160] = 255
convertedScreenshot = Image.fromarray(bw)
tesseract = pytesseract.image_to_string(convertedScreenshot, config='digits --psm 6')
convertedScreenshot.save(filename)
print(tesseract)
The image has to have white text on the black background or the black text on the white background.
It is also important to save the image afterwards.
Tesseract works best on images having black text on white Background. Invert the image before using tesseract by adding the below line :
convertedScreenshot = 255 - convertedScreenshot
Hey I was facing similar problem, I still am but using a few arguments in 'image_to_string' function helped.
I was using it for a single digit detection
d = pytesseract.image_to_string(thr, lang='eng',config='--psm 10 --oem
3 -c tessedit_char_whitelist=0123456789')
This helped me detect the single digits

How can I get text from this image with Tesseract?

Currently I'm using the code below to get text from image and it works fine, but it doesn't work well with these two images, it seems like tesseract cannot scan these types of image. Please show me how to fix it
https://i.ibb.co/zNkbhKG/Untitled1.jpg
https://i.ibb.co/XVbjc3s/Untitled3.jpg
def read_screen():
spinner = Halo(text='Reading screen', spinner='bouncingBar')
spinner.start()
screenshot_file="Screens/to_ocr.png"
screen_grab(screenshot_file)
#prepare argparse
ap = argparse.ArgumentParser(description='HQ_Bot')
ap.add_argument("-i", "--image", required=False,default=screenshot_file,help="path to input image to be OCR'd")
ap.add_argument("-p", "--preprocess", type=str, default="thresh", help="type of preprocessing to be done")
args = vars(ap.parse_args())
# load the image
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
if args["preprocess"] == "thresh":
gray = cv2.threshold(gray, 177, 177,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
elif args["preprocess"] == "blur":
gray = cv2.medianBlur(gray, 3)
# store grayscale image as a temp file to apply OCR
filename = "Screens/{}.png".format(os.getpid())
cv2.imwrite(filename, gray)
# load the image as a PIL/Pillow image, apply OCR, and then delete the temporary file
pytesseract.pytesseract.tesseract_cmd = 'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'
#ENG
#text = pytesseract.image_to_string(Image.open(filename))
#VIET
text = pytesseract.image_to_string(Image.open(filename), lang='vie')
os.remove(filename)
os.remove(screenshot_file)
# show the output images
'''cv2.imshow("Image", image)
cv2.imshow("Output", gray)
os.remove(screenshot_file)
if cv2.waitKey(0):
cv2.destroyAllWindows()
print(text)
'''
spinner.succeed()
spinner.stop()
return text
You should try different psm modes instead of default like so:
target = pytesseract.image_to_string(im,config='--psm 4',lang='vie')
Exert from docs:
Page segmentation modes:
0 Orientation and script detection (OSD) only.
1 Automatic page segmentation with OSD.
2 Automatic page segmentation, but no OSD, or OCR.
3 Fully automatic page segmentation, but no OSD. (Default)
4 Assume a single column of text of variable sizes.
5 Assume a single uniform block of vertically aligned text.
6 Assume a single uniform block of text.
7 Treat the image as a single text line.
8 Treat the image as a single word.
9 Treat the image as a single word in a circle.
10 Treat the image as a single character.
11 Sparse text. Find as much text as possible in no particular order.
12 Sparse text with OSD.
13 Raw line. Treat the image as a single text line,
bypassing hacks that are Tesseract-specific.
So for example for /Untitled3.jpg you could try --psm 4 and failing that you could try --psm 11 for both.
Depending on your version of tesseract you could also try different oem modes:
Use --oem 1 for LSTM, --oem 0 for Legacy Tesseract. Please note that Legacy Tesseract models are only included in traineddata files from tessdata repo.
EDIT
Also as seen in your images there are two languages so if you wish to use lang parameter you need to manually separate image into two to not to confuse tesseract engine and use different lang values for them.
EDIT 2
Below a full working example with Unitiled3. What I noticed was your improper use of thresholding. You should set maxval to something bigger than the value you are thresholding at. Like in my example I set thresh 177 but maxval to 255 so everything above 177 will be black. I didn't even had to do any binarization.
import cv2
import pytesseract
from cv2.cv2 import imread, cvtColor, COLOR_BGR2GRAY, threshold, THRESH_BINARY
image = imread("./Untitled3.jpg")
image = cvtColor(image,COLOR_BGR2GRAY)
_,image = threshold(image,177,255,THRESH_BINARY)
cv2.namedWindow("TEST")
cv2.imshow("TEST",image)
cv2.waitKey()
text = pytesseract.image_to_string(image, lang='eng')
print(text)
Output:
New York, New York
Salzburg, Austria
Hollywood, California

extracting text information from a national id

I'm trying to do OCR arabic on the following ID but I get a very noisy picture, and can't extract information from it.
Here is my attempt
import tesserocr
from PIL import Image
import pytesseract
import matplotlib as plt
import cv2
import imutils
import numpy as np
image = cv2.imread(r'c:\ahmed\ahmed.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray,11,18,18)
gray = cv2.GaussianBlur(gray,(5,5), 0)
kernel = np.ones((2,2), np.uint8)
gray = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,11,2)
#img_dilation = cv2.erode(gray, kernel, iterations=1)
#cv2.imshow("dilation", img_dilation)
cv2.imshow("gray", gray)
text = pytesseract.image_to_string(gray, lang='ara')
print(text)
with open(r"c:\ahmed\file.txt", "w", encoding="utf-8") as myfile:
myfile.write(text)
cv2.waitKey(0)
result
sample
The text for your id is in black color which makes the extraction process easy. All you need to do is threshold the dark pixels and you should be able to get the text out.
Here is a snip of the code
import cv2
import numpy as np
# load image in grayscale
image = cv2.imread('AVXjv.jpg',0)
# remove noise
dst = cv2.blur(image,(3,3))
# extract dark regions which corresponds to text
val, dst = cv2.threshold(dst,80,255,cv2.THRESH_BINARY_INV)
# morphological close to connect seperated blobs
dst = cv2.dilate(dst,None)
dst = cv2.erode(dst,None)
cv2.imshow("dst",dst)
cv2.waitKey(0)
And here is the result:
This is my output using ImageMagick TextCleaner script:
Script: textcleaner -g -e stretch -f 50 -o 30 -s 1 C:/Users/PC/Desktop/id.jpg C:/Users/PC/Desktop/out.png
Take a look here if you want to install and use TextCleaner script on Windows... It's a tutorial I made as simple as possible after few researches I made when I was in your same situation.
Now it should be very easy to detect the text and (not sure how simple) recognize it.

Categories

Resources