Sitemap
Quantrium.ai

This is Quantrium’s official tech blog. A blog on how technology enables us to develop great software applications for our clients.

QUANTRIUM GUIDES

Improving PPOCR Recognition Time in Python

Utilizing multiprocessing and Colab GPU for PPOCR recognition

5 min readAug 29, 2022

--

Press enter or click to view image in full size

Introduction

Over the last few months, I have been writing some articles on Optical Character Recognition (OCR) using Python. But, one of the challenges faced even today with OCR in Python is the recognition time taken by some OCR models. We can find some of the OCR models (such as easyOCR, docTROCR, etc.) performing very fast when implemented with a Graphical Processing Unit (GPU).

If you had gone through my article on integrating multiple OCR models (which can be found here), you would have noticed recognition models such as PPOCR, pytesseract, etc., which perform recognition coordinate-wise. A major drawback with these recognition models is that, since they recognize the text coordinate-wise, their recognition time is much higher than recognition models like easyOCR, which takes the list of all coordinates and images at a time to perform recognition.

Also, if you try performing recognition using PPOCR using a Google Colab GPU directly, you may observe that the GPU is not consumed at all by the recognition model and a warning pops out in some time stating that the GPU is not consumed. Also, GPU availability in such platforms is very limited. However, there is a procedure to perform PPOCR recognition by consuming the Colab GPU, which I have explained in the upcoming sections. PPOCR documentation can be found here.

I have also explained how PPOCR recognition can be done using multiprocessing, which is a basic solution with which one can start and try improving the process even further.

We will test the recognition using all the methods with the following image (in fact, I used the same image in my docTROCR article. The article can be found in this link):-

Test image — PPOCR recognition

Implementing PPOCR recognition with ordinary CPU

For comparison purposes, we will first check and record the time taken by ordinary CPU for PPOCR recognition.

The following installations should be made:

!pip install "paddleocr>=2.0.1"
!pip install paddlepaddle

After the above installations, the following imports and definitions should be made:

from paddleocr import PaddleOCR
ocr = PaddleOCR(lang='en')

To obtain the detection coordinates, I have explained the complete procedure in the articles whose links I have shared above. Now using the text_coordinates, we will perform PPOCR recognition:

import cv2
import time
img_path = <> #define your image path here
start = time.time()
for coord in text_coordinates:
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]
if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
im2 =cv2.imread(img_path)
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
end = time.time()
print(f"Time taken with ordinary CPU: {end-start} sec")

The following output was obtained in my case:

Time taken with ordinary CPU: 11.89705514907837 sec

PPOCR recognition with multiprocessing

The installations for this are the same as the previous one. The following additional imports need to be made:

from multiprocessing import Pool
from functools import partial
pool = Pool(processes=8)

More about multiprocessing can be understood from its documentation which can be found here.

Get Bhargav Sridhar’s stories in your inbox

Join Medium for free to get updates from this writer.

Now, we will implement the recognition in a slightly different way:

def perform_ocr_recognition(coord, im2):
text = ""
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]

if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
return {str(coord): text[0][0]}
img = cv2.imread(img_path)
start = time.time()
text_output = pool.map(partial(perform_ocr_recognition, im2=img),
text_coordinates
)
end = time.time()
print(f"Time taken with multiprocessing: {end-start} sec")

The partial module is used to fix an argument throughout the process (especially in a loop). In our case, the image array would remain the same for the entire recognition process. That is why I declare it as a fixed argument and loop through the text coordinates outside the partial method.

The map function is used to automatically append the output of each iteration to a list. You can obtain the coordinate and text as dictionary objects and this can be checked by printing out the text_output variable.

The following output was obtained in my case (and it will vary for different users and systems):-

Time taken with multiprocessing: 7.432933568954468 sec

PPOCR recognition with Colab GPU

The following installations have to be made:-

!pip install "paddleocr>=2.0.1"
!pip install paddlepaddle
!python -m pip install paddlepaddle-gpu #or python3

The paddlepaddle-gpu can be used to implement PPOCR by utilizing GPU (especially when you have GPU-CUDA set up in your platform). More information on installing this on your system can be found in the paddlepaddle documentation.

The imports and implementation are the same as that of ordinary CPU:-

from paddleocr import PaddleOCR
import cv2
import time
ocr = PaddleOCR(lang='en')
img_path = <> #define your image path here
start = time.time()
for coord in text_coordinates:
x_min, y_min, x_max, y_max = coord[0], coord[2], \
coord[1], coord[3]
if x_min >= 0 and x_max >= 0 and \
y_min >= 0 and y_max >= 0:
im2 =cv2.imread(img_path)
cropped = im2[y_min: y_max, x_min: x_max]
text = ocr.ocr(cropped, det=False, cls=False)
end = time.time()
print(f"Time taken with GPU: {end-start} sec")

The following output was obtained in my case:-

Time taken with GPU: 0.5593817234039307 sec

Now let us try to understand the observations in the final section.

Observations and Conclusion

From the above experiments, the following observations are quite clear:-

  • Ordinary CPU has taken more time when compared to the other methods. This is due to the iteration of each coordinate and a single process is utilized to recognize all coordinates in order;
  • With multiprocessing, PPOCR recognition has executed faster than that of ordinary CPU, even though the time taken is still on the higher side. This is because multiple coordinates are recognized parallelly with the help of multiple processes utilized at the same time. But when testing with a large dataset, multiprocessing could save a lot of time than ordinary CPU execution;
  • As expected, recognition with GPU was the quickest, but implementation was a bit different when compared to the other OCR tools;

Thus, I hope I have given you an idea of improving the PPOCR recognition process. In most cases, GPU availability would be low and hence multiprocessing may serve as a good starting point to increase PPOCR recognition speed. However with a GPU availability, one could install the paddlepaddle-gpu which serves specifically for the PPOCR model and optimize the time as shown in the previous sections. I would be more than willing to acknowledge questions and clarifications related to the topic which can be posted through the comments. Hope you have found this article useful. Thanks!

--

--

Bhargav Sridhar
Bhargav Sridhar

Written by Bhargav Sridhar

PhD Student. Wants to write about Research, Tech, Math, Philosophy, and Life. Striving to make common knowledge and basic skills accessible to everybody.

Quantrium.ai
Quantrium.ai

Published in Quantrium.ai

This is Quantrium’s official tech blog. A blog on how technology enables us to develop great software applications for our clients.