2012-09-25 13 views
5

otrzymali listę współrzędnych X, Y i znaną szerokość & wysokość jak może NUMER z zamkniętych obszarów być ustalona (w języku C#)?Find dany zbiór punktów

Na przykład:

enter image description here

Na tym obrazie 5 zamkniętych pomieszczeniach są zdefiniowane:

  1. twarzy (1)
  2. oczu (2)
  3. nosa (1)
  4. Prawo powierzchni (1)

Lista X, Y punktów będzie dowolny piksel na czarno, w tym doustnie.

+1

[start ze wzoru na znalezienie powierzchni wielokąta] (http://en.wikipedia.org/wiki/Polygon#Area_and_centroid) – Servy

+2

think pikseli załączając swoje regiony jako wielokątów następnie zobaczyć http://stackoverflow.com/questions/2034540/calculating-area-of-irregular-polygon-in-c-sharp o tym, jak uzyskać obszar poligonu – m0s

+0

Przepraszamy, coś zgubiło się w tłumaczeniu ... Muszę wymyślić liczba regionów (5), a nie ich powierzchnia. – user873432

Odpowiedz

2

Można w ten prosty algorytm, oparty na idei powodzi wypełnić pomocnika bitmapy:

// backColor is an INT representation of color at fillPoint in the beginning. 
// result in pixels of enclosed shape. 
private int GetFillSize(Bitmap b, Point fillPoint) 
{ 
    int count = 0; 
    Point p; 
    Stack pixels = new Stack(); 
    var backColor = b.GetPixel(fillPoint.X, fillPoint.Y); 
    pixels.Push(fillPoint); 
    while (pixels.Count != 0) 
    { 
     count++; 

     p = (Point)pixels.Pop(); 
     b.SetPixel(p.X, p.Y, backColor); 

     if (b.GetPixel(p.X - 1, p.Y).ToArgb() == backColor) 
      pixels.Push(new Point(p.X - 1, p.Y)); 

     if (b.GetPixel(p.X, p.Y - 1).ToArgb() == backColor) 
      pixels.Push(new Point(p.X, p.Y - 1)); 

     if (b.GetPixel(p.X + 1, p.Y).ToArgb() == backColor) 
      pixels.Push(new Point(p.X + 1, p.Y)); 

     if (b.GetPixel(p.X, p.Y + 1).ToArgb() == backColor) 
      pixels.Push(new Point(p.X, p.Y + 1)); 
    } 

    return count; 
} 

UPDATE

Powyższy kod działa tylko ta Czterokrotnie-sprzężonych zamkniętych pomieszczeniach. Poniższy kod działa z zamkniętymi obszarami połączonymi przez oktawę.

// offset points initialization. 
Point[] Offsets = new Point[] 
{ 
    new Point(-1, -1), 
    new Point(-0, -1), 
    new Point(+1, -1), 
    new Point(+1, -0), 
    new Point(+1, +1), 
    new Point(+0, +1), 
    new Point(-1, +1), 
    new Point(-1, +0), 
}; 

... 

private int Fill(Bitmap b, Point fillPoint) 
{ 
    int count = 0; 
    Point p; 
    Stack<Point> pixels = new Stack<Point>(); 
    var backColor = b.GetPixel(fillPoint.X, fillPoint.Y).ToArgb(); 
    pixels.Push(fillPoint); 
    while (pixels.Count != 0) 
    { 
     count++; 

     p = (Point)pixels.Pop(); 
     b.SetPixel(p.X, p.Y, Color.FromArgb(backColor)); 

     foreach (var offset in Offsets) 
      if (b.GetPixel(p.X + offset.X, p.Y + offset.Y).ToArgb() == backColor) 
       pixels.Push(new Point(p.X + offset.X, p.Y + offset.Y)); 
    } 

    return count; 
} 

Poniższy rysunek jasno pokazuje, co mam na myśli. Również można dodać więcej punktów dalekich do tablicy przesunięć, aby wypełnić obszary z przerwami.

Connectedness

+0

Cool. To sprawia, że ​​mój niejasny opis jest wyraźny. Lubię. –

+0

Przyjemnie, użyteczne dla innego obszaru, nad którym pracowałem, ale jaki jest pomysł na określenie liczby zamkniętych obszarów? – user873432

+1

Możesz użyć mojego algorytmu dla każdego piksela innego niż kolor tła (czarny na przykładowym obrazie) do wykrywania regionu. Po każdym wypełnieniu regiony te nie zostaną wykryte (z powodu ich wypełnienia) i będziesz musiał zwiększyć liczbę odnalezionych regionów. Poza tym ta metoda jest odpowiednia dla połączonych regionów. Tak więc, w innych przypadkach użyj OpenCV, jak odpowiedział @Jason Hermann. –

1

Na obrazie próbki znajduje się kilka specjalnych przypadków. Musiałbyś zdecydować, jak sobie z nimi poradzić.

Generalnie zaczniesz od przekonwertowania obrazu rastrowego na serię wielokątów. Wtedy obliczenie obszaru jest dość trywialne (zob. Komentarz Servy).

Szczególnymi przypadkami byłyby strona twarzy i ust. Oba są otwarte kształty, nie zamknięte. Musisz dowiedzieć się, jak je zamknąć.

2

Miałem wielki sukces z wykorzystaniem OpenCV. Jest to biblioteka dla .NET nazywany Emgu CV

Tutaj jest kwestia pokrycia alternatyw Emgu CV: .Net (dotNet) wrappers for OpenCV?

To biblioteka zawiera funkcje identyfikacji kontury i znalezienie właściwości o nich. Możesz wyszukać cvContourArea, aby znaleźć więcej informacji.

Jeśli szukasz szybkiego rozwiązania tego konkretnego problemu i chcesz napisać własny kod, zamiast używać go ponownie, nie mam algorytmu, który mógłbym dać, który to robi. Przepraszam.

1

Myślę, że to sprowadza się do zliczania liczby (innych niż czarne) pikseli w każdym regionie. Jeśli wybierzesz jeden piksel, który nie jest czarny, dodaj go do HashSet<>, zobacz, czy piksele nad, pod, na lewo od i na prawo od wybranego piksela, również nie są czarne.

Za każdym razem, gdy znajdziesz nowe nie czarne piksele (przechodząc w górę/dół/lewo/prawo), dodaj je do swojego zestawu. Kiedy znajdziesz je wszystkie, policz je.

Obszar twojego regionu to count/(pixelWidthOfTotalDrawing * pixelHeightOfTotalDrawing) pomnożony przez obszar pełnego prostokąta (w zależności od jednostek, które chcesz).

Komentarz: Nie wydaje mi się, żeby wyglądał jak wielokąt. Właśnie dlatego myślałem o funkcji "zapełnij farbą" prostego oprogramowania do rysowania.