expected string or Unicode object, Photo found in django - python

here i want to read the image from db and apply some operations on my image like noise remove .... and finally i will appy pytesseract to get the text
def GetData(request):
img = Photo.objects.get(id=1)
#wrapper = FileWrapper(open(img.file))
# Read image with opencv
img = cv2.imread(img)
# Apply dilation and erosion to remove some noise
kernel = np.ones((1, 1), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
b,g,r = cv2.split(img)
# get b,g,r
rgb_img = cv2.merge([r,g,b])
# switch it to rgb
# Denoising
dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)
img = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
# Apply threshold to get image with only black and white
img = cv2.adaptiveThreshold(img, 127, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11,2)
new_image = cv2.blur(img, (1, 1))

The error comes from cv2.imread(img) because imread take a string or unicode parameter with the URI of the image, but you are using a Django model class which is quite different.
Assuming that your Photo class model has an ImageField field named image you could fix your issue changing
img = cv2.imread(img)
to something like
img = cv2.imread(img.image.url)

Related

Extracting text from image - OCR

I'm using cv2 and pytesseract library to extract text from image. Here is the image (image3_3.png) and the python code:
def threshold_image(img_src):
"""Grayscale image and apply Otsu's threshold"""
# Grayscale
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
# Binarisation and Otsu's threshold
img_thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
return img_thresh
img = np.array(Image.open('image3_3.png'))
# Apply dilation and erosion to remove some noise
kernel = np.ones((1, 1), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
# normalise the image
norm_img = np.zeros((img.shape[0], img.shape[1]))
img = cv2.normalize(img, norm_img, 0, 255, cv2.NORM_MINMAX)
# Apply blur to smooth out the edges
img = cv2.GaussianBlur(img, (5, 5), 0)
string_ocr = pytesseract.image_to_string(threshold_image(img), lang = 'eng', config = '--psm 6')
print(string_ocr)
Here is the result:
Image A3. This is image A3 with more texts.
ISAS Visual Analytics
INow everyone can easily discover and share powerful
Nsights that inspire action
Why am I not getting the same exact text? Any help highly appreciated.

how to extract numbers from captcha image in python?

I want to extract numbers from captcha image, so I tried this code from this answer this answer:
try:
from PIL import Image
except ImportError:
import Image
import pytesseract
import cv2
file = 'sample.jpg'
img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, None, fx=10, fy=10, interpolation=cv2.INTER_LINEAR)
img = cv2.medianBlur(img, 9)
th, img = cv2.threshold(img, 185, 255, cv2.THRESH_BINARY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4,8))
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite("sample2.jpg", img)
file = 'sample2.jpg'
text = pytesseract.image_to_string(file)
print(''.join(x for x in text if x.isdigit()))
and it worked fine for this image: outPut: 436359 But, when I tried it on this image: It gave me nothing, outPut: .
How can I modify my code to get the numbers as a string from the second image?
EDIT:
I tried Matt's answer and it worked just fine for the image above. but it doesn't recognise numbers like (8,1) in image A, and number (7) in image B
image A
image B
How to fix that?
Often, getting OCR just right on an image like this has to do with the order and parameters of the transformations. For example, in the following code snippet, I first convert to grayscale, then erode the pixels, then dilate, then erode again. I use threshold to convert to binary (just blacks and whites) and then dilate and erode one more time. This for me produces the correct value of 859917 and should be reproducible.
import cv2
import numpy as np
import pytesseract
file = 'sample2.jpg'
img = cv2.imread(file)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ekernel = np.ones((1,2),np.uint8)
eroded = cv2.erode(gray, ekernel, iterations = 1)
dkernel = np.ones((2,3),np.uint8)
dilated_once = cv2.dilate(eroded, dkernel, iterations = 1)
ekernel = np.ones((2,2),np.uint8)
dilated_twice = cv2.erode(dilated_once, ekernel, iterations = 1)
th, threshed = cv2.threshold(dilated_twice, 200, 255, cv2.THRESH_BINARY)
dkernel = np.ones((2,2),np.uint8)
threshed_dilated = cv2.dilate(threshed, dkernel, iterations = 1)
ekernel = np.ones((2,2),np.uint8)
threshed_eroded = cv2.erode(threshed_dilated, ekernel, iterations = 1)
text = pytesseract.image_to_string(threshed_eroded)
print(''.join(x for x in text if x.isdigit()))

Pytesseract - OCR on image with text in different colors

Pytesseract is unable to extract text when texts are present in different colors . I tried using opencv to invert the image but it doesn't work for dark text colors.
The image:
import cv2
import pytesseract
from PIL import Image
def text(image):
image = cv2.resize(image, (0, 0), fx=7, fy=7)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite("gray.png", gray)
blur = cv2.GaussianBlur(gray, (3, 3), 0)
cv2.imwrite("gray_blur.png", blur)
thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
cv2.imwrite("thresh.png", thresh)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
cv2.imwrite("opening.png", opening)
invert = 255 - opening
cv2.imwrite("invert.png", invert)
data = pytesseract.image_to_string(invert, lang="eng", config="--psm 7")
return data
Is there a way to extract both the texts from the given image: DEADLINE(red) and WHITE HOUSE(white)
You can use ImageOps to invert the image.And binaryzate the Image.
import pytesseract
from PIL import Image,ImageOps
import numpy as np
img = Image.open("OCR.png").convert("L")
img = ImageOps.invert(img)
# img.show()
threshold = 240
table = []
pixelArray = img.load()
for y in range(img.size[1]): # binaryzate it
List = []
for x in range(img.size[0]):
if pixelArray[x,y] < threshold:
List.append(0)
else:
List.append(255)
table.append(List)
img = Image.fromarray(np.array(table)) # load the image from array.
# img.show()
print(pytesseract.image_to_string(img))
The result:
The img in the end like this:

