My Opencv/Pytesseract script can't detect characters - python

I have this code:
img = cv2.imread("image.jpg", cv2.IMREAD_UNCHANGED)
img = imutils.resize(img, width=500)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("output/grayscale conversion.jpg", gray)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
cv2.imwrite("output/bilateralfilter.jpg", gray)
edged = cv2.Canny(gray, 170, 200)
cv2.imwrite("output/cannyedges.jpg", edged)
cnts= cv2.findContours(edged.copy(), cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts=sorted(cnts, key = cv2.contourArea, reverse = True)[:30]
NumberPlateCnt = None
count = 0
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
NumberPlateCnt = approx
break
# Masking the part other than the number plate
mask = np.zeros(gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[NumberPlateCnt],0,255,-1)
new_image = cv2.bitwise_and(img,img,mask=mask)
cv2.imwrite("output/masked.jpg", new_image)
# Configuration for tesseract
config = ('-l eng --oem 1 --psm 3')
# Run tesseract OCR on image
text = pytesseract.image_to_string(new_image, config=config)
print(text)
cv2.waitKey(0)
return text
when i pass this image as image.jpg it returns the numbers in the plate
But, passing an image like this doesn't
In this case the isolation of the plate doesn't work, it masks almost everything, while
using other images the plate gets isolated but pytesseract still can't convert them to text(see last image)
what am i doing wrong?

Related

Selecting contours inside a contour (OpenCV, Python)

I am trying to select circles inside a square from a photo. I managed to select the square but I am having troubles with selecting the circles. I think the main problem is my threshold but I don't know how to configure it correctly.
[my image]
(https://i.stack.imgur.com/zwVFQ.jpg)
There is my code:
import cv2
import numpy as np
image = cv2.imread('photo/5.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, kernel, iterations=2)
height= image.shape[0]
width = image.shape[1]
size = height*width
cnts, hierarchy = cv2.findContours(opening, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
trees = 0
trees_area= 0
hierarchy = hierarchy[0]
for component in zip(cnts, hierarchy):
currentContour = component[0]
currentHierarchy = component[1]
x,y,w,h = cv2.boundingRect(currentContour)
if currentHierarchy[1] < 0:
cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),3)
elif currentHierarchy[2] < 0:
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),3)
print('Trees:', trees)
print('Area:', trees_area)
print('Size:', size)
print('Fibre_area', "{:.2f}".format((trees_area/size)*100))
cv2.imshow('image', image)
cv2.waitKey()

How do I not get blobs of a certain size displayed? (OpenCV, Python)

