圆周内的像素
Pixels inside a circumference
我有一张位图,我需要在上面画一个圆圈。现在我只画了圆周的像素。如何在不使用可扩展的距离函数的情况下获得其他像素?
这是我的代码
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;
}
}
}
要在给定圆圈内获得 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]);
您可以使用带有边框像素的现有列表并循环遍历它的 y 坐标,获取圆的左侧和右侧的坐标。由此,您可以通过从左到右遍历所有 x 坐标来计算所有中间像素的坐标。与依赖 GDI 相比,这应该明显更快并且占用更少的内存。
这应该是一种明显更快的方法。它只使用快速运算,没有平方根。
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。
我有一张位图,我需要在上面画一个圆圈。现在我只画了圆周的像素。如何在不使用可扩展的距离函数的情况下获得其他像素? 这是我的代码
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;
}
}
}
要在给定圆圈内获得 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]);
您可以使用带有边框像素的现有列表并循环遍历它的 y 坐标,获取圆的左侧和右侧的坐标。由此,您可以通过从左到右遍历所有 x 坐标来计算所有中间像素的坐标。与依赖 GDI 相比,这应该明显更快并且占用更少的内存。
这应该是一种明显更快的方法。它只使用快速运算,没有平方根。
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。