|
-
Sep 7th, 2011, 05:06 PM
#1
Thread Starter
New Member
Fast update of bitmap from polar coordinate data
Hi,
I am producing a marine radar display in VB.Net and struggling to get the radar data to display quickly enough.
The data is coming into my application from a callback from the radar maker's dll. Each dataset consists of an integer between 0 and 8191 denoting the angle from the datum (ship's head) that the dataset represents and a byte array with 480 elements containing data from ship's position (byte 0) to maximum range (byte 480). Each of these locations is a single byte, I want to set both red and green components of the relevant pixel in a 1000 x 1000 bitmap to this byte value. The dataset number increments round from 0 to 8191 as the radar scanner rotates.
My first approach was to use math.sin and math.cos to convert polar coordinates to cartesian coordinates, and then use setPixel to set the colour of the relevant pixels but this is far too slow.
I'm now trying to use Boop Boops 'FastPix' code:
http://www.vbforums.com/showthread.php?t=586709
Which looks like it should be much better, but I am wondering if there is a more efficient approach, for example cutting out the polar to cartesian conversion, or putting the data direct into a byte array?
I am also running the radar picture processing code on a thread separate to the UI thread to keep the UI responsive - what is the best way to display the resultant bitmap onto the UI? I am currently using a delegate and putting the bitmap into a picturebox, and I am sure there must be a better way?
Many Thanks
Chris
-
Sep 7th, 2011, 05:22 PM
#2
Re: Fast update of bitmap from polar coordinate data
The suggestion I can make is that you show us a bit of your drawing code so we can see how it looks and offer suggestions for improvements there. FastPix is a good idea as well since it moves pretty fast.
But, as another suggestion: I would handle all drawing code inside the PictureBox Paint method. You have direct access to the Graphics object which allows you to paint directly on the PictureBox. I would think you'd see a speed improvement there, and you wouldn't need to utilize FastPix or SetPixel as you would literally be drawing right to the PictureBox.
-
Sep 8th, 2011, 04:40 AM
#3
Thread Starter
New Member
Re: Fast update of bitmap from polar coordinate data
Thanks for the suggestions. Using fastpix is definitely better, but my code is still too slow:
Code:
Try
Dim echo(scale) As Byte 'Create byte array to hold echo data
Dim bm As New Bitmap(frmRadarInstance.PictureBox1.Image)
FastPix.ConvertFormat(bm) 'convert bitmap to 32bppPArgb
System.Runtime.InteropServices.Marshal.Copy(echoPtr, echo, 0, scale) 'Get the echo data
dblAngleRad = angle / 8192 * (Math.PI * 2) 'Convert the scan number to an angle in radians
dblAngleCos = Math.Cos(dblAngleRad)
dblAngleSin = Math.Sin(dblAngleRad)
Using fp As New FastPix(bm)
For radius As Integer = 0 To scale
Dim dimX As Integer = 500 + Convert.ToInt32(radius * dblAngleCos) 'Calculate cartesian coordinates with origin offset to 500,500
Dim dimY As Integer = 500 + Convert.ToInt32(radius * dblAngleSin)
fp.SetPixel(dimX, dimY, Color.FromArgb(echo(radius), echo(radius), 0))
Next
End Using
frmRadarInstance.BeginInvoke(New UpdateBitmap( _
AddressOf frmRadarInstance.updateBitmap), New Object() _
{bm})
Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try
I will try using the PictureBox paint method. I am also inclined to try a lookup table for the conversion to cartesian coordinates?
Thanks
Chris
-
Sep 8th, 2011, 08:32 AM
#4
Re: Fast update of bitmap from polar coordinate data
Hi chriscross,
It's nice to see you are using FastPix. Here's a suggestion for what I think will be a more efficient approach. Instead of plotting the points directly to the picturebox Image, plot them to a single horizontal line:
Code:
Dim radialLine As New Bitmap(scale, 1)
Using fp As New FastPix(radialLine)
Dim Pixels() As Integer = fp.PixelArray
For radius As Integer = 0 To Scale - 1
Pixels(radius) = &HFF000000 + echo(radius) * 257 * 256 'I may have to explain this!
Next
End Using
I've used my favourite FastPix version, the Integer array, because it's far away the most efficient. Still, I'm not certain that the above will actually be much faster than old-fashioned Bitmap.SetPixel, because the number of pixels involved is probably small and Lockbits/FastPix has an overhead.
Now you have a horizontal line plotted in the correct colours. Next draw it at the required angle on your target bitmap. I'll assume you want to draw the full sweep circle, not just the single line. Otherwise use g.Clear to clear the graphics.
Code:
'At form level:
Dim bm As New Bitmap(PictureBox1.Width, PictureBox1.Height)
'In your sub:
Using g As Graphics = Graphics.FromImage(bm)
Using mtx As New Drawing2d.Matrix
mtx.RotateAt(angle, New Point(500, 500)) 'no need to convert to radians
g.Transform = mtx 'rotate the Graphics
End Using
g.DrawImageUnscaled(radialLine, 500, 500)
End Using
PictureBox1.Image = bm
This is just a sketch and I haven't tried it out (yet) but I hope the idea is clear enough. You might gain some speed by doing your own maths and using a lookup table, but my impression is that GDI+ is pretty efficient with things like rotating the graphics. And I hope you'll agree this is much simpler.
BB
Last edited by boops boops; Sep 8th, 2011 at 04:55 PM.
Reason: 4 errors
-
Sep 8th, 2011, 10:38 AM
#5
Re: Fast update of bitmap from polar coordinate data
I can't see a need, here, to draw to a bitmap. Draw directly to the drawing surface in a Paint or OnPaint method.
"Ok, my response to that is pending a Google search" - Bucky Katt.
"There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
"Before you can 'think outside the box' you need to understand where the box is."
-
Sep 8th, 2011, 12:52 PM
#6
Thread Starter
New Member
Re: Fast update of bitmap from polar coordinate data
 Originally Posted by SJWhiteley
