Is there a way to convert Pixel coordinates to Cartesian Coordinates in VB.net - vb.net

I have a PictureBox that is sized 1096 x 1004 with the SizeMode set to StretchImage. I am able to get the coordinates of each pixel correctly(see code below) by factoring in the StrechImage effect on the pixel coordinates.
Now what I am trying to accomplish is converting those pixel coordinates to a Cartesian Coordinate to be able to graph. In the long run, I am going to take the Cartesian Coordinates and convert them to Polar Coordinates.
I have tried to convert the pixel coordinates to cartesian by using this method.
cartesianx = scalefactor*screenx - screenwidth / 2;
cartesiany = -scalefactor*screeny + screenheight / 2;
This method is not putting the origin at (0,0) in the center of the PictureBox. It seems to be setting the origin closer to the Upper Left of the PictureBox. Is there any idea as to what I am missing?
Below is my code to convert the image to BitMap and get those coordinates and scale them correctly.
Imports System.IO
Public Class HomePanel
Dim realX As Int32
Dim realY As Int32
Private Sub HomePanel_Load(sender As Object, e As EventArgs) Handles MyBase.Load
chartImageDisplay_box.Image = Image.FromFile("C:\Users\UserB\Desktop\test.jpg")
End Sub
Private Sub chartImageDisplay_box_MouseMove(sender As Object, e As MouseEventArgs) Handles chartImageDisplay_box.MouseMove
If (e.Button = MouseButtons.Left) Then
ShowCoords(e.X, e.Y)
End If
End Sub
Private Sub chartImageDisplay_box_MouseDown(sender As Object, e As MouseEventArgs) Handles chartImageDisplay_box.MouseDown
If (e.Button = MouseButtons.Left) Then
ShowCoords(e.X, e.Y)
Dim MyBitmap As Bitmap
MyBitmap = CType(chartImageDisplay_box.Image, Bitmap)
'Me.BackColor = MyBitmap.GetPixel(realX, realY)
rgbValue.Text = "RGB Value: " & MyBitmap.GetPixel(realX, realY).ToString()
End If
'printAllPixels()
End Sub
Private Sub ShowCoords(ByVal mouseX As Int32, ByVal mouseY As Int32)
Dim realW As Int32 = chartImageDisplay_box.Image.Width
Dim realH As Int32 = chartImageDisplay_box.Image.Height
Dim currentW As Int32 = chartImageDisplay_box.ClientRectangle.Width
Dim currentH As Int32 = chartImageDisplay_box.ClientRectangle.Height
Dim zoomW As Double = (currentW / CType(realW, Double))
Dim zoomH As Double = (currentH / CType(realH, Double))
Dim zoomActual As Double = Math.Min(zoomW, zoomH)
Dim padX As Double = If(zoomActual = zoomW, 0, (currentW - (zoomActual * realW)) / 2)
Dim padY As Double = If(zoomActual = zoomH, 0, (currentH - (zoomActual * realH)) / 2)
realX = CType(((mouseX - padX) / zoomActual), Int32)
realY = CType(((mouseY - padY) / zoomActual), Int32)
lblPosXval.Text = "X: " & If(realX < 0 OrElse realX > realW, "-", realX.ToString())
lblPosYVal.Text = "Y: " & If(realY < 0 OrElse realY > realH, "-", realY.ToString())
cartX.Text = "X: " 'Where to add the cart conversion for X
cartY.Text = "Y: " 'Where to add the cart conversion for Y
End Sub
'Writes all the pixels to a text file along with RGB values for each pixel
Public Sub printAllPixels()
Using writer As StreamWriter =
New StreamWriter("C:\Users\UserB\Desktop\Pixels.txt")
Dim MyBitmap As Bitmap
MyBitmap = CType(chartImageDisplay_box.Image, Bitmap)
For y = 0 To MyBitmap.Height - 1
For x = 0 To MyBitmap.Width - 1
writer.WriteLine("XY Coord: " & x & ", " & y & "; " & MyBitmap.GetPixel(x, y).ToString)
Next
Next
End Using
End Sub
End Class

I don't know if the content of the variable contains the right value but the formula should look more like this:
cartesianx = scalefactor * (screenx - (screenwidth / 2))
cartesiany = -scalefactor* (screeny - (screenheight / 2))
Translate to 0,0 add the scale factor then flip the y.

