2 regioni con bordo indica che all'interno di una determinata area piccola devono essere presenti 3 colori: rosso, nero e verde.
Quindi una soluzione molto inefficace si presenta: utilizzando Color pixelColor = myBitmap.GetPixel(x, y);
è possibile eseguire la scansione di un'area per quei 3 colori. L'area deve essere più larga della larghezza del bordo, naturalmente.
C'è ovviamente molto spazio per le ottimizzazioni (come andare avanti con incrementi di 50 pixel e diminuire continuamente la precisione). Poiché il nero è il colore meno utilizzato, cercherete prima nelle aree nere.
Questo dovrebbe spiegare quello che ho scritto in vari commenti in questo argomento:
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);
}
}
}
E 'molto semplice. La ricerca in questo modo richiede circa 2 + 4 ms (scansione e ricerca dei punti più vicini).
Si potrebbe anche eseguire la ricerca in modo ricorsivo: prima con precisione = 1000, quindi precisione = 100 e infine precisione = 10 per immagini di grandi dimensioni. FindClosestPoints ti darà praticamente una zona rettangolare stimata in cui posizionare il bordo (di solito i bordi sono così).
Quindi è possibile utilizzare l'approccio vettoriale che ho descritto in altri commenti.
Sono confuso su quali siano i vincoli su una soluzione. Nel tuo codice modificato stai memorizzando le forme come un elenco di pixel. Questi possono essere ordinati in qualche modo? Possiamo rappresentare le forme in una matrice bidimensionale con un offset? Se riusciamo a fare cose del genere, la soluzione al problema diventa più veloce. – Yellowfog
La distanza tra 2 punti è 'distance = Math.Sqrt (Math.Pow (Math.Abs (x1-x2), 2) + Math.Pow (Math.Abs (y1-y2), 2))'. Anche quando trovi 2 punti regione è probabile che il bordo sia da qualche parte tra loro (non certo). Quindi puoi controllare i pixel usando il vettore fino a raggiungere un bordo (o fallire). –
Questo è un algoritmo O (n^2), che diventerà molto lento quando le forme hanno dimensioni significative. Inoltre, sqrt è un'operazione lenta. In genere è più veloce anche il quadrato della distanza e confronta i valori al quadrato. –