EasyOCR - Batch processing images with Python - python

I am attempting to write a bit of python that uses EasyOCR to write the numbers it sees in the images into a text file. My goal is to batch process all images in a directory, rather than a single images at a time, as I have several thousand images to process.
The python code:
import cv2
import os
import io
reader = easyocr.Reader(['en'])
for image_name in os.listdir("ocr-source"):
image = cv2.imread(f'ocr-source/{image_name}')
result = reader.readtext(image, allowlist='0123456789', detail=0)
print(image_name, " ", result, file=open('output.txt', 'w'))
My test ocr-source directory contains about 10 images.
The resulting output.txt file only contains the results from a single image.
How to I get it to properly iterate through the entire directory?

Simple fix: Instead of writing over the file each loop, I needed to append.
import cv2
import os
import io
reader = easyocr.Reader(['en'])
for image_name in os.listdir("ocr-source"):
image = cv2.imread(f'ocr-source/{image_name}')
result = reader.readtext(image, allowlist='0123456789', detail=0)
print(image_name, " ", result, file=open('output.txt', 'a'))
Note the 'a' in the print call

Related

How to load images from memory to numpy using file system

I want to store my image directory in memory, then load the images into a numpy array.
The normative way to load images that are not in memory is as follows:
import PIL.Image
import numpy as np
image = PIL.Image.open("./image_dir/my_image_1.jpg")
image = np.array(image)
However, I am not sure how to do this when the images are in memory. So far, I have been able to setup the following starter code:
import fs
import fs.memoryfs
import fs.osfs
image_dir = "./image_dir"
mem_fs = fs.memoryfs.MemoryFS()
drv_fs = fs.osfs.OSFS(image_path)
fs.copy.copy_fs(drv_fs, mem_fs)
print(mem_fs.listdir('.'))
Returns:
['my_image_1.jpg', 'my_image_2.jpg']
How do I load images that are in memory into numpy?
I am also open to alternatives to the fs package.
As per the documentation, Pillow's Image.open accepts a file object instead of a file name, so as long as your in-memory file package provides Python file objects (which it most likely does), you can just use them. If it doesn't, you could even just wrap them in a class that provides the required methods. Assuming you are using PyFilesystem, according to its documentation you should be fine.
So, you want something like:
import numpy as np
import PIL.Image
import fs.memoryfs
import fs.osfs
import fs.copy
mem_fs = fs.memoryfs.MemoryFS()
drv_fs = fs.osfs.OSFS("./image_dir")
fs.copy.copy_file(drv_fs, './my_image_1.jpg', mem_fs, 'test.jpg')
with mem_fs.openbin('test.jpg') as f:
image = PIL.Image.open(f)
image = np.array(image)
(note I just used copy_file because I tested with a single file, you can use copy_fs if you need to copy the entire tree - it's the same principle)

How to automate the filename process when downloading an image with python3?

I'm not a coder at all I'm just learning bits and bobs so I can get some faces for my art project. I want to download 100 faces from the thispersondoesnotexist website and I have so far gotten this far with my code.
import urllib.request
urllib.request.urlretrieve("http://www.thispersondoesnotexist.com", "image.jpg")
The code downloads the face and saves it as "image.jpg" but when I run it again it overwrites the image I just saved. How can I find out how to write code that will randomly generate a filename? I'm using the PyCharm IDE.
To generate random file names you can include this piece of code.
This code will generate a random string of length 6 and uses it as the filename everytime you run the program.
import random
import string
import urllib.request
filename = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 6)) + '.jpg'
urllib.request.urlretrieve("http://www.thispersondoesnotexist.com", filename)
A nice way can be generating timestamp and use it to name a file:
import urllib.request
import datetime
def generate_timestamp():
return str(datetime.datetime.now()).replace('-', '_').replace(':', '_').replace(' ', '__')
urllib.request.urlretrieve("http://www.thispersondoesnotexist.com", "image_" + generate_timestamp() + ".jpg")
This will serve dual purposes:
Naming a file uniquely.
Getting idea when it has finished downloading.

Cannot save multiple files with PIL save method

