How to compare between two images using VB.net? - vb.net

I have a small bitmap image and I will do a screenshot. I need to find whether the small image is the screenshot. How I can compare two bitmap images? and then return the coordinates.
If it is MATLAB, (NOTE: I need VB.net)
What my plan is this
screenshot
for x_screen = 1: screen_width_x
for y_screen = 1: screen_col_y
for x_pic = = 1: pic_width_x
for y_pic = = 1: pic_col_y
if screenshot(x_screen, y_screen) != pic(x_pic , y_pic)
break
end
end
xx = (x_screen)
yy = (y_screen)
end
end

See Image comparison if you want something advanced Also you can look for machine learning techniques for such tasks.
Here is naive solution and not optimized one (plus it is better to do such tasks in native code):
Plus Note that it is better to check this with bmp files. otherwise it will not handle problem
Private Function FindSubImg2(img As Bitmap, subimg As Bitmap) As Point
If (img.Width - subimg.Width < 0) Or (img.Height - subimg.Height < 0) Then Return Nothing
Dim stepxLen As Integer = img.Width - subimg.Width
Dim stepyLen As Integer = img.Height - subimg.Height
Dim coor As Point
Dim match As Boolean = False
For oy As Integer = 0 To stepyLen
For ox As Integer = 0 To stepxLen
match = True
For x As Integer = 0 To subimg.Width - 1
For y As Integer = 0 To subimg.Height - 1
'actually here we do not need ToArgb method. But it will skip unneeded Color comparisions
If img.GetPixel(x + ox, y + oy).ToArgb <> subimg.GetPixel(x, y).ToArgb Then
match = False
Exit For 'we can use goto operator instead of double exit for
End If
Next
If match = False Then Exit For
Next
If match = True Then
coor.X = ox
coor.Y = oy
Return coor
End If
Next
Next
Return New Point(-1, -1)
End Function
Private Function FindSubImg(a As Bitmap, b As Bitmap) As Point
Dim subimg As Bitmap
Dim img As Bitmap
If (a.Height <= b.Height AndAlso a.Width <= b.Width) Then
subimg = a : img = b
Return FindSubImg2(img, subimg)
ElseIf (a.Height > b.Height AndAlso a.Width > b.Width) Then
subimg = b : img = a
Return FindSubImg2(img, subimg)
Else
Return New Point(-1, -1)
End If
End Function
Usage:
Dim p As Point = FindSubImg(New Bitmap("A.bmp"), New Bitmap("B.bmp"))

Try something like this:
Public Function CompareImages(ByVal img1 As Bitmap, ByVal img2 As Bitmap) As Boolean
Dim i As Integer
Dim j As Integer
For i = 0 To img1.Width - 1
For j = 0 To img2.Height - 1
If img1.GetPixel(i, j) <> img2.GetPixel(i, j) Then
Return False
End If
Next
Next
Return True
End Function
sample call:
CompareImages(New Bitmap("f:\img1.bmp"), New Bitmap("f:\img2.bmp"))

Related

TSP(Travelling Salesman) in VBNET

I'm trying to implement the Traveling salesman problem algorithm in vbnet to find the fastest path that visits all points of a bidirectional and weighted matrix and how much is the cost. Can anyone help me?
I've tried several implementations, but none worked
Tried this but not working. Can someone help me?
Public Function FillGraph(lista As List(Of Cliente)) As Integer(,)
Dim graph As Integer(,) = New Integer(lista.Count, lista.Count) {}
Dim n As Integer = lista.Count
For i = 0 To lista.Count - 1
For j = 0 To lista.Count - 1
If lista.Item(i).Id = lista.Item(j).Id Then
graph(i, j) = 0
Else
graph(i, j) = GetDistanceBetweenTwoPoints(lista.Item(i).latitude, lista.Item(i).longitude, lista.Item(j).latitude, lista.Item(j).longitude)
End If
Next
Next
Return graph
End Function
Public Function findNextPermutation(ByVal data As List(Of Integer)) As Boolean
If data.Count <= 1 Then Return False
Dim last As Integer = data.Count - 2
While last >= 0
If data(last) < data(last + 1) Then Exit While
last -= 1
End While
If last < 0 Then Return False
Dim nextGreater As Integer = data.Count - 1
For i As Integer = data.Count - 1 To last + 1
If data(i) > data(last) Then
nextGreater = i
Exit For
End If
Next
data = swap(data, nextGreater, last)
data = reverse(data, last + 1, data.Count - 1)
Return True
End Function
Public Shared Function reverse(ByVal data As List(Of Integer), ByVal left As Integer, ByVal right As Integer) As List(Of Integer)
While left < right
Dim temp As Integer = data(left)
data(Math.Min(System.Threading.Interlocked.Increment(left), left - 1)) = data(right)
data(Math.Max(System.Threading.Interlocked.Decrement(right), right + 1)) = temp
End While
Return data
End Function
Public Function swap(ByVal data As List(Of Integer), ByVal left As Integer, ByVal right As Integer) As List(Of Integer)
Dim temp As Integer = data(left)
data(left) = data(right)
data(right) = temp
Return data
End Function
Private Function travllingSalesmanProblem(ByVal graph As Integer(,), ByVal s As Integer) As Integer
Dim vertex As List(Of Integer) = New List(Of Integer)()
For i As Integer = 0 To V - 1
If i <> s Then vertex.Add(i)
Next
Dim min_path As Integer = Int32.MaxValue
Do
Dim current_pathweight As Integer = 0
Dim k As Integer = s
For i As Integer = 0 To vertex.Count - 1
current_pathweight += graph(k, vertex(i))
k = vertex(i)
Next
current_pathweight += graph(k, s)
min_path = Math.Min(min_path, current_pathweight)
Loop While findNextPermutation(vertex)
routeTxt.Text = path
Return min_path
End Function