I am in need of a function in OpenCV that allows me to not show blobs of a certain size, like in the picture where blobs are marked with a red circle, I would like for them simply not to be shown in an image.
This is the code I used:
img = cv.imread('Fotos/1.jpg')
params = cv.SimpleBlobDetector_Params()
params.filterByArea = True
params.minArea = 8200
params.maxArea = 15500
detector = cv.SimpleBlobDetector_create(params)
keypoints = detector.detect(img)
#draw blobs
img_with_blobs = cv.drawKeypoints(img, keypoints, np.array([]), (0, 0, 255), cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.imshow(img_with_blobs)
cv.imshow("Keypoints", img_with_blobs)
Blobs detected
import cv2
img = cv2.imread('input/1.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 51, 9)
cnts = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
if 8200 < cv2.contourArea(c) < 12500:
cv2.drawContours(img, [c], -1, (255, 255, 255), -1)
cv2.imshow("1", img)
erased result

pytesseract not recognising image

I am building a image de-shredding program, and despite my prepossessing attempts I am still not getting any text output. The images I am putting into it seem as simple as possible. They are binarized and have little to no skew. What am I doing wrong? is there a special neural network library that I am not importing?Image
here is my code
import cv2
import numpy as np
import os
import imutils
from pytesseract import Output
import pytesseract
a1 = 0
a2 = 1
diflist = []
areas = []
images = []
rotated_shreds = []
cropped_shreds = []
idx = 0
scan = cv2.imread('test3.jpeg')
height = scan.shape[0]
width = scan.shape[1]
DrawnContours = np.zeros(shape=[height, width, 3], dtype=np.uint8)
blank_image2 = np.zeros(shape=[height, width, 3], dtype=np.uint8)
#grayscales the image
gray = cv2.cvtColor(scan, cv2.COLOR_BGR2GRAY)
gaus = cv2.GaussianBlur(gray, (3,3),0)
canny_output = cv2.Canny(gaus,50,50)
StripConts, hierarchy= cv2.findContours(canny_output, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(DrawnContours, StripConts, -1, (255,255,255),12)
DrawnContoursgray = cv2.cvtColor(DrawnContours, cv2.COLOR_BGR2GRAY)
DrawConts, hierarchy= cv2.findContours(DrawnContoursgray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
sorted_contours= sorted(DrawConts, key=cv2.contourArea, reverse= True)
for contour in sorted_contours:
measure = cv2.contourArea(contour)
areas.append(measure)
print(measure)
for area in areas:
try:
dif = areas[a1]-areas[a2]
diflist.append(dif)
a1 += 1
a2 += 1
except:
break
maximum = max(diflist)
del diflist[0]
number = (diflist.index(maximum)+2)
print(number)
for c in sorted_contours:
if idx >= number:
break
else:
x,y,w,h = cv2.boundingRect(c)
new_img=scan[y:y+h,x:x+w]
images.append(new_img)
idx+=1
for image in images:
try:
shred_gaus = cv2.GaussianBlur(image, (3,3),0)
shred_canny_output = cv2.Canny(shred_gaus, 130, 130)
ShredCont, hierarchy = cv2.findContours(shred_canny_output, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
sorted_contours= sorted(ShredCont, key=cv2.contourArea, reverse= True)
cnt = sorted_contours[1]
rect = cv2.minAreaRect(cnt)
angle = rect[2]
if angle < 0:
rotguide = -90 +abs(angle)
print(rotguide)
else:
rotguide = 90 - angle
print(rotguide)
rotated_shred = imutils.rotate_bound(image, rotguide)
rotated_shreds.append(rotated_shred)
except:
counter = 100
for rotated_shred in rotated_shreds:
print("r")
ret, thresh2 = cv2.threshold(rotated_shred, 120, 255, cv2.THRESH_BINARY)
grayfinal = cv2.cvtColor(thresh2, cv2.COLOR_BGR2GRAY)
strait_shred, hierarchy= cv2.findContours(grayfinal, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
sorted_contours= sorted(strait_shred, key=cv2.contourArea, reverse= True)
x,y,w,h = cv2.boundingRect(sorted_contours[0])
new_img=thresh2[y:y+h,x:x+w]
gaus_img = cv2.GaussianBlur(new_img, (3,3),0)
cropped_shreds.append(gaus_img)
cv2.imwrite('rotate.jpeg',cropped_shreds[0])
print(pytesseract.image_to_string(cropped_shreds[1]))
I tried playing with the binarisation values, by blurring it and then binarizing it with a low threshold I fixed it.

Achieving more accurate image warping

could you help me with better paper warping? Right now it looks like this and as you can see it's really bad as many cells are 50% black 50% white. Here's my code if it helps:
image = cv2.imread("image2.jpg")
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ret,warped = cv2.threshold(warped,160,255,cv2.THRESH_BINARY)
Below is the code adding the skew detection part to your code:
import numpy as np
import cv2
from imutils.perspective import four_point_transform
import imutils
image = cv2.imread("image2.jpg")
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
coords = np.column_stack(np.where(warped > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
print(angle)
(h, w) = warped.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(warped, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
cv2.imshow('Corrected', imutils.resize(rotated, height = 650))
cv2.waitKey(0)
It didn't identify any skew in the warped image. But sometimes it happens that after warping you need to check if there is any skew resulting from not so accurate warping.

Tesseract not detecting any text on RGB images on Python

Hey I started working with Tesseract OCR but I'm having problems getting the text from really simple RGB images.
It works just fine with text2image images.
Here is my code:
from PIL import Image
import pytesseract
import argparse
import cv2
import os
import sys
class wordExtractor():
def __init__(self, image_path):
self.image_path = image_path
pytesseract.pytesseract.tesseract_cmd = r'/home/yarin/tesseract/bin/debug/tesseract'
#self.resize_image()
def resize_image(self):
basewidth = 800
img = Image.open(self.image_path)
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
os.remove(self.image_path)
img.save(self.image_path[:-4] + '.png')
self.image_path = self.image_path[:-4] + '.png'
def get_text(self, lang):
# load the example image and convert it to grayscale
image = cv2.imread(self.image_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# check to see if we should apply thresholding to preprocess the
# image
#if args["preprocess"] == "thresh":
gray = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# make a check to see if median blurring should be done to remove
# noise
#elif args["preprocess"] == "blur":
# gray = cv2.medianBlur(gray, 3)
# write the grayscale image to disk as a temporary file so we can
# apply OCR to it
filename = "{}.png".format(os.getpid())
cv2.imwrite(filename, gray)
#load the image as a PIL/Pillow image, apply OCR, and then delete
# the temporary file
text = pytesseract.image_to_string(Image.open(filename), lang='eng')
os.remove(filename)
return text
# show the output images
#cv2.imshow("Image", image)
#cv2.imshow("Output", gray)
#cv2.waitKey(0)
w = wordExtractor('6.png')
print(w.get_text('eng'))
Tesseract returns empty string for the following images:
Please show me how can I solve this Thanks in advance!
After thresholding, you can use findContours to find contour for each shape. Then you can filter the contours and put every contour you are interested in into a blank white image. By then, you will get the letters and ready to process using tesseract. You can see the detail in the code below.
import cv2
import numpy as np
import pytesseract
# img = cv2.imread("dwLFQ.png", cv2.IMREAD_COLOR)
img = cv2.imread("NfwY4.png", cv2.IMREAD_COLOR)
# img = cv2.imread("xTH6s.png", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
items = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = items[0] if len(items) == 2 else items[1]
base = np.zeros(thresh.shape, dtype=np.uint8)
base = cv2.bitwise_not(base)
max_area = 0
for i in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[i])
ratio = h / w
area = cv2.contourArea(contours[i])
cv2.drawContours(img, [contours[i]], 0, (255, 0, 0), 2)
if 1 < ratio < 3:
max_area = max(area, max_area)
print("area: " + str(area) + ", max area: " + str(max_area) + ", ratio: " + str(ratio))
# if 1000 < area < max_area / 2:
if 1000 < area < 40000:
mask = np.zeros(thresh.shape, dtype=np.uint8)
cv2.drawContours(mask, [contours[i]], -1, color=255, thickness=-1)
mean = cv2.mean(thresh, mask=mask)
segment = np.zeros((h, w), dtype=np.uint8)
segment[:h, :w] = thresh[y:y + h, x:x + w]
if mean[0] > 150:
# white, invert
segment = cv2.bitwise_not(segment)
base[y:y + h, x:x + w] = segment[:h, :w]
cv2.imshow("base", base)
cv2.drawContours(img, [contours[i]], 0, (255, 0, 0), 2)
cv2.waitKey(0)
custom_config = r'-l eng --oem 3 --psm 6 -c tessedit_char_whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZ " '
text = pytesseract.image_to_string(base, config=custom_config)
print("detected: " + text)
cv2.imshow("img", img)
cv2.imshow("base", base)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result
detected: NO
ENTRY

Categories

Resources