I believe I figured my question out. I was using the wrong value for my screenx and screeny. I was using the calculated scale value but I needed to just use the mouse event X and Y values.

Related

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

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

Adding images of different sizes into a listview

I have a listview to which i add images of different sizes, eg. 123x23, 23,43, and so on..
How do i go on about this problem. I know listview has a tilesize property but that sets the general size of all the tiles
Tried with an imagelist, changing the imagelist imagesize doesnt help either... Heres the code i use to add the images to the listbox
The imglist in the code is an imagelist to which all the required images are loaded.
Private Sub frm_load_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Form1.ListViewEx1.LargeImageList = imglist
For i = 0 To imglist.Images.Count - 1
Dim x = Form1.ListViewEx1.Items.Add(New ListViewItem("", i))
x.Tag = imglist.Images.Keys(i).ToString
Next
Form1.lbl_status1.Text = "Image Count: " & Form1.ListViewEx1.Items.Count
End sub
I had the same problem.
I found this and that works for me: Click here
Public Sub LoadImageList(ByVal ImagePath As String, ByVal Key As String)
Dim picImage As Image = Nothing
Dim final_Bitmap As Bitmap = Nothing
Dim org_Image As Bitmap = Nothing
If File.Exists(ImagePath) Then
picImage = Image.FromFile(ImagePath)
'********************* Drawing the Image in proportion to the imagelist Size Here ****************
Dim proportion As Integer = 0
Dim startx As Decimal = 0
Dim startY As Decimal = 0
Dim drawwidth As Decimal = 0
Dim drawheight As Decimal = 0
org_Image = New Bitmap(picImage)
final_Bitmap = New Bitmap(ImageList1.ImageSize.Width, ImageList1.ImageSize.Height)
Dim gr As Graphics = Graphics.FromImage(final_Bitmap)
Dim factorscale As Decimal
factorscale = org_Image.Height / org_Image.Width
drawwidth = final_Bitmap.Width
drawheight = final_Bitmap.Width * factorscale
If drawheight > final_Bitmap.Height Then
proportion = 1
factorscale = org_Image.Width / org_Image.Height
drawheight = final_Bitmap.Height
drawwidth = final_Bitmap.Height * factorscale
End If
startx = 0
startY = final_Bitmap.Height - drawheight
gr.DrawImage(org_Image, startx, startY, drawwidth, drawheight)
ImageList1.Images.Add(Key, final_Bitmap)
org_Image.Dispose()
final_Bitmap.Dispose()
'************************** End Loading the Image****************
End If
End Sub

How to correctly draw to map coordinates in gdi+

I have a large scanned map that I want to use in order to display the location of a moving target
I load the map to a picture box inside a panel
the panel is set to auto-scroll. The picture box size mode is set to
auto_size
In order to calculate the transformation I let the user sample 3 points to calculate the affine transformation matrix
[x' y' 1] = [x y 1] * [a b 0
c d 0
e f 1]
I know the transformation is successful because the mouse hover event displays the correct coordinates:
Private Sub picMap_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picMap.MouseMove
If _CalibSuccess Then
Dim CurPoint(0) As PointF
CurPoint(0).X = e.X : CurPoint(0).Y = e.Y
Dim genericGraphics As Drawing.Graphics = CreateGraphics()
Dim Mat As Drawing2D.Matrix = New Drawing2D.Matrix(mdlGlobal._GeoRefParams(0), mdlGlobal._GeoRefParams(3), _
mdlGlobal._GeoRefParams(1), mdlGlobal._GeoRefParams(4), _
mdlGlobal._GeoRefParams(2), mdlGlobal._GeoRefParams(5))
genericGraphics.Transform = Mat
genericGraphics.TransformPoints(Drawing2D.CoordinateSpace.Device, Drawing2D.CoordinateSpace.World, CurPoint)
lblX.Text = CurPoint(0).X
lblY.Text = CurPoint(0).Y
Else
lblX.Text = e.X
lblY.Text = e.Y
End If
End Sub
But when I try to draw a marker on the screen I get nothing
Private Sub picMap_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picMap.Paint
Dim drawGraphics As Graphics = e.Graphics
If _CalibSuccess And _BroadCasting Then
Dim Mat As Drawing2D.Matrix = New Drawing2D.Matrix(mdlGlobal._GeoRefParams(0), mdlGlobal._GeoRefParams(3), _
mdlGlobal._GeoRefParams(1), mdlGlobal._GeoRefParams(4), _
mdlGlobal._GeoRefParams(2), mdlGlobal._GeoRefParams(5))
drawGraphics.ResetTransform()
drawGraphics.Transform = Mat
drawGraphics.FillRectangle(Brushes.Red, _ShipBase.X - (100.0F / 3600.0F), _ShipBase.Y - (100.0F / 3600.0F), (200.0F / 3600.0F), (200.0F / 3600.0F))
End If
End Sub
Could you tell me what am I doing wrong?
Your transform matrix is the inverse of what it needs to be. You can tell because your TransformPoints call is going from World to Device coordinates, but your mouse input is already in Device coordinates.

