Here is one way to use the drawing transforms to rotate an int[,]
. The demo code below needs a new forms application with
- timer1 (Enabled, ~100ms)
- pictureBox1 (1360x1024, hook up paint handler)
This outputs the rotated data to rotArr
and completes the operation in ~40ms (on my 4 year-old laptop). Compiling for x86 seems to be faster here. It may be just quick enough if you can manage the rest efficiently and have a reasonably new system to work with. To get better speeds than this you can override the default interpolation mode using :
g.InterpolationMode = InterpolationMode.NearestNeighbor;
this reduces the quality of the rotated image but it can be faster. A low interpolation quality may add uncertainty to your data - you'll have to test this. Another flag you can test is
g.SmoothingMode = SmoothingMode.AntiAlias;
This adds time to the calculation (not much for me, but your mileage may vary), but may improve the fidelity of the rotated image (reduce artifact errors introduced by the transform).
This has to be C# - you said you'd prefer VB but you have to set "Allow unsafe code" in your project compile options for this work and VB does not support unsafe code.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private int[,] imgArr = new int[1360, 1024]; //the 2D source from the camera
private int[,] rotArr = new int[1360, 1024]; //the rotated output
private float angle = 0;
public Form1()
{
InitializeComponent();
//Make an RGB stripe for testing
for (int i = 0; i < 1360; i++)
{
for (int j = 0; j < 1024; j++)
{
if (j < 333)
{
imgArr[i, j] = -65536; //0xFFFF0000 - red
}
else if (j < 666)
{
imgArr[i, j] = -16711936; //0xFF00FF00 - green
}
else
{
imgArr[i, j] = -16776961; //0xFF0000FF - blue
}
}
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Bitmap drawImg;
// Copy array to a bitmap - fast!
unsafe
{
fixed (int* intPtr = &imgArr[0, 0])
{
//swap width and height due to [,] row layout
drawImg = new Bitmap(1024, 1360, 4096,
PixelFormat.Format32bppArgb,
new IntPtr(intPtr));
}
}
// transform
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon(new Point[]{new Point(0,0),
new Point(drawImg.Width,0),
new Point(0,drawImg.Height)});
Matrix m = new Matrix();
m.RotateAt(angle, new PointF((float)drawImg.Width/2, (float)drawImg.Height/2));
gp.Transform(m);
PointF[] pts = gp.PathPoints;
//draw rotated image
Bitmap rotImg = new Bitmap(1024, 1360);
Graphics g = Graphics.FromImage(rotImg);
// for speed...default is Bilinear
//g.InterpolationMode = InterpolationMode.NearestNeighbor;
// may improve accuracy - default is no AntiAliasing
// slows calculation
// g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawImage(drawImg, pts);
//copy array data out
BitmapData bData = rotImg.LockBits(
new Rectangle(new Point(), rotImg.Size),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
int byteCount = bData.Stride * (rotImg.Height);
int[] flatArr = new int[byteCount / 4];
//Do this in two steps - first to a flat array, then
//block copy to the [,] array
Marshal.Copy(bData.Scan0, flatArr, 0, byteCount / 4);
Buffer.BlockCopy(flatArr, 0, rotArr, 0, byteCount);
// unlock the bitmap!!
rotImg.UnlockBits(bData);
// for show... draw the rotated image to the picturebox
// have to rotate 90deg due to [,] row layout
rotImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
e.Graphics.DrawImage(rotImg, new Point(0, 0));
}
private void timer1_Tick(object sender, EventArgs e)
{
// increment angle and paint
angle += 1.0f;
if (angle > 360.0f) { angle = 0; }
pictureBox1.Invalidate();
}
}
}