Question

I have x, y coordinates of all vertices of a polygon, say (1,1) (20,10) (10,30), how do I generate a mask with all pixels inside the polygon being 1 whereas outside being 0? I know there is a function FillPolygon() in C# that looks pretty much doing the job, but it seems to me that it does not return a mask in any way.

Était-ce utile?

La solution

Bitmap b = new Bitmap(30, 30);

using (Graphics g = Graphics.FromImage(b))
{
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
    g.Clear(Color.Black);
    g.FillPolygon(Brushes.White, new Point[] {
        new Point(5,5),
        new Point(20,20),
        new Point(2,15)});
}

byte[,] mask = new byte[b.Width, b.Height];

for (int y = 0; y < b.Height; y++)
for (int x = 0; x < b.Width; x++)
{
    mask[x, y] = b.GetPixel(x, y).R > 0 ? 1 : 0;
}

This will of course be more performant if you use direct pixel access using LockBits instead of GetPixel.

Autres conseils

I know this is rather old question but in case someone comes around and looks for something similar ...

If you just want to get the mask, there are much better approaches than referencing System.Drawing and actually drawing onto image in memory ...

struct Point
{
    public readonly int X;
    public readonly int Y;

    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

bool PointInPolygon(Point[] polygon, int x, int y)
{
    if(polygon == null || polygon.Length < 3) return false;

    int counter = 0;
    double intersections;
    Point p1 = polygon[0];
    Point p2;
    for (int i = 1; i <= polygon.Length; i++)
    {
        p2 = polygon[i % polygon.Length];
        if ((y > (p1.Y < p2.Y ? p1.Y : p2.Y)) && (y <= (p1.Y > p2.Y ? p1.Y : p2.Y)) && (x <= (p1.X > p2.X ? p1.X : p2.X)) && (p1.Y != p2.Y))
        {
            intersections = (y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X;
            if (p1.X == p2.X || x <= intersections) counter++;
        }
        p1 = p2;
    }

    return counter % 2 != 0;
}

void Main()
{
    Point[] polygon = new Point[] { new Point(1,1), new Point(20,10), new Point(10,30) };
    bool[,] mask = new bool[30,30];

    for(int i=0;i<30;i++)
    {
        for(int j=0;j<30;j++)
        {
            mask[i,j] = PointInPolygon(polygon, i, j);
            Console.Write(mask[i,j]?"*":".");
        }
        Console.WriteLine();
    }
}

Which will output like this:

..............................
..............................
..............................
..***.........................
...*****......................
...********...................
....**********................
....**************............
.....****************.........
.....*******************......
......*********************...
......************************
.......*********************..
.......*******************....
........****************......
........**************........
.........***********..........
.........*********............
..........******..............
..........****................
..........**..................
..............................
..............................
..............................
..............................
..............................
..............................
..............................
..............................
..............................

For playng with masking, you can use a Region.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top