Does Visual Basic process nested loops like this very slowly, or is there some other issue with my code? - vb.net

Basically, I'm trying to loop through every pixel of a picture and check it against every pixel of another image. The problem is that it seems to just do this very slowly (I can no longer interact with the opened window, and Debug.WriteLine works). I want to be sure this is the problem rather than there just being something wrong with my code.
monPic and crop are dimmed as bitmaps at the top of my code.
Private Sub BtnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click
monPic = New Bitmap("../../../../" & picNum & ".png")
crop = New Bitmap("../../../../mm.png")
For x As Integer = 0 To monPic.Width - 1
Debug.WriteLine("level 1")
For y As Integer = 0 To monPic.Height - 1
Debug.WriteLine("level 2")
If CInt(monPic.GetPixel(x, y).A) <> 0 Then
For x2 As Integer = 0 To crop.Width - 1
Debug.WriteLine("level 3")
For y2 As Integer = 0 To crop.Height - 1
Debug.WriteLine("level 4")
If monPic.GetPixel(x, y).R = crop.GetPixel(x2, y2).R And monPic.GetPixel(x, y).G = crop.GetPixel(x2, y2).G And monPic.GetPixel(x, y).B = crop.GetPixel(x2, y2).B Then matches += 1
Next y2
Next x2
End If
Next y
Next x
lblMatches.Text = CStr(matches)
End Sub

This works quickly. It requires
Imports System.Security.Cryptography
Convert the 2 bitmaps to Byte arrays then hash with Sha256. Compare the hash.
Adapted from https://www.codeproject.com/Articles/9299/Comparing-Images-using-GDI
Private Function Compare(bmp1 As Bitmap, bmp2 As Bitmap) As String
Dim result = "It's a match!"
If Not (bmp1.Size = bmp2.Size) Then
result = "It's not even the same size"
Else
Dim ic As New ImageConverter
Dim btImage1(0) As Byte
btImage1 = CType(ic.ConvertTo(bmp1, btImage1.GetType), Byte())
Dim btImage2(0) As Byte
btImage2 = CType(ic.ConvertTo(bmp2, btImage2.GetType), Byte())
Dim shaM As New SHA256Managed
Dim hash1 = shaM.ComputeHash(btImage1)
Dim hash2 = shaM.ComputeHash(btImage2)
Dim i As Integer = 0
Do While i < hash1.Length AndAlso i < hash2.Length AndAlso result = "It's a match!"
If hash1(i) <> hash2(i) Then
result = "The pixels don't match"
End If
i = (i + 1)
Loop
End If
Return result
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim png1 As New Bitmap(path1)
Dim png2 As New Bitmap(path2)
Dim message = Compare(png1, png2)
MessageBox.Show(message)
End Sub

Related

Shell Sort Algorithm

I am attempting to implement an array using the shell sort algorithm. The program will sort the array and output each element to the Listbox after the button was clicked. However, the first item output is always 0. I have included a piece of my source code and a photo of the form below;
Dim randGen As New Random()
Dim unstArray() As Integer
Dim unstArrayCopy() As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Generates random number to save in array.
Dim i As Integer = CInt(TextBox1.Text)
ReDim unstArray(i)
ReDim unstArrayCopy(i)
For x = 0 To i
unstArray(x) = randGen.Next(1, 10001)
Next
Array.Copy(unstArray, unstArrayCopy, i)
End Sub
Private Sub ShllSrtBtn_Click(sender As Object, e As EventArgs) Handles shllSrtBtn.Click
shellsort(unstArrayCopy, unstArrayCopy.GetUpperBound(0))
End Sub
Sub shellsort(ByRef shellSort() As Integer, ByVal max As Integer)
Dim stopp%, swap%, limit%, temp%, k%
Dim x As Integer = CInt((max / 2) - 1)
Do While x > 0
stopp = 0
limit = max - x
Do While stopp = 0
swap = 0
For k = 0 To limit
If shellSort(k) > shellSort(k + x) Then
temp = shellSort(k)
shellSort(k) = shellSort(k + x)
shellSort(k + x) = temp
swap = k
End If
Next k
limit = swap - x
If swap = 0 Then stopp = 1
Loop
x = CInt(x / 2)
Loop
For i = 0 To shellSort.GetUpperBound(0)
ListBox1.Items.Add(shellSort(i))
Next i
End Sub
The problem is here:
ReDim unstArray(i)
ReDim unstArrayCopy(i)
In VB, when you initialize an array, you must give it the maximum index you want to use, not the intended array length as in other languages like C#.
Because of that, your code creates an array of length i+1, but you only loop from 0 to i when filling the array. So the last element at index i will always be zero.
You should set the initializer in these lines to i-1.
VB Array Reference

