2 regiony posiadające granicę oznaczają, że na pewnym niewielkim obszarze powinny znajdować się 3 kolory: czerwony, czarny i zielony.
Pojawia się bardzo nieefektywne rozwiązanie: przy użyciu Color pixelColor = myBitmap.GetPixel(x, y);
można skanować obszar dla tych 3 kolorów. Oczywiście obszar musi być większy niż szerokość granicy.
Jest oczywiście dużo miejsca na optymalizacje (np. Chodzenie w odstępach co 50 pikseli i ciągłe zmniejszanie dokładności). Ponieważ czarny jest najmniej używanym kolorem, najpierw należy przeszukać czarne obszary.
Należy wyjaśnić, co mam napisane w różnych uwag w tym temacie:
namespace Phobos.Graphics
{
public class BorderDetector
{
private Color region1Color = Color.FromArgb(222, 22, 46);
private Color region2Color = Color.FromArgb(11, 189, 63);
private Color borderColor = Color.FromArgb(11, 189, 63);
private List<Point> region1Points = new List<Point>();
private List<Point> region2Points = new List<Point>();
private List<Point> borderPoints = new List<Point>();
private Bitmap b;
private const int precision = 10;
private const int distanceTreshold = 25;
public long Miliseconds1 { get; set; }
public long Miliseconds2 { get; set; }
public BorderDetector(Bitmap b)
{
if (b == null) throw new ArgumentNullException("b");
this.b = b;
}
private void ScanBitmap()
{
Color c;
for (int x = precision; x < this.b.Width; x += BorderDetector.precision)
{
for (int y = precision; y < this.b.Height; y += BorderDetector.precision)
{
c = this.b.GetPixel(x, y);
if (c == region1Color) region1Points.Add(new Point(x, y));
else if (c == region2Color) region2Points.Add(new Point(x, y));
else if (c == borderColor) borderPoints.Add(new Point(x, y));
}
}
}
/// <summary>Returns a distance of two points (inaccurate but very fast).</summary>
private int GetDistance(Point p1, Point p2)
{
return Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y);
}
/// <summary>Finds the closests 2 points among the points in the 2 sets.</summary>
private int FindClosestPoints(List<Point> r1Points, List<Point> r2Points, out Point foundR1, out Point foundR2)
{
int minDistance = Int32.MaxValue;
int distance = 0;
foundR1 = Point.Empty;
foundR2 = Point.Empty;
foreach (Point r1 in r1Points)
foreach (Point r2 in r2Points)
{
distance = this.GetDistance(r1, r2);
if (distance < minDistance)
{
foundR1 = r1;
foundR2 = r2;
minDistance = distance;
}
}
return minDistance;
}
public bool FindBorder()
{
Point r1;
Point r2;
Stopwatch watch = new Stopwatch();
watch.Start();
this.ScanBitmap();
watch.Stop();
this.Miliseconds1 = watch.ElapsedMilliseconds;
watch.Start();
int distance = this.FindClosestPoints(this.region1Points, this.region2Points, out r1, out r2);
watch.Stop();
this.Miliseconds2 = watch.ElapsedMilliseconds;
this.b.SetPixel(r1.X, r1.Y, Color.Green);
this.b.SetPixel(r2.X, r2.Y, Color.Red);
return (distance <= BorderDetector.distanceTreshold);
}
}
}
To bardzo proste. Wyszukiwanie w ten sposób zajmuje tylko około 2 + 4 ms (skanowanie i znajdowanie najbliższych punktów).
Można również przeprowadzić rekursywne wyszukiwanie: najpierw z dokładnością = 1000, następnie dokładnością = 100 i ostatecznie precyzją = 10 dla dużych obrazów. FindClosestPoints praktycznie poda szacunkowy obszar prostokątny, w którym powinna się znajdować granica (zazwyczaj są to granice).
Następnie można zastosować podejście wektorowe, które opisałem w innych komentarzach.
Jestem zdezorientowany co do tego, jakie ograniczenia dotyczą rozwiązania. W edytowanym kodzie przechowujesz kształty jako listę pikseli. Czy można je zamówić w jakikolwiek sposób? Czy możemy reprezentować kształty w dwuwymiarowej tablicy z przesunięciem? Jeśli możemy zrobić takie rzeczy, to rozwiązanie problemu staje się szybsze. – Yellowfog
Odległość między 2 punktami to "distance = Math.Sqrt (Math.Pow (Math.Abs (x1-x2), 2) + Math.Pow (Math.Abs (y1-y2), 2))". Również, gdy znajdziesz 2 punkty regionu, jest prawdopodobne, że granica jest gdzieś pomiędzy nimi (nie jest pewna). Możesz więc sprawdzić piksele za pomocą wektora, aż dotrzesz do granicy (lub nie). –
To jest algorytm O (n^2), który będzie bardzo powolny, gdy kształty będą miały znaczący rozmiar. Ponadto sqrt jest powolną operacją. Zasadniczo szybciej jest również wyrównać odległość i porównać wartości kwadratów. –