how to remove other noise from image using opencv

Here I am using below script to remove black spot near the image and remove line-through above number but it removes noise but not properly.
def get_string(img_path):
# Read image with opencv
img = cv2.imread(img_path)
# Convert to gray
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply dilation and erosion to remove some noise
kernel = np.ones((1, 1), np.uint8)
img = cv2.dilate(img, kernel, iterations=12)
img = cv2.erode(img, kernel, iterations=12)
# Write image after removed noise
cv2.imwrite(src_path + "removed_noise.png", img)
# Apply threshold to get image with only black and white
img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
# Write the image after apply opencv to do some ...
cv2.imwrite(src_path + "thres.png", img)
# Recognize text with tesseract for python
result = pytesseract.image_to_string(Image.open(src_path + "vertical_final.jpg"))
# Remove template file
#os.remove(temp)
return result
but it's not working properly.
Input image:
Output Image:-
I need someone to help me out from these problems it's highly appreciated.
Source Code:-
def get_string(img_path):
# Read image with opencv
img = cv2.imread(img_path)
# Convert to gray
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply dilation and erosion to remove some noise
kernel = np.ones((1,20), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
#img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((1, 1), np.uint8)
#img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite(src_path + "removed_noise.png", img)
img3 = cv2.subtract(cv2.imread(src_path + "removed_noise.png"),cv2.imread(src_path + "tax_amount.png"))
cv2.imwrite(src_path + "removed_noise_makes_00.png", img3)
lower_black = np.array([0,0,0], dtype = "uint16")
upper_black = np.array([70,70,70], dtype = "uint16")
black_mask = cv2.inRange(img3, lower_black, upper_black)
black_mask[np.where((black_mask == [0] ).all(axis = 1))] = [255]
opening = cv2.morphologyEx(black_mask, cv2.MORPH_CLOSE, kernel)
cv2.imwrite(src_path + "removed_noise_makes_00_1.png", opening)
# Recognize text with tesseract for python
result = pytesseract.image_to_string(Image.open(src_path + "removed_noise_makes_00_1.png"))
# Remove template file
#os.remove(temp)
return result
Where you do
kernel = np.ones((1, 1), np.uint8)
img = cv2.dilate(img, kernel, iterations=12)
You apply 12 times a dilation with a 1x1 structuring element (SE). Unless OpenCV does something special with such a SE, this code should not change your image at all.
You should create a larger SE:
kernel = np.ones((7, 7), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
This will first dilate and then erode the result. What this accomplishes is that small (thin) black regions disappear. These are the regions where the SE didn't fit. This is the same as
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
To remove the long line, you want to apply a closing with an elongated SE:
kernel = np.ones((1, 30), np.uint8)
line = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
This leaves only the horizontal line. The difference of img and line is the text without the line.
If you think of img as the sum of line and text, then img - line will be text. However, there is a small problem still: img has white background (255), and black foreground. So really, it is img = 255 - text - line, and the line image you found above is really 255 - line, because it also has white background. So directly taking the difference will not produce the desired effect.
The solution is to invert your images first:
img = 255 - img;
line = 255 - line;
text = img - line;

How to improve text extraction from an image?

I am using pytesseract to extract text from images. Before extracting text with pytesseract, I use Pillow and cv2 to reduce noise and enhance the image:
import numpy as np
import pytesseract
from PIL import Image, ImageFilter, ImageEnhance
import cv2
img = cv2.imread('ss.png')
img = cv2.resize(img, (0,0), fx=3, fy=3)
cv2.imwrite("new.png", img)
img1 = cv2.imread("new.png", 0)
#Apply dilation and erosion
kernel = np.ones((2, 2), np.uint8)
img1 = cv2.dilate(img1, kernel, iterations=1)
img1 = cv2.erode(img1, kernel, iterations=1)
img1 = cv2.adaptiveThreshold(img1,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,2)
cv2.imwrite("new1.png", img1)
img2 = Image.open("new1.png")
#Enhance the image
img2 = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
img2 = enhancer.enhance(2)
img2.save('new2.png')
result = pytesseract.image_to_string(Image.open("new2.png"))
print(result)
I mostly get good results, but when I use some low quality/resolution images, I do not get the expected output. Can I improve this in my code?
Example:
Input:
new1.png:
new2.png:
The string that I get from the console is play. What could I change in my algorithm, so that I get the whole string extracted?
Any help would be greatly appreciated.
This is a late answer, but I just came across this. we can use Pillow and cv2 to reduce noise and enhance the image before extracting text from images using pytesseract. I hope it would help someone in future.
#import required library
src_path = "C:/Users/chethan/Desktop/"
def get_string(img_path):
# Read image with opencv
img = cv2.imread(img_path)
# Convert to gray
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply dilation and erosion to remove some noise
kernel = np.ones((1, 1), np.uint8)
img = cv2.dilate(img, kernel, iterations=1)
img = cv2.erode(img, kernel, iterations=1)
# Write image after removed noise
cv2.imwrite(src_path + "removed_noise.png", img)
# Apply threshold to get image with only black and white
#img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
# Write the image after apply opencv to do some ...
cv2.imwrite(src_path + "thres.png", img)
# Recognize text with tesseract for python
result = pytesseract.image_to_string(Image.open(src_path + "thres.png"))
# Recognize text with tesseract for python
result = pytesseract.image_to_string(Image.open(img_path))
# Remove template file
# os.remove(temp)
return result
print(get_string(src_path + "dummy.png"))

Categories