What has to be done to show a marquee output with a scroll menu?

Today i continue my work, Building a menu with a vb.net console application. I found more samples to build with Windows forms. Still i try to get Basic Knowledge with the console surface.I was not able to put the following marquee text in a scroll menu, the second Code past the marquee text.
Module Module1
Dim aTimer As New System.Timers.Timer
Const marqueeText As String = "The quick brown fox... "
Dim sb As New System.Text.StringBuilder
Dim direction As Boolean = False
Sub Main()
aTimer.AutoReset = True
aTimer.Interval = 100 '1/10 second
AddHandler aTimer.Elapsed, AddressOf tick
aTimer.Start()
Console.ReadKey()
End Sub
Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
Console.Clear()
If sb.Length = 0 Then sb.Append(marqueeText)
If direction Then
sb.Insert(0, sb(sb.Length - 1))
sb.Remove(sb.Length - 1, 1)
Else
sb.Append(sb(0))
sb.Remove(0, 1)
End If
Console.CursorLeft = 10 'no visible change
Console.CursorTop = 10 'visible change
Console.Write("{0}{1}", vbCr, sb.ToString)
End Sub
End Module
The marquee text Output from above is not easy to manage with the console.cursorleft command. I have no clue how to move it to the right or to put the marquee Output in the following Code, a scroll menu, on the third line.
Module Module1
Dim MenuList As New List(Of String)
Sub PrintMenu(highlight As Integer, left As Integer, top As Integer)
Dim Nickvektor() As Integer = {1, 2, 3, 4, 5}
For I = 0 To MenuList.Count - 1
Console.CursorLeft = left
Console.CursorTop = top + I
If I = highlight Then
Console.Write("{0}", "[" & Nickvektor(I) & "]")
Else
Console.Write(MenuList(I))
End If
Next
End Sub
Sub Main()
Console.CursorVisible = False
Dim x As Integer = 0
Dim Nickvektor() As String = {" "}
For counter As Integer = 0 To 0
Do
For Each s In Nickvektor
MenuList.Add(s)
Next
x += 1
Loop Until x = 5
Next
Console.SetCursorPosition(10, 16)
Console.Write("[ ]")
Dim CurrentItem As Integer = 0
Dim CurrentKey As ConsoleKey
While CurrentKey <> ConsoleKey.Enter
PrintMenu(CurrentItem, 10, 10)
CurrentKey = Console.ReadKey(True).Key
Select Case CurrentKey
Case ConsoleKey.DownArrow
CurrentItem += 1
Case ConsoleKey.UpArrow
CurrentItem -= 1
End Select
CurrentItem = (CurrentItem + MenuList.Count) Mod MenuList.Count
End While
End Sub
End Module
The menu Frame for the above Code can be used with the up and down arrows on the Keyboard.
Maybe it is to much work but i have no clue how to continue.
The first Solution for the marquee Output is an easy change of the original code. The wrap, vbCr, was the main Problem to move the text output toward the right edge oft he screen. The following code can be used to change the cursorTop Positon and also the cursorLeft Position of the Text.
Console.CursorVisible = False
Console.CursorLeft = 30
Console.CursorTop = 10
Console.Write("{0}", sb.ToString)
The heavy part are the Menu code Lines. To answer my own question some additional help was necessary.
I posted my question on the MS developer Network written in german language. With the following link it can be viewed.
For the case the link should be broken or other cases i post the code on this site.
Module Module1
Dim MenuList As New List(Of String)
Dim aTimer As New System.Timers.Timer
Const marqueeText As String = "The quick brown fox... "
Dim sb As New System.Text.StringBuilder
Dim direction As Boolean = False
Sub PrintMenu(highlight As Integer, left As Integer, top As Integer)
Dim Nickvektor() As Integer = {1, 2, 3, 4, 5}
For I = 0 To MenuList.Count - 1
Console.CursorLeft = left
Console.CursorTop = top + I
If I = highlight Then
Console.Write("{0}", "[" & Nickvektor(I) & "]")
Else
Console.Write(MenuList(I))
End If
Next
End Sub
Sub Main()
Console.CursorVisible = False
aTimer.AutoReset = True
aTimer.Interval = 100 '1/10 second
AddHandler aTimer.Elapsed, AddressOf tick
Dim x As Integer = 0
Dim Nickvektor() As String = {" "}
For counter As Integer = 0 To 0
Do
For Each s In Nickvektor
MenuList.Add(s)
Next
x += 1
Loop Until x = 5
Next
Console.SetCursorPosition(10, 16)
Console.Write("[ ]")
Dim CurrentItem As Integer = 0
Dim CurrentKey As ConsoleKey
While CurrentKey <> ConsoleKey.Enter
If CurrentItem = 2 Then ' Zero can be used to show the marquee output prompt
aTimer.Start() ' With a change to two or four the timer can be stoped:
'Else
'If aTimer.Enabled Then
' aTimer.Stop()
'End If
End If
PrintMenu(CurrentItem, 10, 10)
CurrentKey = Console.ReadKey(True).Key
Select Case CurrentKey
Case ConsoleKey.DownArrow
CurrentItem += 1
Case ConsoleKey.UpArrow
CurrentItem -= 1
End Select
CurrentItem = (CurrentItem + MenuList.Count) Mod MenuList.Count
End While
End Sub
Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
If sb.Length = 0 Then sb.Append(marqueeText)
If direction Then
sb.Insert(0, sb(sb.Length - 1))
sb.Remove(sb.Length - 1, 1)
Else
sb.Append(sb(0))
sb.Remove(0, 1)
End If
Console.CursorVisible = False
Console.CursorLeft = 20
Console.CursorTop = 12 ' For the first Element CursorTop=10, fort he third 12
Console.Write("{0}", sb.ToString)
End Sub
End Module
To learn an other language like English i have to search a lot. Visual Basic Code is mostly written with English key words for the commands. I think it is easier to look up the maintainable changes for your self. To search is not every day funny.

