有迹象表明,我想起两种方法:
- 您可以创建沿车矩形的倾斜面走循环
- 或者你也可以在汽车复制到非倾斜位图和环它通常。
以下是第二种方法的示例。
它采用了LockBits
方法检测Yellow
在一个Bitmap
你的代码。
并且它通过从原始的BackgroundImage
未复制的复制它来准备该位图。
下面是结果,包括控制Panel
表示非倾斜矩形:
这里是黄色取景器功能。它采用Lockbits飞车:
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
public bool testForYellowBitmap(Bitmap bmp)
{
Size s1 = bmp.Size;
PixelFormat fmt = new PixelFormat();
fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmp1Data = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
byte bpp1 = 4;
if (fmt == PixelFormat.Format24bppRgb) bpp1 = 3;
else if (fmt == PixelFormat.Format32bppArgb) bpp1 = 4; else return false; // throw!!
int size1 = bmp1Data.Stride * bmp1Data.Height;
byte[] data1 = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
for (int y = 0; y < s1.Height; y++)
{
for (int x = 0; x < s1.Width; x++)
{
Color c1;
int index1 = y * bmp1Data.Stride + x * bpp1;
if (bpp1 == 4)
c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
else c1 = Color.FromArgb(255, data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
if (c1.R > 220 && c1.G > 220 && c1.B < 200)
{ bmp.UnlockBits(bmp1Data); return true; }
}
}
bmp.UnlockBits(bmp1Data);
return false;
}
我准备Bitmap
在MouseMove
比较。变量w, h, w2, h2
保持汽车尺寸的宽度,高度和一半。源位图位于drawPanel1.BackgroundImage
。当前角度在TrackBar tr_a.Value
。为了进一步控制,我还以白色显示旋转的汽车矩形。
private void drawPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
Size sz = drawPanel1.BackgroundImage.Size;
Rectangle rectSrc = new Rectangle(e.X - w2, e.Y - h2, w, h);
Rectangle rectTgt = new Rectangle(e.X - w, e.Y - h, 2 * w, 2 * h);
using (Graphics g = drawPanel1.CreateGraphics()) // start optional
{
g.TranslateTransform(e.X, e.Y);
g.RotateTransform(trb_a.Value);
g.TranslateTransform(-e.X, -e.Y);
drawPanel1.Refresh();
g.DrawRectangle(Pens.White, rectSrc);
}
using (Graphics g = drawPanel2.CreateGraphics())
{ // end optional
using (Bitmap bmp = new Bitmap(sz.Width, sz.Height))
using (Graphics g2 = Graphics.FromImage(bmp))
{
g2.TranslateTransform(e.X, e.Y);
g2.RotateTransform(-trb_a.Value);
g2.TranslateTransform(-e.X, -e.Y);
g2.DrawImage(drawPanel1.BackgroundImage, rectTgt, rectTgt,
GraphicsUnit.Pixel);
drawPanel2.Refresh();
g.DrawImage(bmp, rectSrc, rectSrc, GraphicsUnit.Pixel);
Text = testForYellowBitmap(bmp) ? "!!YELLOW!!" : "";
}
}
}
第一种方法将使用类似的方法LockBits
,但内部的循环沿车矩形的旋转边走,使用floats
问心无愧的循环变量来计算x坐标。这些数据应根据每次更改车辆尺寸或角度进行准备。代码有点长,但也应该快一点。
如果第二种方法的优点是通过在Graphics
对象上使用ClippingRegion
可以检查任意形状,而第一种方法可以很容易地修改为凹多边形,但不能用于弯曲形状。
下面是检查代码为第一版本的改编版:
public bool testForYellowBitmapTilt(Bitmap bmp, List<int> leftPts,
List<int> rightPts, Point topLeft)
{
Size s1 = bmp.Size;
PixelFormat fmt = new PixelFormat();
fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmp1Data = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
byte bpp1 = 4;
if (fmt == PixelFormat.Format24bppRgb) bpp1 = 3;
else if (fmt == PixelFormat.Format32bppArgb) bpp1 = 4;
else return false; // or throw!!
if (leftPts.Count != rightPts.Count) return false; // or throw!!
int size1 = bmp1Data.Stride * bmp1Data.Height;
byte[] data1 = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
for (int y = 0; y < (leftPts.Count); y++)
{
for (int x = leftPts[y] + topLeft.X; x < rightPts[y] + topLeft.X; x++)
{
Color c1;
int index1 = (y + topLeft.Y) * bmp1Data.Stride + x * bpp1;
if (index1 > 0)
{
if (bpp1 == 4)
c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
else c1 = Color.FromArgb(255, data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
if (c1.R > 220 && c1.G > 220 && c1.B < 200)
{ bmp.UnlockBits(bmp1Data); return true; }
}
}
}
bmp.UnlockBits(bmp1Data);
return false;
}
左侧和rightside坐标都存储在这里:
List<int> leftPts = new List<int>();
List<int> rightPts = new List<int>();
Point top = Point.Empty;
void getOuterPoints(List<PointF> corners, out List<int> leftPts,
out List<int> rightPts, out Point top)
{
leftPts = new List<int>();
rightPts = new List<int>();
PointF left = corners.Select(x => x).OrderBy(x => x.X).First();
PointF right = corners.Select(x => x).OrderByDescending(x => x.X).First();
top = Point.Round(corners.Select(x => x).OrderBy(x => x.Y).First());
PointF bottom = corners.Select(x => x).OrderByDescending(x => x.Y).First();
int w1 = -(int)(top.X - left.X);
int w2 = -(int)(left.X - bottom.X);
int h1 = (int)(left.Y - top.Y);
int h2 = (int)(bottom.Y - left.Y);
float d1 = 1f * w1/h1;
float d2 = 1f * w2/h2;
for (int y = 0; y < h1; y++) leftPts.Add((int)(y * d1));
for (int y = 0; y < h2; y++) leftPts.Add((int)(y * d2 + w1));
for (int y = 0; y < h2; y++) rightPts.Add((int)(y * d2));
for (int y = 0; y < h1; y++) rightPts.Add( (int)(y * d1 + w2));
}
您需要在养活以任何顺序作为List<PointF>
四个角落; top
可以是任何东西,它将在方法中设置。该coodinates是相对于汽车,所以他们不会改变当汽车移动..
速度使用LockBits! - 为了遍历矩形,你需要在外部边界(顶部和底部边界)和内部循环之间建立一个外部循环,这些内部循环通过累积浮动斜率来计算左侧和右侧的开始和结束点,直到碰到一个拐角,然后减去。在改变汽车方向时,您可以计算出2个斜坡。 – TaW
很高兴你发现有用的anwer。你可能想看看更新后的版本.. – TaW
@TaW我真的很感谢你为这个答案付出的努力!非常感谢你的帮助。 –