圆周内的像素

时间:2015-03-03 15:21:42

标签: c# visual-studio-2012 bitmap

我有一个位图,我需要画一个圆圈。现在我只绘制了圆周的像素。如何在不使用扩展的距离函数的情况下获取其他像素? 这是我的代码

public void FindMostIntenityPixelInCircle(int x0, int y0, int radius, List<Point> intensities)
{
  Bitmap bitmap = ((Bitmap)(_smartLabForm.pictureBoxGreenImage.Image));
  int x = radius;
  int y = 0;
  int radiusError = 1 - x;
  while (x >= y)
  {
    intensities.Add(new Point(x + x0, y + y0));
    intensities.Add(new Point(y + x0, x + y0));
    intensities.Add(new Point(-x + x0, y + y0));
    intensities.Add(new Point(-y + x0, x + y0));
    intensities.Add(new Point(-x + x0, -y + y0));
    intensities.Add(new Point(-y + x0, -x + y0));
    intensities.Add(new Point(x + x0, -y + y0));
    intensities.Add(new Point(y + x0, -x + y0));
    if (radiusError < 0)
    {
      radiusError += 2 * y + 1;
    }
    else
    {
      x--;
      radiusError += 2 * (y - x) + 1;
    }
  }
}

3 个答案:

答案 0 :(得分:2)

这应该是一种明显更快的方法。它只使用快速操作,没有平方根。

List<int> indices = new List<int>();

for (int x = 0; x < width; x++)
{
    for (int y = 0; y < height; y++)
    {
        double dx = x - m1;
        double dy = y - m2;
        double distanceSquared = dx * dx + dy * dy;

        if (distanceSquared <= radiusSquared)
        {
            indices.Add(x + y * width);
        }
    }
}

此代码取自this answer

答案 1 :(得分:1)

要在给定圈子中获得List<Point>分,您可以让GDI+为您完成工作:

List<Point> PointsInCircle(int diameter)
{
    List<Point> points = new List<Point>();
    Color black = Color.FromArgb(255, 0, 0, 0);
    using (Bitmap bmp = new Bitmap(diameter, diameter))
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.Clear(Color.White);
        g.FillEllipse(Brushes.Black, 0, 0, diameter, diameter);
        for (int y = 0; y < diameter; y++)
            for (int x = 0; x < diameter; x++)
                if (bmp.GetPixel(x, y) == black) points.Add(new Point(x, y));
    }
    return points;
}

要在位图内的某个圆圈上使用该列表,您只需将圆心的偏移添加到列表点即可。

为了使例程更快,您可以使用LockBits:

List<Point> PointsInCircleFast(int diameter)
{
    List<Point> points = new List<Point>();
    Color black = Color.FromArgb(255, 0, 0, 0);
    using (Bitmap bmp = new Bitmap(diameter, diameter,PixelFormat.Format32bppArgb))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.Clear(Color.White);
            g.FillEllipse(Brushes.Black, 0, 0, diameter, diameter);
        }
        Size size0 = bmp.Size;
        Rectangle rect = new Rectangle(Point.Empty, size0);
        BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);

        int size1 = bmpData.Stride * bmpData.Height;
        byte[] data = new byte[size1];
        System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1);

        for (int y = 0; y < diameter; y++)
            for (int x = 0; x < diameter; x++)
            {
                int index =  y * bmpData.Stride + x * 4;
                if (data[index] == 0 ) points.Add(new Point(x, y));
            }
    }
    return points;
}

但是对于真正的大圈子来说,创建大型列表可能是瓶颈。您可以通过仅创建四分之一的点进行优化,也可以内联处理..

内部LockBits循环内部像素的颜色如下所示:

Color c = Color.FromArgb(data[index + 3], data[index + 2], data[index + 1], data[index]);

答案 2 :(得分:1)

您可以使用边框像素拍摄现有列表,然后循环显示左侧和右侧的坐标。从那里你可以通过从左到右循环所有的x坐标来计算所有中间像素的坐标。与依赖GDI相比,这应该明显更快,占用内存更少。