Convert 1DPointArray into 2DPointArray

I started a new project which loads and saves tilesets in style of ini-datas.
The problem is now, that it loads the tiles into a 1d- list, which got copied sorted into a 1d-array.
Now I am trying to convert this sorted 1d-array into a 2d-array.
My try:
LoadedTiles.Sort(Function(p1, p2) (p1.Position.X.CompareTo(p2.Position.X)))
LoadedTiles.Sort(Function(p1, p2) (p1.Position.Y.CompareTo(p2.Position.Y)))
Dim currentArray(AmountTiles) As Tile
currentArray = LoadedTiles.ToArray
Dim lengthX, lengthY As Integer
Dim yAxis As Integer = currentArray(0).Position.Y
For Each p In currentArray
If Not p.Position.Y = yAxis Then
lengthX = (p.Position.X / p.Size.Width)
lengthY = (currentArray(currentArray.Length - 1).Position.Y / p.Size.Width)
Else
lengthX = (currentArray(currentArray.Length - 1).Position.X / p.Size.Width)
lengthY = 0
End If
Next
MapTiles = New Tile(lengthX, lengthY) {}
Dim ii As Integer
For x = 0 To lengthX
For y = 0 To lengthY
MapTiles(x, y) = currentArray(ii)
If Not ii >= currentArray.Length - 1 Then
ii += 1
End If
Next
Next
This gives a wrong output.
See picture below:
http://www.directupload.net/file/d/3690/pz8x98jr_png.htm
Is it possible to do it right?
Thanks alot!
The k-th element in a 1D array can correspond to row i=k/N and column j=k%N where N is the number of columns. The reverse is k=i*N+j
Ok guys, I got it ( =
Public Class Form1
Dim List As New List(Of Point)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
List.Add(New Point(180, 360))
List.Add(New Point(180, 180))
List.Add(New Point(180, 540))
'Convert 1d to 2d
Dim count As Point = countXYAxis(List, 180)
MsgBox(count.ToString)
Dim p(count.X - 1, List.Count - 1) As Point
MsgBox(p.Length)
Dim rofl As Integer
For i = 0 To p.GetUpperBound(0)
For j = 0 To p.GetUpperBound(1)
p(i, j) = List(rofl)
If Not rofl >= List.Count - 1 Then
rofl += 1
End If
Next
Next
For Each t In p
MsgBox(t.ToString)
Next
End Sub
Private Function countXYAxis(ByVal pt As List(Of Point), ByVal size As Integer) As Point
Dim bufferY As New List(Of Integer)
Dim cP As New Point
For Each pts In pt
If Not bufferY.Contains(pts.Y) Then
bufferY.Add(pts.Y)
End If
Next
For i = 0 To pt.Count - 1
If pt(i).Y = bufferY(0) Then
Else
cP = New Point(pt(i).X / size, bufferY.Count)
End If
Next
Return cP
End Function
End Class

Visual Basic 2008 , Search for an image on my desktop ( getpixel way/ comparing pixels)

i'm a young "programmer" and i'm trying to make a code that searches if a 400 x 500 image (a bmp file from my computer ) appears on the screen .
The code looks like this :
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'Dim-ing section'
Dim scrsize As Size = New Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
Dim scrtake = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
Dim path As String = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory, "fishbot.bmp")
Dim resource As New Bitmap(path)
Dim a As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(scrtake)
Dim b As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(resource)
a.CopyFromScreen(New Point(0, 0), New Point(0, 0), scrsize)
'as a test to see if the code is compiled until here'
Me.BackgroundImage = scrtake
'end test'
For x As Integer = 100 To scrsize.Height - 400
For y As Integer = 300 To scrsize.Width - 300
For x1 As Integer = 0 To resource.Height
For y1 As Integer = 0 To resource.Width
If scrtake.GetPixel(x, y) = resource.GetPixel(x1, y1) Then
TextBox1.Text = "found"
End If
Next
Next
Next
Next
End Sub
Also , the elements are already on the form .
For x As Integer = 100 To scrsize.Height - 400
For y As Integer = 300 To scrsize.Width - 300
For x1 As Integer = 0 To resource.Height
For y1 As Integer = 0 To resource.Width
If scrtake.GetPixel(x, y) = resource.GetPixel(x1, y1) Then
TextBox1.Text = "found"
End If
Next
Next
Next
Next
This code returns :" Parameter must be positive and < Height. Parameter name: y " and i can't find a solution . Also checked lots of sites and still nothing
And if you know a better comparation system for pixels or something to improve speed , share with me :) .
ok looked over your code
For x1 As Integer = 0 To resource.Height
should be
For x1 As Integer = 0 To resource.Height - 1
etc
a 100x100 bitmap would have the addressable area of 0-99 x 0-99 as 0 is also a valid index

