So this is amazing and was very much needed. I adopted our Threading Based Queuing code to integrate with Tesseract OCR to chuck out a HUGE WORKLOAD of processing. With the updated code a User can simply select multiple High Detailed images to render and then walk away, The Images are then all translated at the same time but the data is dumped in the correct order! The newly spawned threads will wait until the previous ones before it are compelted then dump the data that has already been processed! Works like a charm!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
Imports Tesseract Imports System.Threading Imports System.Runtime.InteropServices Imports System.IO Public Class Form1 Private Delegate Sub MyDelPtr(CurrentInstance As MyThreading) Public Const MOD_ALT As Integer = &H1 'Alt key Public Const WM_HOTKEY As Integer = &H312 <DllImport("User32.dll")> Public Shared Function RegisterHotKey(ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer End Function <DllImport("User32.dll")> Public Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, ByVal id As Integer) As Integer End Function <DllImport("dwmapi.dll", PreserveSig:=False)> Public Shared Function DwmIsCompositionEnabled() As Boolean End Function <DllImport("dwmapi.dll", PreserveSig:=False)> Public Shared Sub DwmEnableComposition(ByVal bEnable As Boolean) End Sub <DllImport("user32.dll", EntryPoint:="GetCursorInfo")> Public Shared Function GetCursorInfo(ByRef pci As CURSORINFO) As Boolean End Function <DllImport("user32.dll", EntryPoint:="CopyIcon")> Public Shared Function CopyIcon(ByVal hIcon As IntPtr) As IntPtr End Function <DllImport("user32.dll", EntryPoint:="GetIconInfo")> Public Shared Function GetIconInfo(ByVal hIcon As IntPtr, ByRef piconinfo As ICONINFO) As Boolean End Function Dim aeroIsEnabled As Boolean Dim b As Bitmap Dim graphics As Graphics Dim StartPoint As New Point(0, 0) Dim ScreenShotSize As Drawing.Size Dim ThreadNameIndex As Integer = 0 Dim MyThreadingClass As MyThreading Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) If m.Msg = WM_HOTKEY Then Dim id As IntPtr = m.WParam Select Case (id.ToString) Case "100" Debug.WriteLine("You pressed ALT+S key combination") If StartPoint.IsEmpty Then StartPoint = GetCursorPosition() Debug.WriteLine(StartPoint) Else Dim MyEndPoint As Point = GetCursorPosition() Debug.WriteLine(MyEndPoint) Dim MyTwoPoints As New Point(MyEndPoint.X - StartPoint.X, MyEndPoint.Y - StartPoint.Y) ScreenShotSize = New Size(MyTwoPoints) Debug.WriteLine(ScreenShotSize) 'CaptureScreenshot(New Point(0, 0), PictureBox1.Size) 'This resizes the Background of the image to scale If True Then b = New Bitmap(PictureBox1.Size.Width, PictureBox1.Size.Height) Else b = New Bitmap(MyEndPoint.X - StartPoint.X, MyEndPoint.Y - StartPoint.Y) End If 'ResizeImage(b, b.Width * 3, b.Height * 3) PictureBox1.Image = b graphics = Graphics.FromImage(b) ' graphics.Clear(Color.Transparent) graphics.CopyFromScreen(StartPoint, New Point(0, 0), ScreenShotSize) Dim output As New Bitmap(ScreenShotSize.Width * 2, ScreenShotSize.Height * 2) Using g As Graphics = Graphics.FromImage(output) g.DrawImage(b, 0, 0, PictureBox1.Size.Width * 2, PictureBox1.Size.Height * 2) End Using PictureBox1.Image = output 'PictureBox1.Image.Save("./saved.tiff", System.Drawing.Imaging.ImageFormat.Tiff) 'ResizeImage(b, b.Width * 3, b.Height * 3) ' StartPoint = New Point(0, 0) Application.DoEvents() 'translateFromMemory(ConvertToByteArray(output)) If IsNothing(MyThreadingClass) Then MyThreadingClass = New MyThreading(ThreadNameIndex, ConvertToByteArray(output), Nothing, Me, New MyDelPtr(AddressOf PostBackFromThread)) Else MyThreadingClass = New MyThreading(ThreadNameIndex, ConvertToByteArray(output), MyThreadingClass.MyThreadToStart, Me, New MyDelPtr(AddressOf PostBackFromThread)) End If ThreadNameIndex += 1 'translateFromFile("./saved.tiff") 'translateFromMemory(ConvertToByteArray(New Bitmap(ScreenShotSize.Width, ScreenShotSize.Height, graphics))) End If Case "200" MessageBox.Show("You pressed ALT+C key combination") End Select End If MyBase.WndProc(m) End Sub Public Sub PostBackFromThread(CurrentInstance As MyThreading) Debug.WriteLine("Results (in order) came back to mainthread from:" & CurrentInstance.MyThreadToStart.Name & " Data returned: " & CurrentInstance.DataToReturn) TextBox1.Text &= CurrentInstance.DataToReturn CurrentInstance = Nothing End Sub Public Shared Function ConvertToByteArray(ByVal value As Bitmap) As Byte() Dim ms = New System.IO.MemoryStream value.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff) ' Use appropriate format here Dim bytes = ms.ToArray() Return bytes End Function #Region " ResizeImage " Public Overloads Shared Function ResizeImage(SourceImage As Drawing.Image, TargetWidth As Int32, TargetHeight As Int32) As Drawing.Bitmap Dim bmSource = New Drawing.Bitmap(SourceImage) Return ResizeImage(bmSource, TargetWidth, TargetHeight) End Function Public Overloads Shared Function ResizeImage(bmSource As Drawing.Bitmap, TargetWidth As Int32, TargetHeight As Int32) As Drawing.Bitmap Dim bmDest As New Drawing.Bitmap(TargetWidth, TargetHeight, Drawing.Imaging.PixelFormat.Format32bppArgb) Dim nSourceAspectRatio = bmSource.Width / bmSource.Height Dim nDestAspectRatio = bmDest.Width / bmDest.Height Dim NewX = 0 Dim NewY = 0 Dim NewWidth = bmDest.Width Dim NewHeight = bmDest.Height If nDestAspectRatio = nSourceAspectRatio Then 'same ratio ElseIf nDestAspectRatio > nSourceAspectRatio Then 'Source is taller NewWidth = Convert.ToInt32(Math.Floor(nSourceAspectRatio * NewHeight)) NewX = Convert.ToInt32(Math.Floor((bmDest.Width - NewWidth) / 2)) Else 'Source is wider NewHeight = Convert.ToInt32(Math.Floor((1 / nSourceAspectRatio) * NewWidth)) NewY = Convert.ToInt32(Math.Floor((bmDest.Height - NewHeight) / 2)) End If Using grDest = Drawing.Graphics.FromImage(bmDest) With grDest .CompositingQuality = Drawing.Drawing2D.CompositingQuality.HighQuality .InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic .PixelOffsetMode = Drawing.Drawing2D.PixelOffsetMode.HighQuality .SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias .CompositingMode = Drawing.Drawing2D.CompositingMode.SourceOver .DrawImage(bmSource, NewX, NewY, NewWidth, NewHeight) End With End Using Return bmDest End Function #End Region Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Add any initialization after the InitializeComponent() call. 'b = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height) b = New Bitmap(PictureBox1.Size.Width, PictureBox1.Size.Height) PictureBox1.Image = b graphics = Graphics.FromImage(b) Me.DisableAero() RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.S) 'PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage 'translateFromFile("./saved.tiff") End Sub Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) _ Handles MyBase.FormClosing UnregisterHotKey(Me.Handle, 100) UnregisterHotKey(Me.Handle, 200) End Sub Private Sub DisableAero() Try aeroIsEnabled = DwmIsCompositionEnabled() If aeroIsEnabled = True Then DwmEnableComposition(False) End If Catch ex As Exception End Try End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick 'Timer1.Stop() CaptureScreenshot(New Point(0, 0), PictureBox1.Size) 'Timer1.Start() End Sub Private Function CaptureScreenshot(startPoint As Point, DrawingSize As Size) As Boolean Try If b IsNot Nothing Then 'graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.Location, New Point(0, 0), Screen.PrimaryScreen.Bounds.Size) 'Dim newDrawingSize As New System.Drawing.Size(PictureBox1.Size) 'graphics.CopyFromScreen(New Point(x, y), startPoint, DrawingSize) 'graphics.CopyFromScreen(startPoint, New Point(0, 0), DrawingSize, CopyPixelOperation.SourceAnd) graphics.CopyFromScreen(startPoint, New Point(0, 0), DrawingSize) If False Then Dim x As Integer Dim y As Integer Dim cursorBmp As Bitmap = CaptureCursor(x, y) 'Draws Cursor on picture graphics.DrawImage(cursorBmp, x, y) cursorBmp.Dispose() 'Cursor.Draw(graphics, New Rectangle(Cursor.Position, Cursor.Size)) End If Me.Refresh() End If Catch ex As Exception End Try End Function Private Shared Function CaptureCursor(ByRef x As Integer, ByRef y As Integer) As Bitmap Dim bmp As Bitmap Dim hicon As IntPtr Dim ci As New CURSORINFO() Dim icInfo As ICONINFO ci.cbSize = Marshal.SizeOf(ci) If GetCursorInfo(ci) Then hicon = CopyIcon(ci.hCursor) If GetIconInfo(hicon, icInfo) Then x = ci.ptScreenPos.X - CInt(icInfo.xHotspot) y = ci.ptScreenPos.Y - CInt(icInfo.yHotspot) Dim ic As Icon = Icon.FromHandle(hicon) bmp = ic.ToBitmap() ic.Dispose() Return bmp End If End If Return Nothing End Function Private Shared Function GetCursorPosition() As Point Dim hicon As IntPtr Dim ci As New CURSORINFO() Dim icInfo As ICONINFO Dim x, y As Integer ci.cbSize = Marshal.SizeOf(ci) If GetCursorInfo(ci) Then hicon = CopyIcon(ci.hCursor) If GetIconInfo(hicon, icInfo) Then x = ci.ptScreenPos.X - CInt(icInfo.xHotspot) y = ci.ptScreenPos.Y - CInt(icInfo.yHotspot) Return New Point(x, y) End If End If Return Nothing End Function <StructLayout(LayoutKind.Sequential)> Public Structure CURSORINFO Public cbSize As Int32 Public flags As Int32 Public hCursor As IntPtr Public ptScreenPos As Point End Structure <StructLayout(LayoutKind.Sequential)> Public Structure ICONINFO Public fIcon As Boolean Public xHotspot As Int32 Public yHotspot As Int32 Public hbmMask As IntPtr Public hbmColor As IntPtr End Structure Public Function translateFromMemory(ByteArray As Byte()) As String Try Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default) Using img = Pix.LoadTiffFromMemory(ByteArray) Using page = engine.Process(img) Dim text = page.GetText() Console.WriteLine("Mean confidence: {0}", page.GetMeanConfidence()) Console.WriteLine("Text (GetText): " & vbCr & vbLf & "{0}", text) Console.WriteLine("Text (iterator):") Using iter = page.GetIterator() iter.Begin() Do Do Do Do If iter.IsAtBeginningOf(PageIteratorLevel.Block) Then Console.WriteLine("<BLOCK>") End If If iter.GetText(PageIteratorLevel.Word).Trim.EndsWith("-") Then translateFromMemory &= (iter.GetText(PageIteratorLevel.Word).Replace("-", "")) Else translateFromMemory &= (iter.GetText(PageIteratorLevel.Word)) translateFromMemory &= (" ") End If If iter.IsAtFinalOf(PageIteratorLevel.TextLine, PageIteratorLevel.Word) Then If Not CheckBox1.Checked AndAlso Not iter.GetText(PageIteratorLevel.Word).EndsWith("-") Then translateFromMemory &= vbCrLf End If End If Loop While iter.[Next](PageIteratorLevel.TextLine, PageIteratorLevel.Word) If iter.IsAtFinalOf(PageIteratorLevel.Para, PageIteratorLevel.TextLine) Then Console.WriteLine() End If Loop While iter.[Next](PageIteratorLevel.Para, PageIteratorLevel.TextLine) Loop While iter.[Next](PageIteratorLevel.Block, PageIteratorLevel.Para) Loop While iter.[Next](PageIteratorLevel.Block) End Using End Using End Using End Using Catch ex As Exception Trace.TraceError(ex.ToString()) Console.WriteLine("Unexpected Error: " + ex.Message) Console.WriteLine("Details: ") Console.WriteLine(ex.ToString()) End Try translateFromMemory &= vbCrLf & vbCrLf Return translateFromMemory End Function Public Sub translateFromFile(testImagePath As String, sw As IO.StreamWriter) Try Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default) Using img = Pix.LoadFromFile(testImagePath) Using page = engine.Process(img) Dim text = page.GetText() Console.WriteLine("Mean confidence: {0}", page.GetMeanConfidence()) Console.WriteLine("Text (GetText): " & vbCr & vbLf & "{0}", text) Console.WriteLine("Text (iterator):") Using iter = page.GetIterator() iter.Begin() Do Do Do Do If iter.IsAtBeginningOf(PageIteratorLevel.Block) Then Console.WriteLine("<BLOCK>") End If 'TextBox1.Text &= (iter.GetText(PageIteratorLevel.Word)) 'TextBox1.Text &= (" ") If iter.GetText(PageIteratorLevel.Word).Trim.EndsWith("-") Then sw.Write(iter.GetText(PageIteratorLevel.Word).Replace("-", "")) Else sw.Write(iter.GetText(PageIteratorLevel.Word) & (" ")) End If If iter.IsAtFinalOf(PageIteratorLevel.TextLine, PageIteratorLevel.Word) Then If Not CheckBox1.Checked AndAlso Not iter.GetText(PageIteratorLevel.Word).EndsWith("-") Then sw.WriteLine() End If End If Loop While iter.[Next](PageIteratorLevel.TextLine, PageIteratorLevel.Word) If iter.IsAtFinalOf(PageIteratorLevel.Para, PageIteratorLevel.TextLine) Then Console.WriteLine() End If Loop While iter.[Next](PageIteratorLevel.Para, PageIteratorLevel.TextLine) Loop While iter.[Next](PageIteratorLevel.Block, PageIteratorLevel.Para) Loop While iter.[Next](PageIteratorLevel.Block) End Using End Using End Using End Using Catch ex As Exception Trace.TraceError(ex.ToString()) Console.WriteLine("Unexpected Error: " + ex.Message) Console.WriteLine("Details: ") Console.WriteLine(ex.ToString()) End Try Console.Write("Press any key to continue . . . ") End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Timer1.Interval = 1000 Timer1.Enabled = True End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click If (FolderBrowserDialog1.ShowDialog() = DialogResult.OK) Then Using sw As StreamWriter = File.AppendText(FolderBrowserDialog1.SelectedPath & "\Output.txt") For Each MyFile As String In IO.Directory.GetFiles(FolderBrowserDialog1.SelectedPath) translateFromFile(MyFile, sw) Application.DoEvents() Next End Using End If End Sub End Class Public Class MyThreading Public DataToPass() As Byte Public DataToReturn As String Public CallingThreadForm As Form Public InvokeFunctionOnCompelte As [Delegate] Public MyThreadToStart As Threading.Thread Public PreviousThread As System.Threading.Thread Public Sub New(ByVal NameOfThread As String, ByVal pDataToPass() As Byte, ByVal pPreviousThread As Threading.Thread, ByVal pCallingThreadForm As Form, ByVal pInvokeFunctionOnCompelte As [Delegate]) DataToPass = pDataToPass.Clone PreviousThread = pPreviousThread CallingThreadForm = pCallingThreadForm InvokeFunctionOnCompelte = pInvokeFunctionOnCompelte MyThreadToStart = New Threading.Thread(AddressOf StartWork) MyThreadToStart.Name = NameOfThread MyThreadToStart.Start() End Sub Private Sub StartWork() DataToReturn = CType(CallingThreadForm, Form1).translateFromMemory(DataToPass) If PreviousThread IsNot Nothing Then While PreviousThread.IsAlive Debug.WriteLine(MyThreadToStart.Name & ": Sleeping for a Seconds while waiting on " & PreviousThread.Name & " to complete") Threading.Thread.Sleep(500) End While Else Debug.WriteLine(MyThreadToStart.Name & "Previous Thread is nothing") End If Debug.WriteLine(MyThreadToStart.Name & ": Done!") CallingThreadForm.Invoke(InvokeFunctionOnCompelte, Me) End Sub End Class |