I can't see a need, here, to draw to a bitmap. Draw directly to the drawing surface in a Paint or OnPaint method.
I did try this, but it made the UI very unresponsive. I assume I need to iterate through the whole data array within the paint event in order to display the full circle of data?
Thanks
Chris
-
Sep 8th, 2011, 12:41 PM
#7
Thread Starter
New Member
Re: Fast update of bitmap from polar coordinate data
 Originally Posted by boops boops
It's nice to see you are using FastPix. Here's a suggestion for what I think will be a more efficient approach. Instead of plotting the points directly to the picturebox Image, plot them to a single horizontal line:
Hi BB,
Thank you for the suggestion, that certainly appears to be a neater and simpler implementation, however I am having a few issues with it. In the line:
Code:
Pixels(i) = echo(radius) * 257 * 256 'I may have to explain this!
Should pixels(i) be pixels(radius)?
In the second section, should it be
Code:
Using g As Graphics = Graphics.FromImage(bm)
Using mtx As New Drawing2d.Matrix
mtx.RotateAt(angle, new PointF (500, 500)) 'no need to convert to radians
g.Transform = mtx 'rotate the Graphics
End Using
g.Graphics.DrawImageUnscaled(radialLine, 500, 500)
End Using
PictureBox1.Image = bm
I am not getting any exceptions, but it is not drawing anything to the picture box? The pixels array appears to have valid data in it, but I am not sure about either radialLine or bm.
Many Thanks
Chris
-
Sep 8th, 2011, 03:31 PM
#8
Re: Fast update of bitmap from polar coordinate data
 Originally Posted by chriscross123
Hi BB,
Should pixels(i) be pixels(radius)?
Yes, of course. I was in a bit of a hurry and didn't even check the syntax!
Code:
Using g As Graphics = Graphics.FromImage(bm)
mtx.RotateAt(angle, new PointF (500, 500)) 'no need to convert to radians
You're right again. Same excuse...
EDIT: I've spotted the problem (plus another syntax correction). I forgot to set the Alpha byte ! See the corrections in red in Post #4. I think you will find it's quick enough. I just did a test with "scale" set to 500 and 360 lines drawn at 1 degree intervals. On my rather average PC it took 41 milliseconds to complete -- and that included generating the random data and updating the PictureBox.Image.
@SJWhiteley. The radar detects echoes in a single direction, but the aerial rotates to produce a usable picture. So the lines of data have to be accumulated somewhere. You could do that on a bitmap or in a collection. But to plot a point in the Paint event you have to draw a 1*1 pixel rectangle. Assuming a data line of 500 pixels and a rotary resolution of 1 degree, that would mean drawing 180,000 tiny rectangles in the Paint event. I haven't tried it but it doesn't sound very efficient to me. Anyway, what's wrong with using a bitmap?
BB
Last edited by boops boops; Sep 8th, 2011 at 04:50 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|