How can I go about adding a ProgressBar to this code which calculates CRC32 checksum in VB.NET?

Thanks for reading - I am using the class below to calculate the CRC32 checksum of a specified file.
My question is how would I go about reporting the progress of file completion (in %) to a progressbar on a different form. I have tried (i / count) * 100 under the New() sub but I am not having any luck, or setting the progress bar with it for that matter. Can anyone help?
Thanks in advance
Steve
Public Class CRC32
Private crc32Table() As Integer
Private Const BUFFER_SIZE As Integer = 1024
Public Function GetCrc32(ByRef stream As System.IO.Stream) As Integer
Dim crc32Result As Integer
crc32Result = &HFFFFFFFF
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim count As Integer = stream.Read(buffer, 0, readSize)
Dim i As Integer
Dim iLookup As Integer
Do While (count > 0)
For i = 0 To count - 1
iLookup = (crc32Result And &HFF) Xor buffer(i)
crc32Result = ((crc32Result And &HFFFFFF00) \ &H100) And &HFFFFFF
crc32Result = crc32Result Xor crc32Table(iLookup)
Next i
count = stream.Read(buffer, 0, readSize)
Loop
GetCrc32 = Not (crc32Result)
End Function
Public Sub New()
Dim dwPolynomial As Integer = &HEDB88320
Dim i As Integer, j As Integer
ReDim crc32Table(256)
Dim dwCrc As Integer
For i = 0 To 255
Form1.CRCWorker.ReportProgress((i / 255) * 100) 'Report Progress
dwCrc = i
For j = 8 To 1 Step -1
If (dwCrc And 1) Then
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
dwCrc = dwCrc Xor dwPolynomial
Else
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
End If
Next j
crc32Table(i) = dwCrc
Next i
'file complete
End Sub
End Class
'------------- END CRC32 CLASS--------------
'-------------- START FORM1 --------------------------
Private Sub CRCWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CRCWorker.DoWork
For i = CurrentInt To dgv.Rows.Count - 1
CRCWorker.ReportProgress(0, i & "/" & Total_Files)
Current_File_Num = (i + 1)
SetControlText(lblCurrentFile, Str(Current_File_Num) & "/" & Total_Files)
result = CheckFile(SFV_Parent_Directory & "\" & dgv.Rows(i).Cells(0).Value, dgv.Rows(i).Cells(1).Value)
Select Case result
Case 0 ' missing file
UpdateRow(i, 2, "MISSING")
'dgv.Rows(i).Cells(2).Value = "MISSING"
Missing_Files = Missing_Files + 1
SetControlText(lblMissingFiles, Str(Missing_Files))
Case 1 ' crc match
UpdateRow(i, 2, "OK")
' dgv.Rows(i).Cells(2).Value = "OK"
Good_Files = Good_Files + 1
SetControlText(lblGoodFiles, Str(Good_Files))
Case 2 'crc bad
UpdateRow(i, 2, "BAD")
' dgv.Rows(i).Cells(2).Value = "BAD"
Bad_Files = Bad_Files + 1
SetControlText(lblBadFiles, Str(Bad_Files))
End Select
If CRCWorker.CancellationPending = True Then
e.Cancel = True
Exit Sub
End If
Next
End Sub
Private Sub CRCWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles CRCWorker.ProgressChanged
Dim val As Integer = e.ProgressPercentage
ProgressBar2.Maximum = 100
ProgressBar2.Value = e.ProgressPercentage
Debug.Print(val)
End Sub
Function CheckFile(ByVal tocheck_filepath As String, ByVal expected_crc As String) As Integer 'returns result of a file check 0 = missing 1 = good 2 = bad
If File.Exists(tocheck_filepath) = False Then
Return 0 'return file missing
End If
Dim f As FileStream = New FileStream(tocheck_filepath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
Dim c As New CRC32()
crc = c.GetCrc32(f)
Dim crcResult As String = "00000000"
crcResult = String.Format("{0:X8}", crc)
f.Close()
End Function
It appears your .ReportProgress() call is in the New() subroutine, which is the part that makes the lookup table for the CRC calculation. The New() subroutine is called once, before the main CRC routine. The main CRC routine is the one that takes up all the time and needs the progress bar.
Shouldn't the progress bar updating be in the GetCrc32() function? Something like this:
Public Function GetCrc32(ByRef stream As System.IO.Stream, _
Optional prbr As ProgressBar = Nothing) As UInteger
Dim crc As UInteger = Not CUInt(0)
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim left As Long = stream.Length
If Not (prbr Is Nothing) Then ' ProgressBar setup for counting down amount left.
prbr.Maximum = 100
prbr.Minimum = 0
prbr.Value = 100
End If
Dim count As Integer : Do
count = stream.Read(buffer, 0, readSize)
For i As Integer = 0 To count - 1
crc = (crc >> 8) Xor tbl((crc And 255) Xor buffer(i))
Next
If Not (prbr Is Nothing) Then ' ProgressBar updated here
left -= count
prbr.Value = CInt(left * 100 \ stream.Length)
prbr.Refresh()
End If
Loop While count > 0
Return Not crc
End Function
In Windows Forms BackgroundWorker Class is often used to run intensive tasks in another thread and update progress bar without blocking the interface.
Example of using BackgroundWorker in VB.Net
The problem is when you use use the form in your code without instantiating it Form1.CRCWorker.ReportProgress((i / 255) * 100) there is a kind of hidden "auto-instantiation" happening and new instance of Form1 is created each time.