tess4j icon indicating copy to clipboard operation
tess4j copied to clipboard

how to increase processing speed of tesseract OCR?

Open svijayakumar1 opened this issue 5 years ago • 7 comments

Hi Quan,

Hope you're doing good. I have developed tessesract ocr application in spring boot. This application must scan 600,000 pdf scanned images. Currently , I am using tess 4j 4.4.0 version. It is taking 1 hour to process 275 pdfs. Per day it will be 6600 pdfs. I request you kindly provide solution to increase the processing speed of tesseract OCR , so that it scanning part will be completed. I must finish this task at the earliest. Please help me

svijayakumar1 avatar Aug 14 '19 21:08 svijayakumar1

More CPU cores, more RAM, multi-threading? Keep an instance of Tesseract engine to process several images instead of repeatedly instantiating for each image. Use GS to convert PDFs for speed.

Other users/developers please charm in.

nguyenq avatar Aug 16 '19 00:08 nguyenq

New release 4.4.1 bundles tessdata_fast data, which significantly cuts down processing time.

nguyenq avatar Oct 09 '19 00:10 nguyenq

@svijayakumar1 You can hack the PdfBox so it renders the pages in parallel to an array of ImageBuffers. Then you can OCR the pages in parallel (1 page per core). This reduces the OCR time dramatically for me.

ChristianSchwarz avatar Jan 20 '20 15:01 ChristianSchwarz

More CPU cores, more RAM, multi-threading? Keep an instance of Tesseract engine to process several images instead of repeatedly instantiating for each image. Use GS to convert PDFs for speed.

Other users/developers please charm in.

Quan Keep an instance of Tesseract engine to process: Are you suggesting to avoid new Tesserract1() for each image or you mean something else. Use GS to convert PDfs: I have tried this but it is taking more time. I am splitting pdf into single pages using pdfbox and then sent for processing, does that sounds good you will still suggest using GS.

Yogeshmsharma-architect avatar Apr 07 '21 19:04 Yogeshmsharma-architect

@Yogeshmsharma-architect Yes, setup and shutdown of the OCR engine for each image could take significant amounts of time. If you can send in a list of images to be processed all at once, it could help. There's a doOCR method version that accepts List<IIOImage> as input that you can use.

Or you can extend or come up with an alternative implementation of Tesseract or Tesseract1 to accept list of files or buffered images. Those classes are just applications of the base TessAPI classes.

If PDFBox is faster than GS for you, then, by all means, stick with it. Our own experience showed that GS has generally been faster.

nguyenq avatar Apr 25 '21 17:04 nguyenq

Here is what I did: Extract pages from the PDF in parallel, a page per core. Then pass every page image for further processing to the callback onImageExtracted. Note: You should not use more threads than cores, otherwise the whole process will getting slower rather, see: Executors.newFixedThreadPool(...). This helped me to speed up the image extraction by factor ~7.

The following sample is written in Kotlin:

    /**
     * Converts PDF-pages  to BufferedImage's.
      */
    @Throws(IOException::class)
    fun convertPdfToBufferedImages(inputPdfFile: File, onImageExtracted: (BufferedImage, pageIndex:Int)->Unit) {

        val executor = Executors.newFixedThreadPool(8)
        PDDocument.load(inputPdfFile).use { document ->
            val pdfRenderer = PDFRenderer(document)

            val numberOfPages = document.numberOfPages
            val out = Array<BufferedImage?>(numberOfPages) { null }
            out.forEachIndexed { pageIndex, _ ->
                executor.submit {
                    try {
                        val pageImage = pdfRenderer.renderImageWithDPI(pageIndex, 300f, ImageType.GRAY)
                        out[pageIndex] = pageImage
                        onImageExtracted(pageImage,pageIndex)
                    } catch (e: IOException) {
                        logger.error("Error extracting PDF Document pageIndex $pageIndex=> $e", e)
                    }
                }
            }
            executor.shutdown()
            executor.awaitTermination(5, TimeUnit.HOURS)
        }
    }

ChristianSchwarz avatar Apr 26 '21 08:04 ChristianSchwarz

@ChristianSchwarz Thanks for example! Than you call one instance of tess4j or have you also 8 instances in a pool?

alisdev avatar May 22 '24 15:05 alisdev