How to draw circular arcs in VB.NET

I have to generate the following figure according to user fed values. How do I go about drawing the arcs (B-C-F as in figure, circular in nature) given their start point & end point (B & F respectively) & the height from the segment BF? I can do some geometric calculations & get the radius & all, but how do I draw the arc?
I have tried using the Graphics.DrawCurve() method, but it doesn't work as expected. How can I make this method work for circular arcs? Any other workaround is also welcome.
From my comment:
If you have computed the necessary radius to generate the curve, then
simply draw the entire circle with Graphics.DrawEllipse(), but use
Graphics.SetClip() and pass a rectangle using the points B and F as a
side and computing the other two points using the height C. This will
clip the entire circle to just the part visible within that rectangle.
Then call Graphics.ResetClip() and draw the rest of the lines. Repeat
the SetClip() trick to draw the curve at the bottom as well.
Here's a proof of concept for the top curve thru B, C, and F.
I used the formulas provided by Donna Roberts at Investigative Circle Activity Using Three Points.
Here's a screenshot:
...and the code that produced it:
Public Class Form1
Private B As New Point(50, 100)
Private F As New Point(250, 100)
Private DistanceFromBF As Integer = 50
Private Sub Form1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
If B.Y = F.Y Then
Dim C As New Point(B.X + (F.X - B.X) / 2, B.Y - DistanceFromBF)
Dim ctr As Point
Dim rad As Double
CircleFromPointsOnCircumference(B, C, F, ctr, rad)
Dim rc As New Rectangle(ctr, New Size(1, 1))
rc.Inflate(rad, rad)
e.Graphics.DrawRectangle(Pens.Black, rc)
Dim clip As New Rectangle(New Point(B.X, B.Y - DistanceFromBF), New Size(F.X - B.X, DistanceFromBF))
e.Graphics.SetClip(clip)
e.Graphics.DrawEllipse(Pens.Green, rc)
e.Graphics.ResetClip()
DrawPoint(B, e.Graphics, Color.Red)
DrawPoint(C, e.Graphics, Color.Red)
DrawPoint(F, e.Graphics, Color.Red)
DrawPoint(ctr, e.Graphics, Color.Green)
End If
End Sub
Private Sub DrawPoint(ByVal pt As Point, ByVal G As Graphics, ByVal clr As Color)
Dim rc As New Rectangle(pt, New Size(1, 1))
rc.Inflate(3, 3)
Using brsh As New SolidBrush(clr)
G.FillEllipse(brsh, rc)
End Using
End Sub
Private Sub CircleFromPointsOnCircumference(ByVal ptA As Point, ByVal ptB As Point, ByVal ptC As Point, ByRef Center As Point, ByRef Radius As Double)
Dim mR As Double = CDbl(ptA.Y - ptB.Y) / CDbl(ptA.X - ptB.X)
Dim mT As Double = CDbl(ptC.Y - ptB.Y) / CDbl(ptC.X - ptB.X)
Dim X As Double = (mR * mT * (ptC.Y - ptA.Y) + mR * (ptB.X + ptC.X) - mT * (ptA.X + ptB.X)) / CDbl(2) * (mR - mT)
Dim Y As Double = CDbl(-1) / mR * (X - CDbl(ptA.X + ptB.X) / CDbl(2)) + (CDbl(ptA.Y + ptB.Y) / CDbl(2))
Center = New Point(X, Y)
Radius = Math.Sqrt(Math.Pow(ptA.X - Center.X, 2) + Math.Pow(ptA.Y - Center.Y, 2))
End Sub
End Class
Got it! Thanks #Mitch & #Idle_Mind
Using the builtin DrawArc method of Graphics
Friend Function draw_tank() As Boolean
' Create pen.
Dim blackPen As New Pen(Color.Black, 3)
' Create rectangle to bound ellipse.
Dim rect As New Rectangle(100, 100, 200, 200)
' Keeping the width & length same (200) we get a circle
' Create start and sweep angles on ellipse.
Dim startAngle As Single = 225.0F
Dim sweepAngle As Single = 90.0F
' Draw arc to screen.
Dim myarc As Graphics = Me.CreateGraphics
myarc.DrawArc(blackPen, rect, startAngle, sweepAngle)
Return True
End Function
Suggestions/Improvements welcome.
Note - This isn't the actual function from my code.

