使用 Windows.Media.Ocr 引擎逐行扫描
Scanning line by line with Windows.Media.Ocr engine
我正在使用 Windows.Media.OCR 引擎来扫描这两行
但是软件是这样扫描的:
虽然我希望它能像这样扫描:
KIBA/USDT 0.00003826 6.31M KIBA 241.68459400 USDT
KIBA/USDT 0.00003470 17.13M KIBA 594.48387000 USDT
我使用的代码是:
'require references: "C:\Program Files (x86)\Windows Kits\UnionMetadata\Windows.winmd"
'"C:\ProgramFiles(x86)\ReferenceAssemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll"
' and windows 10 sdk
Imports Windows.Media.Ocr
Imports System.IO
Imports System.Runtime.InteropServices.WindowsRuntime
Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim softwareBmp As Windows.Graphics.Imaging.SoftwareBitmap
Using bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Using g As Graphics = Graphics.FromImage(bmp)
Dim pt As Point = Me.PointToScreen(New Point(PictureBox1.Left, PictureBox1.Top))
g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy)
Using memStream = New Windows.Storage.Streams.InMemoryRandomAccessStream()
bmp.Save(memStream.AsStream(), System.Drawing.Imaging.ImageFormat.Bmp)
Dim decoder As Windows.Graphics.Imaging.BitmapDecoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream)
softwareBmp = Await decoder.GetSoftwareBitmapAsync()
End Using
End Using
End Using
Dim ocrEng = OcrEngine.TryCreateFromLanguage(New Windows.Globalization.Language("en-US"))
Dim languages As IReadOnlyList(Of Windows.Globalization.Language) = ocrEng.AvailableRecognizerLanguages
For Each language In languages
Console.WriteLine(language.LanguageTag)
Next
Dim r = ocrEng.RecognizerLanguage
Dim n = ocrEng.MaxImageDimension
Dim ocrResult = Await ocrEng.RecognizeAsync(softwareBmp)
RichTextBox1.Text = ocrResult.Text
End Sub
End Class
为了按行扫描而不是按列扫描,此代码需要进行哪种更改?
编辑:
二进制:code
所以行与行之间有0D 0A
完整的行图像:
但我之前没有 post 因为无论如何我只需要从 0.000038 ecc 扫描到 0.0000%
我选择对输出字符串执行操作而不是处理 OCR API。
如果可能的话,在 OCR API 中解决问题可能是一个更好的解决方案,但我无法在我的系统中正确引用您的代码。
所以你可以添加这个函数来转置字符串
Private Function transpose(input As String) As String
Dim numberOfColumns = 4 ' this must be known and could be a parameter to this function
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT")
Dim splitInput = fixedInput.Split(" "c)
Dim numberOfWords = splitInput.Count()
Dim numberOfRows = numberOfWords / numberOfColumns
Dim words As New List(Of String)()
For row = 0 To numberOfRows - 1
For col = 0 To numberOfColumns - 1
words.Add(splitInput(CInt(row + numberOfRows * col)))
Next
Next
Dim sb As New System.Text.StringBuilder()
For i = 0 To words.Count() - 1
sb.Append(words(i).Replace("|", " "))
If (i <> words.Count() - 1) Then
sb.Append(If((i + 1) Mod numberOfColumns = 0, Environment.NewLine, vbTab))
End If
Next
Return sb.ToString()
End Function
只需将您的 ocr 输出字符串传递给它即可。这里是在你的代码中调用的
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim softwareBmp As Windows.Graphics.Imaging.SoftwareBitmap
Using bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Using g As Graphics = Graphics.FromImage(bmp)
Dim pt As Point = Me.PointToScreen(New Point(PictureBox1.Left, PictureBox1.Top))
g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy)
Using memStream = New Windows.Storage.Streams.InMemoryRandomAccessStream()
bmp.Save(memStream.AsStream(), System.Drawing.Imaging.ImageFormat.Bmp)
Dim decoder As Windows.Graphics.Imaging.BitmapDecoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream)
softwareBmp = Await decoder.GetSoftwareBitmapAsync()
End Using
End Using
End Using
Dim ocrEng = OcrEngine.TryCreateFromLanguage(New Windows.Globalization.Language("en-US"))
Dim languages As IReadOnlyList(Of Windows.Globalization.Language) = ocrEng.AvailableRecognizerLanguages
For Each language In languages
Console.WriteLine(language.LanguageTag)
Next
Dim r = ocrEng.RecognizerLanguage
Dim n = ocrEng.MaxImageDimension
Dim ocrResult = Await ocrEng.RecognizeAsync(softwareBmp)
RichTextBox1.Text = transpose(ocrResult.Text)
End Sub
我用这个功能测试过
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim input = "0.00003599 0.00003599 104.1K KIBA 23.22M KIBA 3.74655900 USDT 835.89654200 USDT 0.0000% 0.0000%"
Dim output = transpose(input)
End Sub
输入:
0.00003599 0.00003599 104.1K KIBA 23.22M KIBA 3.74655900 USDT 835.89654200 USDT 0.0000% 0.0000%
输出:
0.00003599 104.1K KIBA 3.74655900 USDT 0.0000%
0.00003599 23.22M KIBA 835.89654200 USDT 0.0000%
请注意,您需要修复您的字符串,通过将 space
替换为管道 |
来临时替换任何包含多个单词的句子,这样它们就不会被拆分,如果您遇到更多这样的例子可以根据代码继续添加Replace
。如果管道被证明是一个有效的字符,请将其替换为您永远不会看到的其他字符。
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT")
...
sb.Append(words(i).Replace("|", " "))
另一个解决方案,再次通过转置处理不正确的字符串,但这次输出将是一个 class,您可以使用它。
做一个class来代表你的数据
Public Class KibaClass
Public Property Price As Decimal
Public Property VolumeKIBA As Decimal
Public Property VolumeUSDT As Decimal
Public Property Percent As Decimal
End Class
还有一个不同的函数来解析这个 class
Private Function transposeToClass(input As String) As IEnumerable(Of KibaClass)
Dim numberOfColumns = 4
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT").Trim()
Dim splitInput = fixedInput.Split(" "c)
Dim numberOfWords = splitInput.Count()
Dim numberOfRows = numberOfWords / numberOfColumns ' 2
Dim words As New List(Of String)()
For row = 0 To numberOfRows - 1
For col = 0 To numberOfColumns - 1
words.Add(splitInput(CInt(row + numberOfRows * col)))
Next
Next
Dim kibas As New List(Of KibaClass)()
For row = 0 To numberOfRows - 1
Dim rowOffset = CInt(row * numberOfColumns)
Dim kiba = New KibaClass With {
.Percent = CDec(words(3 + rowOffset).Replace("%", "")) / 100,
.Price = CDec(words(0 + rowOffset))}
Dim multiplier As Double
Dim splitVolume = words(1 + rowOffset).Split("|"c)(0)
Dim lastChar = Convert.ToChar(splitVolume.Last())
Dim volume = splitVolume
If Not Char.IsDigit(lastChar) Then
volume = splitVolume.Substring(0, splitVolume.Length - 1)
Select Case lastChar.ToString().ToUpper()
Case "T"
multiplier = 1000000000.0
Case "M"
multiplier = 1000000.0
Case "K"
multiplier = 1000.0
Case Else
multiplier = 1.0
End Select
End If
kiba.VolumeKIBA = CDec(CDbl(volume) * multiplier)
splitVolume = words(2 + rowOffset).Split("|"c)(0)
lastChar = Convert.ToChar(splitVolume.Last())
volume = splitVolume
If Not Char.IsDigit(lastChar) Then
volume = splitVolume.Substring(0, splitVolume.Length - 1)
Select Case lastChar.ToString().ToUpper()
Case "T"
multiplier = 1000000000.0
Case "M"
multiplier = 1000000.0
Case "K"
multiplier = 1000.0
Case Else
multiplier = 1.0
End Select
End If
kiba.VolumeUSDT = CDec(CDbl(volume) * multiplier)
kibas.Add(kiba)
Next
Return kibas
End Function
Dim output1 = transposeToClass(input)
这包含您的 class 的 IEnumerable
,您可以将其枚举到该对象的多个实例中,这些实例具有代表您最初 OCR 的列的正确格式的属性。
我正在使用 Windows.Media.OCR 引擎来扫描这两行
但是软件是这样扫描的:
虽然我希望它能像这样扫描:
KIBA/USDT 0.00003826 6.31M KIBA 241.68459400 USDT
KIBA/USDT 0.00003470 17.13M KIBA 594.48387000 USDT
我使用的代码是:
'require references: "C:\Program Files (x86)\Windows Kits\UnionMetadata\Windows.winmd"
'"C:\ProgramFiles(x86)\ReferenceAssemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll"
' and windows 10 sdk
Imports Windows.Media.Ocr
Imports System.IO
Imports System.Runtime.InteropServices.WindowsRuntime
Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim softwareBmp As Windows.Graphics.Imaging.SoftwareBitmap
Using bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Using g As Graphics = Graphics.FromImage(bmp)
Dim pt As Point = Me.PointToScreen(New Point(PictureBox1.Left, PictureBox1.Top))
g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy)
Using memStream = New Windows.Storage.Streams.InMemoryRandomAccessStream()
bmp.Save(memStream.AsStream(), System.Drawing.Imaging.ImageFormat.Bmp)
Dim decoder As Windows.Graphics.Imaging.BitmapDecoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream)
softwareBmp = Await decoder.GetSoftwareBitmapAsync()
End Using
End Using
End Using
Dim ocrEng = OcrEngine.TryCreateFromLanguage(New Windows.Globalization.Language("en-US"))
Dim languages As IReadOnlyList(Of Windows.Globalization.Language) = ocrEng.AvailableRecognizerLanguages
For Each language In languages
Console.WriteLine(language.LanguageTag)
Next
Dim r = ocrEng.RecognizerLanguage
Dim n = ocrEng.MaxImageDimension
Dim ocrResult = Await ocrEng.RecognizeAsync(softwareBmp)
RichTextBox1.Text = ocrResult.Text
End Sub
End Class
为了按行扫描而不是按列扫描,此代码需要进行哪种更改?
编辑: 二进制:code
所以行与行之间有0D 0A
完整的行图像:
但我之前没有 post 因为无论如何我只需要从 0.000038 ecc 扫描到 0.0000%
我选择对输出字符串执行操作而不是处理 OCR API。
如果可能的话,在 OCR API 中解决问题可能是一个更好的解决方案,但我无法在我的系统中正确引用您的代码。
所以你可以添加这个函数来转置字符串
Private Function transpose(input As String) As String
Dim numberOfColumns = 4 ' this must be known and could be a parameter to this function
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT")
Dim splitInput = fixedInput.Split(" "c)
Dim numberOfWords = splitInput.Count()
Dim numberOfRows = numberOfWords / numberOfColumns
Dim words As New List(Of String)()
For row = 0 To numberOfRows - 1
For col = 0 To numberOfColumns - 1
words.Add(splitInput(CInt(row + numberOfRows * col)))
Next
Next
Dim sb As New System.Text.StringBuilder()
For i = 0 To words.Count() - 1
sb.Append(words(i).Replace("|", " "))
If (i <> words.Count() - 1) Then
sb.Append(If((i + 1) Mod numberOfColumns = 0, Environment.NewLine, vbTab))
End If
Next
Return sb.ToString()
End Function
只需将您的 ocr 输出字符串传递给它即可。这里是在你的代码中调用的
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim softwareBmp As Windows.Graphics.Imaging.SoftwareBitmap
Using bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Using g As Graphics = Graphics.FromImage(bmp)
Dim pt As Point = Me.PointToScreen(New Point(PictureBox1.Left, PictureBox1.Top))
g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy)
Using memStream = New Windows.Storage.Streams.InMemoryRandomAccessStream()
bmp.Save(memStream.AsStream(), System.Drawing.Imaging.ImageFormat.Bmp)
Dim decoder As Windows.Graphics.Imaging.BitmapDecoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream)
softwareBmp = Await decoder.GetSoftwareBitmapAsync()
End Using
End Using
End Using
Dim ocrEng = OcrEngine.TryCreateFromLanguage(New Windows.Globalization.Language("en-US"))
Dim languages As IReadOnlyList(Of Windows.Globalization.Language) = ocrEng.AvailableRecognizerLanguages
For Each language In languages
Console.WriteLine(language.LanguageTag)
Next
Dim r = ocrEng.RecognizerLanguage
Dim n = ocrEng.MaxImageDimension
Dim ocrResult = Await ocrEng.RecognizeAsync(softwareBmp)
RichTextBox1.Text = transpose(ocrResult.Text)
End Sub
我用这个功能测试过
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim input = "0.00003599 0.00003599 104.1K KIBA 23.22M KIBA 3.74655900 USDT 835.89654200 USDT 0.0000% 0.0000%"
Dim output = transpose(input)
End Sub
输入:
0.00003599 0.00003599 104.1K KIBA 23.22M KIBA 3.74655900 USDT 835.89654200 USDT 0.0000% 0.0000%
输出:
0.00003599 104.1K KIBA 3.74655900 USDT 0.0000%
0.00003599 23.22M KIBA 835.89654200 USDT 0.0000%
请注意,您需要修复您的字符串,通过将 space
替换为管道 |
来临时替换任何包含多个单词的句子,这样它们就不会被拆分,如果您遇到更多这样的例子可以根据代码继续添加Replace
。如果管道被证明是一个有效的字符,请将其替换为您永远不会看到的其他字符。
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT")
...
sb.Append(words(i).Replace("|", " "))
另一个解决方案,再次通过转置处理不正确的字符串,但这次输出将是一个 class,您可以使用它。
做一个class来代表你的数据
Public Class KibaClass
Public Property Price As Decimal
Public Property VolumeKIBA As Decimal
Public Property VolumeUSDT As Decimal
Public Property Percent As Decimal
End Class
还有一个不同的函数来解析这个 class
Private Function transposeToClass(input As String) As IEnumerable(Of KibaClass)
Dim numberOfColumns = 4
Dim fixedInput = input.Replace(" KIBA", "|KIBA").Replace(" USDT", "|USDT").Trim()
Dim splitInput = fixedInput.Split(" "c)
Dim numberOfWords = splitInput.Count()
Dim numberOfRows = numberOfWords / numberOfColumns ' 2
Dim words As New List(Of String)()
For row = 0 To numberOfRows - 1
For col = 0 To numberOfColumns - 1
words.Add(splitInput(CInt(row + numberOfRows * col)))
Next
Next
Dim kibas As New List(Of KibaClass)()
For row = 0 To numberOfRows - 1
Dim rowOffset = CInt(row * numberOfColumns)
Dim kiba = New KibaClass With {
.Percent = CDec(words(3 + rowOffset).Replace("%", "")) / 100,
.Price = CDec(words(0 + rowOffset))}
Dim multiplier As Double
Dim splitVolume = words(1 + rowOffset).Split("|"c)(0)
Dim lastChar = Convert.ToChar(splitVolume.Last())
Dim volume = splitVolume
If Not Char.IsDigit(lastChar) Then
volume = splitVolume.Substring(0, splitVolume.Length - 1)
Select Case lastChar.ToString().ToUpper()
Case "T"
multiplier = 1000000000.0
Case "M"
multiplier = 1000000.0
Case "K"
multiplier = 1000.0
Case Else
multiplier = 1.0
End Select
End If
kiba.VolumeKIBA = CDec(CDbl(volume) * multiplier)
splitVolume = words(2 + rowOffset).Split("|"c)(0)
lastChar = Convert.ToChar(splitVolume.Last())
volume = splitVolume
If Not Char.IsDigit(lastChar) Then
volume = splitVolume.Substring(0, splitVolume.Length - 1)
Select Case lastChar.ToString().ToUpper()
Case "T"
multiplier = 1000000000.0
Case "M"
multiplier = 1000000.0
Case "K"
multiplier = 1000.0
Case Else
multiplier = 1.0
End Select
End If
kiba.VolumeUSDT = CDec(CDbl(volume) * multiplier)
kibas.Add(kiba)
Next
Return kibas
End Function
Dim output1 = transposeToClass(input)
这包含您的 class 的 IEnumerable
,您可以将其枚举到该对象的多个实例中,这些实例具有代表您最初 OCR 的列的正确格式的属性。