Find folder with approximate name

I currently have a routine that searches up through the directory where a file is saved and finds a folder called "$Fabrication Data".
I am working on a new addition that will be subbed into my existing code to allow for some human error, aka slight misspelling/misformating if that folder name.
I would like to examine each folder in the 'Path' directory (but not its sub folders). Currently it returns a match:
Path\SubFolder$Fabrication Data$
instead if the path I want:
Path$ Fabrication Data
Bonus question... I am currently returning any folder that is above a .8 match, how can I return the closest match if there are multiple folders above .8 match?
Dim Path As String = "N:\Stuff\More Stuff\More More Stuff\Project Folder"
For Each d In System.IO.Directory.GetDirectories(Path)
For Each sDir In System.IO.Directory.GetDirectories(d)
Dim sdirInfo As New System.IO.DirectoryInfo(sDir)
Dim similarity As Single = GetSimilarity(sdirInfo.Name, "$Fabrication Data")
If similarity > .8 Then
sFDPath = Path & "\" & sdirInfo.Name
MsgBox(sFDPath)
Else
End If
Next
Next
End Sub
Public Function GetSimilarity(string1 As String, string2 As String) As Single
Dim dis As Single = ComputeDistance(string1, string2)
Dim maxLen As Single = string1.Length
If maxLen < string2.Length Then
maxLen = string2.Length
End If
If maxLen = 0.0F Then
Return 1.0F
Else
Return 1.0F - dis / maxLen
End If
End Function
Private Function ComputeDistance(s As String, t As String) As Integer
Dim n As Integer = s.Length
Dim m As Integer = t.Length
Dim distance As Integer(,) = New Integer(n, m) {}
' matrix
Dim cost As Integer = 0
If n = 0 Then
Return m
End If
If m = 0 Then
Return n
End If
'init1
Dim i As Integer = 0
While i <= n
distance(i, 0) = System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
Dim j As Integer = 0
While j <= m
distance(0, j) = System.Math.Min(System.Threading.Interlocked.Increment(j), j - 1)
End While
'find min distance
For i = 1 To n
For j = 1 To m
cost = (If(t.Substring(j - 1, 1) = s.Substring(i - 1, 1), 0, 1))
distance(i, j) = Math.Min(distance(i - 1, j) + 1, Math.Min(distance(i, j - 1) + 1, distance(i - 1, j - 1) + cost))
Next
Next
Return distance(n, m)
End Function ```
You can track the ratings for each folder using a simple class like this:
Public Class FolderRating
Public Rating As Single
Public Folder As String
Public Sub New(folder As String, rating As Single)
Me.Folder = folder
Me.Rating = rating
End Sub
End Class
Then, create a List:
Dim ratings As New List(Of FolderRating)
In your loop, when you find a rating that is above 0.8, add it to the list:
If similarity > 0.8 Then
Dim sFDPath As String = Path & "\" & sdirInfo.Name
ratings.Add(New FolderRating(sFDPath, similarity))
End If
Finally, sort the list:
ratings.Sort(Function(x, y) x.Rating.CompareTo(y.Rating))
You can then take the last value in the list and it will be your most similar folder, if any:
Dim bestMatch As FolderRating = ratings.LastOrDefault

Drawing an array of PictureBoxes in vb.net

I'm trying to draw an array of PictureBoxes, for testing I use the same picture for each picturebox.
But instead of showing the picture, it shows the color blue.
I would show you a picture, but I dont have 10 reputation..
Dim teren(120) As PictureBox
Dim x_locatie As Integer = 1, y_locatie As Integer = 0
For i = 0 To 10
x_locatie = 210
For j = 0 To 12
teren(i * j) = New PictureBox()
teren(i * j).Size = New Size(61, 61)
teren(i * j).Name = "x" + i.ToString + "y" + j.ToString
teren(i * j).Location = New Point(x_locatie, y_locatie)
Dim locatie As String = folder + "\harta\test.png"
teren(i * j).ImageLocation = locatie
teren(i * j).Show()
Next
y_locatie += 61
Next
I also tried another method , but same result.
Sub PictureBox1_Paint(sender1 As Object, er As PaintEventArgs)
If myImage IsNot Nothing Then
Dim r As New Rectangle(x, y, xlatime, ylungime)
er.Graphics.DrawImage(myImage, r)
End If
End Sub
Sub deseneaza(ByVal poza As String, ByRef x_perm As Integer, ByRef y_perm As Integer, ByRef lungime As Integer, ByRef latime As Integer)
myImage = Image.FromFile(poza)
x = x_perm
y = y_perm
xlatime = latime
ylungime = lungime
Refresh()
End Sub
'this part of code is in body of another function
Dim x_locatie As Integer = 1, y_locatie As Integer = 0
For i = 0 To 10
x_locatie = 210
For j = 0 To 12
Dim locatie As String = folder + "\harta\test.png"
deseneaza(locatie, x_locatie, y_locatie, 61, 61)
Next
y_locatie += 61
Next
I saw in other threads that their problem solution was something like that Dim teren() As PictureBox {teren1, teren2 , ... , teren n} But the problem in my case is that I need 120 PictureBoxes, and I think that it must be a way to do this without writing 120 pictureboxes.
Please try this...it will generate 16 picture box, size 20x20, in a row. I put it under "FormLoading" event.
Dim Shapes(16) As PictureBox
For i = 1 To 16
Shapes(i) = New PictureBox
With Shapes(i)
.BackColor = SystemColors.Control 'Color.Green
.BackgroundImage = New Bitmap(My.Resources.led_blk)
.BackgroundImageLayout = ImageLayout.Zoom
.Size = New Size(20, 20)
.Visible = True
.Location = New Point( 23 * i, 50)
End With
Me.Controls.Add(Shapes(i))
Next
I think GDI+ will be the way to go. I think you need a custom class that has a rectangle structure as a member with other properties that help you with further logic with the character intersecting with them. Paint should be done in the Paint event of the surface control you are using - PictureBox has the best rendering - IMO.
Public Class Tile
Public Property Bounds As New Rectangle
Public Property IsImpassable As Boolean
'others you think of
End Class
Dim iTop = 325
Dim pBox(48) As PictureBox
Dim pinColor = Color.SkyBlue
Dim leftStart = 50
For j = 0 To 3
For i = 0 To 11
pBox(i) = New PictureBox
'pBox(i).Image = Image.FromFile("\NoTest.bmp")
pBox(i).Visible = True
pBox(i).BackColor = pinColor
pBox(i).Top = iTop + (j * 40)
pBox(i).Width = 20
pBox(i).Height = 20
pBox(i).Left = leftStart + (35 * i)
If i > 9 Then
pBox(i).Left = leftStart + (35 * i) + 15
pBox(i).Width = 25
End If
pBox(i).BringToFront()
pBox(i).SizeMode = PictureBoxSizeMode.StretchImage
Controls.Add(pBox(i))
Next
Next

How can I list all the combinations that meet certain criteria using Excel VBA?

Which are the combinations that the sum of each digit is equal to 8 or less, from 1 to 88,888,888?
For example,
70000001 = 7+0+0+0+0+0+0+1 = 8 Should be on the list
00000021 = 0+0+0+0+0+0+2+1 = 3 Should be on the list.
20005002 = 2+0+0+0+5+0+0+2 = 9 Should not be on the list.
Sub Comb()
Dim r As Integer 'Row (to store the number)
Dim i As Integer 'Range
r = 1
For i = 0 To 88888888
If i = 8
'How can I get the sum of the digits on vba?
ActiveSheet.Cells(r, 1) = i
r = r + 1
End If
Else
End Sub
... Is this what you're looking for?
Function AddDigits(sNum As String) As Integer
Dim i As Integer
AddDigits = 0
For i = 1 To Len(sNum)
AddDigits = AddDigits + CInt(Mid(sNum, i, 1))
Next i
End Function
(Just remember to use CStr() on the number you pass into the function.
If not, can you explain what it is you want in a bit more detail.
Hope this helps
The method you suggest is pretty much brute force. On my machine, it ran 6.5min to calculate all numbers. so far a challenge I tried to find a more efficient algorithm.
This one takes about 0.5s:
Private Const cIntNumberOfDigits As Integer = 9
Private mStrNum As String
Private mRng As Range
Private Sub GetNumbers()
Dim dblStart As Double
Set mRng = Range("a1")
dblStart = Timer
mStrNum = Replace(Space(cIntNumberOfDigits), " ", "0")
subGetNumbers 8
Debug.Print (Timer - dblStart) / 10000000, (Timer - dblStart)
End Sub
Private Sub subGetNumbers(intMaxSum As Integer, Optional intStartPos As Integer = 1)
Dim i As Integer
If intStartPos = cIntNumberOfDigits Then
Mid(mStrNum, intStartPos, 1) = intMaxSum
mRng.Value = Val(mStrNum)
Set mRng = mRng.Offset(1)
Mid(mStrNum, intStartPos, 1) = 0
Exit Sub
End If
For i = 0 To intMaxSum
Mid(mStrNum, intStartPos, 1) = CStr(i)
subGetNumbers intMaxSum - i, intStartPos + 1
Next i
Mid(mStrNum, intStartPos, 1) = 0
End Sub
It can be sped up further by about factor 10 by using arrays instead of writing directly to the range and offsetting it, but that should suffice for now! :-)
As an alternative, You can use a function like this:
Function isInnerLowr8(x As Long) As Boolean
Dim strX As String, inSum As Long
isInnerLowr8 = False
strX = Replace(CStr(x), "0", "")
For i = 1 To Len(strX)
Sum = Sum + Val(Mid(strX, i, 1))
If Sum > 8 Then Exit Function
Next i
isInnerLowr8 = True
End Function
Now change If i = 8 to If isInnerLowr8(i) Then.

DirectCast not working

'ofd is open file dialog
Dim img As Bitmap
Dim iscmyk As Boolean
Dim i As String
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ofd.Filter = "Jpg Image(*.jpg)|*.jpg"
If ofd.ShowDialog = Windows.Forms.DialogResult.OK Then
img = Bitmap.FromFile(ofd.FileName)
iscmyk = ((DirectCast(img.Flags, Imaging.ImageFlags) And Imaging.ImageFlags.ColorSpaceCmyk) = Imaging.ImageFlags.ColorSpaceCmyk)
End If
img = New Bitmap(img, New Size(120, 190))
MsgBox("cmyk = " & iscmyk)
PictureBox1.Image = img
End Sub
i need to check if the image is cmyk or rgb
if its cmyk then iscmyk returns true
if its not cmyk then iscmyk returns false
in my windows 7 pc its returns false for each & every image
but in XP it returns perfect answer
why its not working in my other win7 pcs???
First, sorry for responding so late...
Second, actually I don't know
why you get different results on different OS versions.
Anyway, here is a low-level (and ugly) workaround. It's designed for JPEG images:
Public Shared Function GetJpegBpp(FileName As String) As Integer
Dim len As Integer
Dim fp As FileStream = Nothing
Dim marker(1) As Byte
Dim data(15) As Byte
Dim components As Byte = 0
GetJpegBpp = -2
Try
fp = New FileStream(FileName, FileMode.Open, FileAccess.Read)
GetJpegBpp = -1
If fp.Read(marker, 0, 2) < 2 OrElse marker(0) <> &HFF OrElse marker(1) <> &HD8 Then Exit Function
Do
If fp.Read(marker, 0, 2) < 2 OrElse marker(0) <> &HFF OrElse (marker(1) > 1 And marker(1) < &HC0) Then Exit Function
If (marker(1) < &HD0 Or marker(1) > &HD9) AndAlso marker(1) > 1 Then
If fp.Read(data, 0, 2) < 2 Then Exit Function
len = (CInt(data(0)) << 8) Or data(1)
len -= 2
If len < 0 Then Exit Function
If (marker(1) >= &HC0) And (marker(1) <= &HC3) Then
If len < 9 OrElse fp.Read(data, 0, 6) < 6 Then Exit Function
components = data(5)
If components = 0 OrElse components = 2 OrElse components > 4 OrElse (components * 3 + 6) <> len Then Exit Function
len -= 6
ElseIf marker(1) = &HDA Then
If len < (4 + 2 * components) Or (fp.ReadByte() <> components) Then Exit Function
len -= 1
End If
fp.Position += len
End If
Loop Until marker(1) = &HDA Or marker(1) = &HD9
If components = 0 OrElse marker(1) = &HD9 OrElse (fp.Length - fp.Position) < 3 Then Exit Function
Catch
Exit Function
Finally
If Not fp Is Nothing Then fp.Close()
End Try
GetJpegBpp = components * 8
End Function
You need to replace this line
iscmyk = ((DirectCast(img.Flags, Imaging.ImageFlags) And Imaging.ImageFlags.ColorSpaceCmyk) = Imaging.ImageFlags.ColorSpaceCmyk)
with this:
iscmyk = (GetJpegBpp(ofd.FileName) = 32)
Finally, I haven't tested this code with CMYK JPEG images, but I guess it should work...