Vb.Net 2015 - проблема с хранением байтового массива и сравнениями с использованием lockbits/marshal.copy
Я новичок здесь, так что извините, если мой вопрос не в надлежащем формате, чтобы дать ответ. Пожалуйста, дайте мне знать, если мне нужно что-то добавить:
В настоящее время я работаю над проектом из дома для помощника в компании, которая использует действительно старую унаследованную систему, которая отображает вывод на экран. Система, которая у них есть, устарела и больше не поддерживается (компания, которая ее установила, больше не работает). Мне сказали, что им нужно хранить систему для ежемесячных отчетов, но они хотят отображать ее результаты более современным способом, чтобы, когда люди приходят, они могли видеть, что происходит без смущения. Трудно объяснить, но в основном меня просили захватывать информацию с экрана и выводить ее на другой.
Я проработал примерно 3/4 образца, написанного на VB.Net... и обнаружил, что сравнение изображений слишком медленное для изменений, происходящих с использованием getpixel для сравнения. Скорость также была проблемой при сохранении изображений в поток памяти для сравнения (проходя через x,y в поисках совпадения)... поэтому я переключился на копирование блокировок / маршалов в байтовые массивы для сравнения. В основном - данные, отображаемые в нескольких областях, всегда соответствуют одному из примерно 20 изображений, которые я сохранил. Я могу сравнивать изображения, используя снимки и сохраненные изображения (поместите diff поверх существующего сохраненного изображения, и результат будет затемнен на 100%). Я знаю, что мои сохраненные изображения соответствуют 100%, а предыдущие методы сравнения из g.fromimage полностью совпадают, но методы, которые я использовал, слишком медленные. Теперь, когда я использую байтовые массивы, я видел много несоответствий и обнаружил, что байтовые массивы изменяются случайным образом при извлечении из одних и тех же изображений (изображение загружается для сравнения и сохраняется в массиве... изображение на экране сохраняются в массиве, и сохраняются в текст, и больше ничего не делается снова и снова, что приводит к различиям.).
Открыв новый проект, я воспроизвел этот вопрос. Загрузка изображения в поле рисунка при запуске / без изменений на всем протяжении - g.copyfromscreen в растровое изображение, а затем сохраняется в байтовом массиве и экспортируется в текстовый файл, когда выполняется снова и снова. Я не могу понять, почему это происходит. Как будто я случайно обнаружил генератор случайных чисел, ха-ха. Области, которые я сравниваю, 5х72, поэтому не массивны. Прямо сейчас, чтобы упростить, я загружаю изображение в pixturebox и нажимаю кнопку, чтобы сохранить данные из этого изображения в байтовом массиве. Затем я сохраняю область изображения в.png и преобразовываю текст байтового массива из той же области в текстовый файл. Нажатие кнопки снова и снова приводит к разным байтовым массивам для вывода текста, но к файлам png, которые соответствуют 100%. Я не перемещаю изображение, я не перезагружаю изображение... Я не понимаю, почему байтовые массивы меняются.
Module Module1
Public baGB1Small((5 * 72 - 1) * 3) As Byte ' To be populated with small image.
Public baGB2Small((5 * 72 - 1) * 3) As Byte ' To be populated with small image.
Public baGB3Small((5 * 72 - 1) * 3) As Byte ' To be populated with small image.
Public baGB4Small((5 * 72 - 1) * 3) As Byte ' To be populated with small image.
End Module
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filename As String = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff")
'-- Below saves a chunk of the screen with the picturebox in it for comparison.
Dim BMPScrNew As New Bitmap(5, 420, Imaging.PixelFormat.Format24bppRgb)
Dim GrabRect As New Rectangle(478, 170, 5, 420)
Using g As Graphics = Graphics.FromImage(BMPScrNew)
g.CopyFromScreen(GrabRect.Location, New Point(0, 0), GrabRect.Size)
End Using
BMPScrNew.Save("C:\TestSaveLoc\SCR1-" & filename & ".png", Imaging.ImageFormat.Png)
'-- Below breaks the main saved image into chunks for comparison.
'-- Chunk 1:
Dim BMPSN As New Bitmap(5, 72)
Dim GRNew As New Rectangle(0, 7, 5, 72)
BMPSN = BMPScrNew.Clone(GRNew, Imaging.PixelFormat.Format24bppRgb)
BMPSN.Save("C:\TestSaveLoc\B1-" & filename & ".png", Imaging.ImageFormat.Png)
Dim BMD As Imaging.BitmapData = BMPSN.LockBits(New Rectangle(0, 0, BMPSN.Width, BMPSN.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Runtime.InteropServices.Marshal.Copy(BMD.Scan0, baGB1Small, 0, baGB1Small.Length)
BMPSN.UnlockBits(BMD)
'-- Chunk 2:
BMPSN = New Bitmap(5, 72)
GRNew = New Rectangle(0, 89, 5, 72)
BMPSN = BMPScrNew.Clone(GRNew, Imaging.PixelFormat.Format24bppRgb)
BMPSN.Save("C:\TestSaveLoc\B2-" & filename & ".png", Imaging.ImageFormat.Png)
BMD = BMPSN.LockBits(New Rectangle(0, 0, BMPSN.Width, BMPSN.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Runtime.InteropServices.Marshal.Copy(BMD.Scan0, baGB2Small, 0, baGB2Small.Length)
BMPSN.UnlockBits(BMD)
'-- Chunk 3:
BMPSN = New Bitmap(5, 72)
GRNew = New Rectangle(0, 171, 5, 72)
BMPSN = BMPScrNew.Clone(GRNew, Imaging.PixelFormat.Format24bppRgb)
BMPSN.Save("C:\TestSaveLoc\B3-" & filename & ".png", Imaging.ImageFormat.Png)
BMD = BMPSN.LockBits(New Rectangle(0, 0, BMPSN.Width, BMPSN.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Runtime.InteropServices.Marshal.Copy(BMD.Scan0, baGB3Small, 0, baGB3Small.Length)
BMPSN.UnlockBits(BMD)
'-- Chunk 4:
BMPSN = New Bitmap(5, 72)
GRNew = New Rectangle(0, 253, 5, 72)
BMPSN = BMPScrNew.Clone(GRNew, Imaging.PixelFormat.Format24bppRgb)
BMPSN.Save("C:\SWAutoer\TestSaveLoc\B4-" & filename & ".png", Imaging.ImageFormat.Png)
BMD = BMPSN.LockBits(New Rectangle(0, 0, BMPSN.Width, BMPSN.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Runtime.InteropServices.Marshal.Copy(BMD.Scan0, baGB4Small, 0, baGB4Small.Length)
BMPSN.UnlockBits(BMD)
BMPSN.Dispose()
BMPScrNew.Dispose()
'-- Writes output to a textbox on the screen (for testing only)
Output1.AppendText(Environment.NewLine & DateTime.Now)
Output1.AppendText(Environment.NewLine & "FirstCheck:" & CDWB3(filename))
filename = Nothing
End Sub
Public Function CDWB3(vfpath As String) As String
Dim BMPScrNew As New Bitmap(5, 420, Imaging.PixelFormat.Format24bppRgb)
Dim GrabRect As New Rectangle(478, 170, 5, 420)
Using g As Graphics = Graphics.FromImage(BMPScrNew)
g.CopyFromScreen(GrabRect.Location, New Point(0, 0), GrabRect.Size)
End Using
BMPScrNew.Save("C:\TestSaveLoc\SCR2-" & vfpath & ".png", Imaging.ImageFormat.Png)
Dim WasFound As Integer = 0
Dim FoundAtY As Integer = 0
Dim Checkst As Stopwatch = Stopwatch.StartNew
Dim StoppedAt As Integer = 169
For vNewY = 0 To 348 ' Goes down one pixel through the main scraped image to compare a chunk that is 5x72 to the saved arrays of smaller chunks.
Dim BMPSN As New Bitmap(5, 72)
Dim GRNew As New Rectangle(0, vNewY, 5, 72)
BMPSN = BMPScrNew.Clone(GRNew, Imaging.PixelFormat.Format24bppRgb)
BMPSN.Save("C:\TestSaveLoc\B1Loc-" & vfpath & ".png", Imaging.ImageFormat.Png)
Dim BMD As Imaging.BitmapData = BMPSN.LockBits(New Rectangle(0, 0, BMPSN.Width, BMPSN.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Dim vmBuffer((BMPSN.Width * BMPSN.Height - 1) * 3) As Byte
Marshal.Copy(BMD.Scan0, vmBuffer, 0, vmBuffer.Length)
BMPSN.UnlockBits(BMD)
If vNewY = 7 Then '-- THIS IS WHERE bagb1small should always match.
Dim writer1 As New IO.StreamWriter("C:\TestSaveLoc\MainBuff-" & vfpath & ".txt")
writer1.WriteLine(Convert.ToBase64String(vmBuffer))
writer1.Flush()
writer1.Close()
writer1.Dispose()
Dim writer2 As New IO.StreamWriter("C:\TestSaveLoc\bagb1small-" & vfpath & ".txt")
writer2.WriteLine(Convert.ToBase64String(bagb1small))
writer2.Flush()
writer2.Close()
writer2.Dispose()
End If
StoppedAt = StoppedAt + 1
Dim B1Found As Boolean = True
Dim B2Found As Boolean = True
Dim B3Found As Boolean = True
Dim B4Found As Boolean = True
For i = 0 To vmBuffer.Length - 1 Step 3
Dim BadCount As Integer = 0
If vmBuffer(i) <> baGB1Small(i) Then
B1Found = False
BadCount += 1
End If
If vmBuffer(i) <> baGB2Small(i) Then
B2Found = False
BadCount += 1
End If
If vmBuffer(i) <> baGB3Small(i) Then
B3Found = False
BadCount += 1
End If
If vmBuffer(i) <> baGB4Small(i) Then
B4Found = False
BadCount += 1
End If
If BadCount > 3 Then Exit For
Next
BMD = Nothing
vmBuffer = Nothing
If B1Found = True Then
WasFound = 1
Exit For
End If
If B2Found = True Then
WasFound = 2
Exit For
End If
If B3Found = True Then
WasFound = 3
Exit For
End If
If B4Found = True Then
WasFound = 4
Exit For
End If
BMPSN.Dispose()
Next
BMPScrNew.Dispose()
Checkst.Stop()
CDWB3 = WasFound.ToString & "," & StoppedAt
End Function
С помощью приведенного выше кода изображение загружается в поле для картинок в заданной позиции на экране в событии загрузки формы. Я ожидаю, что нажатие кнопки будет выдавать один и тот же вывод каждый раз (байтовый массив соответствует байтовому массиву последнего клика), поскольку изображение на экране вообще не меняется. Это не вариант.
Выводы моего изображения (файл сохраняется в png) совпадают каждый раз, когда я нажимаю кнопку. Вывод байтового массива в текст не совпадает. Блок 1 иногда обнаруживается, блок 2-4 - другой (блок 1 не виден на экране), а иногда его вообще нет... Это статическое изображение на экране, с которого я копирую и сравниваю - это должно не будет дела. Блок 1 должен всегда находиться в одной и той же позиции каждый раз, а массивы байтов должны быть одинаковыми каждый раз.