views:

207

answers:

0

Howdy, I'm attempting to use OCR to automate some of the QA process we have in place at work. A QA worker gets one terminal open per document scanner, and as work orders are scanned, they appear in the terminal, and information from this terminal is entered into a different tool to be added to a database, then the QA worker signals they are done with the current document, and the terminal will retrieve/wait for the next document.

I have a main thread, that constantly watches for terminal windows to open, and upon detecting a new terminal window opening, spawns a new thread, that new threads job is to manage that specific terminal window.

In that thread, I check to see if a new document has appeared, and upon it appearing, I call three functions, those three functions read specific screen coordinates, run them through tessnet2/tesseract-ocr, and return the results to the worker thread. This works fine on one thread, with one terminal window. However when two terminal windows are open, neither work. I assumed it was a race condition so I've applied a mutex that is acquired before calling the 3 ocr functions, and released after the third is completed.

In the terminal management thread, upon detecting a new document, I do this (aRECT is the rectangle of the terminal window, it's sending the X,Y of the window so that no matter where the terminal window is, the locations are read correctly.

            mutexReadSections.WaitOne()
            orderNumberStr = ReadOrderNumber(aRECT.Left, aRECT.Top)
            orderTypeStr = ReadOrderType(aRECT.Left, aRECT.Top)
            orderSalesmanStr = ReadOrderSalesman(aRECT.Left, aRECT.Top)
            mutexReadReactions.ReleaseMutex()

The three functions are identical, except for the location of the square that they read. In the following function desktopHDC is a global variable containing the hardware device context of the desktop (0). pbOrderNum is just a picture box on the form so that I can see the image captured, it functions the same way whether this is commented out or not.

Public Function ReadOrderNum(ByVal windowx As Integer, ByVal windowy As Integer) As String
    Try
        Dim ocr As Tesseract = New Tesseract()
        ocr.Init("C:\tessdata", "eng", False)
        Dim orderNumStr As String = ""
        Dim dsk As IntPtr = desktopHDC
        Dim mem As IntPtr = CreateCompatibleDC(dsk)
        Dim currentView As Bitmap
        Dim newBMP As IntPtr
        Dim eps As Imaging.EncoderParameters = New Imaging.EncoderParameters(1)
        Dim CodecInfo() As System.Drawing.Imaging.ImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders
        Dim TifCodec As System.Drawing.Imaging.ImageCodecInfo = CodecInfo(3)
        eps.Param(0) = New Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, System.Drawing.Imaging.EncoderValue.CompressionNone)
        mem = CreateCompatibleDC(dsk)
        newBMP = CreateCompatibleBitmap(dsk, 22, 26)
        If newBMP <> IntPtr.Zero Then
            Dim oldBmp As IntPtr = DirectCast(SelectObject(mem, newBMP), IntPtr)
            BitBlt(mem, 0, 0, 22, 26, dsk, 229 + windowx, 218 + windowy, SRCCOPY)
            SelectObject(mem, oldBmp)
            DeleteDC(mem)
            'ReleaseDC(desktopHDC, dsk)
            currentView = Image.FromHbitmap(newBMP)
            pbOrderNum.Image = currentView
            Dim uhWords As New List(Of tessnet2.Word)
            currentView = convertTo1bpp(currentView)
            uhWords = ocr.doOCR(currentView, Rectangle.Empty)
            For Each word In uhWords
                orderNumStr = word.Text
            Next
        End If
        ocr.Dispose()
        Return OrderNumStr
    Catch ex As Exception
        WriteReceived("OrderNum Error: " & ex.Message.ToString)
        Return 0
    End Try
End Function

I have tried using a global variable for the ocr object, with no change, I've also tried putting these functions directly in the management thread (so they aren't calling anything external. Everything I try results in the same problem, it works great with 1 thread, and fails for all threads as soon as I use more than one.