Runtime error message Index was outside the bounds of the array. for Visual Basic 2010

I am computing the ROI with a moving rectangle and extracting the ROI to compute the standard deviation, mean, area and Pixel value coordinates X and Y in a seperate form2 by clicking the mouse. At this juncture I am trying to pass a function from the main Form that loads the Image and displays the rectangle to another Form that has the displayed properties of the mean and standard deviation etc. However, I'm receiving errors in runtime in the function that contains the standard deviation. The error displayed is
Index was outside the bounds of the array.
It is displayed at the end of this portion of the code in the function StD, i.e at the end of the mean part'
SD(count) = Double.Parse(pixelcolor.R) + Double.Parse(pixelcolor.G) + Double.Parse(pixelcolor.B) - mean
what is this actually saying and how can I fix this situation. Any tips and ideas, thanks.
My code is at the bottom
enterPublic Function StD(ByVal image As Bitmap, ByVal mean As Double, ByVal meancount As Integer) As Double
Dim SD(SquareHeight * SquareWidth) As Double
Dim count As Integer = 0
For i = 0 To SquareWidth
For j = 0 To SquareHeight
Dim pixelcolor As Color = image.GetPixel(i, j)
SD(count) = Double.Parse(pixelcolor.R) + Double.Parse(pixelcolor.G) + Double.Parse(pixelcolor.B) - mean
count += 1
Next
Next
Dim SDsum As Double = 0
For i = 0 To count
SDsum = SDsum + SD(i)
Next
SDsum = SDsum / (SquareHeight * SquareWidth)
SDsum = ((SDsum) ^ (1 / 2))
Return SDsum
End Function code here
I would like to pass this using the code below
enterPrivate Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
Dim mean As Double = 0
Dim meancount As Integer = 0
Dim bmap As New Bitmap(400, 400)
bmap = PictureBox1.Image
Dim colorpixel As Color = bmap.GetPixel(e.X, e.Y)
' Dim pixels As Double = colorpixel.R + colorpixel.G + colorpixel.B
If e.Button = Windows.Forms.MouseButtons.Left AndAlso Rect.Contains(e.Location) Then
If (PictureBox1.Image Is Nothing) Or (PictureBox1.Height - (e.Y + SquareHeight) < 0) Or (PictureBox1.Width - (e.X + SquareWidth) < 0) Then
Else
Dim ROI As New Bitmap(400, 400)
Dim x As Integer = 0
Dim countx As Integer = 0
Dim county As Integer = 0
For i = e.X To (e.X + SquareWidth)
For j = (e.Y + x) To (e.Y + SquareHeight)
Dim pixelcolor As Color = bmap.GetPixel(i, j)
ROI.SetPixel(countx, county, pixelcolor)
mean = mean + pixelcolor.R + pixelcolor.G + pixelcolor.B
county += 1
meancount += 1
Next
county = 0
countx += 1
x = x + 1
Next
mean = mean / (meancount * 3)
Dim SD = mean - 75
Dim area As Integer = (SquareHeight * SquareWidth)
Dim anotherForm As Form2
anotherForm = New Form2(mean, StD(bmap, mean, meancount), area, 34)
anotherForm.Show()
End If
End If
' Catch ex As Exception
' MessageBox.Show(ex.Message())
' End Try
End Sub code here
To be displayed with this code
enter Public Sub New(ByVal mean As Double, ByVal StD As Double, ByVal Area As Integer, ByVal pixel As Double)
MyBase.New()
InitializeComponent()
TextBox1.Text = mean.ToString()
TextBox2.Text = StD.ToString()
TextBox3.Text = Area.ToString()
TextBox4.Text = pixel.ToString()
End Sub code here
The problem probably is because of these lines:
For i = 0 To SquareWidth
For j = 0 To SquareHeight
Try using this instead:
For i = 0 To SquareWidth - 1
For j = 0 To SquareHeight - 1