I have modified a vk4 converter to allow for the conversion of several .vk4 files into .jpg image files. When ran, IDLE does not give me an error, but it only manages to convert one file before ending the process. I believe the issue is that image.save() only seems to affect a single file and I have been unsuccessful in looping that command to extend to all other files in the directory.
Code:
import numpy as np
from PIL import Image
import vk4extract
import os
os.chdir(r'path\to\directory')
root = ('.\\')
vkimages = os.listdir(root)
for img in vkimages:
if (img.endswith('.vk4')):
with open(img, 'rb') as in_file:
offsets = vk4extract.extract_offsets(in_file)
rgb_dict = vk4extract.extract_color_data(offsets, 'peak', in_file)
rgb_data = rgb_dict['data']
height = rgb_dict['height']
width = rgb_dict['width']
rgb_matrix = np.reshape(rgb_data, (height, width, 3))
image = Image.fromarray(rgb_matrix, 'RGB')
image.save('sample.jpeg', 'JPEG')
How do I prevent the converted files from being overwritten while using the PIL module?
Thank you.
It is saving every file, but since you are always providing the same name to each file (image.save('sample.jpeg', 'JPEG')), only the last one will be saved and all the other ones will be overwritten. You need to specify different names to every file. There are several ways of doing it. One is adding the index when looping using enumerate():
for i, img in enumerate(vkimages):
and then using the i on the name of the file when saving:
image.save(f'sample_{i}.jpeg', 'JPEG')
Another way is to use the original filename and replace the extension. From your code, it looks like the files are .vk4 files. So another possibility is to save with the same name but replacing .vk4 to .jpeg:
image.save(img.replace('.vk4', '.jpeg'), 'JPEG')

CV2 Returning NoneType for Image?

I am currently trying to compute the arrays of different images. I have the code below which uses cv2 to read and then hog.compute to calculate it. However the issue that I am getting is that I am getting a NoneType being outputted. I know that the absolute file path which is why I used os.path.abspath(file). However, I know that the file is being read as I have printed the file name and it is the file that is in the directory?
The files are located within a folder called image_dataset and this has 3 subfolders called bikes, cars and people. I'm pretty sure the first file is being read as well but have no clue why I am getting a NoneType returned when I try hog.compute(im)? Any clue as to why?
import os
import numpy as np
import cv2
import glob
import pandas as pd
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
def obtain_dataset(folder_name):
# assuming 128x128 size images and HoGDescriptor length of 34020
hog_feature_len=34020
hog = cv2.HOGDescriptor()
image_dict = {'bikes':1, 'cars':2, 'people':3}
y = []
X = []
#code for obtaining hog feature for one image file name
for subdir, dirs, files in os.walk(folder_name):
for file in files:
if file.lower().endswith(('.png')):
location = (os.path.abspath(file))
im = cv2.imread(location)
h = hog.compute(im)
# use this to read all images in the three directories and obtain the set of features X and train labels Y
# you can assume there are three different classes in the image dataset
return (X,y)
train_folder_name='image_dataset'
(X_train, Y_train) = obtain_dataset(train_folder_name)
In your case, as you have a subdirectory, the os.path.abspath() method does not return the complete path of the file. Instead, use os.path.join() to join the file names with the path of the directory of the files:
location = os.path.join(subdir, file)

Can't read second barcode in the same image file using pyzbar

I'm coding in Python 2.7 and I need to implement a process where I will read a PDF then obtain the image of the first page of the document, then from that image that contains two barcodes obtain the values of both. As of now these are the two functions I've been working on so far (I need to do a lot of polishing before I move this to an environment):
Python process to obtain the image from the PDF from a Tutorial:
from wand.image import Image as wi
pdf = wi(filename="test.pdf", resolution=300)
pdfImageTest = pdf.convert("png")
i=1
for img in pdfImage.sequence:
page = wi
(image = img)
page.save(filename="test"+str(i)+".png")
i+=1
Python process to read the barcodes from an image:
from pyzbar.pyzbar import decode
from PIL import Image
import cv2
import numpy
decodedObjects = decode(Image.open('test2.png'))
obj = decodedObjects
print(obj)
decodedObjects = decode(cv2.imread('test2.png'))
print(obj)
According to the documentation for decode function in pyzbar, the function will scan all the barcodes contained in the image but as of now for both cases I've used, I'm only obtaining the first barcode in the image. Is there a way to force the function to keep scanning the image or pointing it into a specific location of the image after finishing the process for the first image?
You should use obj.data and iterate over all objects.
Here's an example:
from pyzbar.pyzbar import decode
from PIL import Image
import cv2
import numpy
decodedObjects = decode(Image.open('test2.png'))
obj = decodedObjects
for bar in obj:
print(bar.data)
By the way, the print statement is replaced with print() function in Python 3. So if you strictly want to use Python 2.7, you should use e.g. print bar.data.

Categories

Resources