2 regiones que tienen borde significa que dentro de una cierta área pequeña debe haber 3 colores presentes: rojo, negro y verde.
De modo que se presenta una solución muy ineficaz: usando Color pixelColor = myBitmap.GetPixel(x, y);
puede escanear un área para esos 3 colores. El área debe ser más grande que el ancho del borde, por supuesto.
Por supuesto, hay mucho espacio para optimizaciones (como ir en pasos de 50 píxeles y disminuir la precisión continuamente). Como el negro es el color menos usado, primero debe buscar en las áreas negras.
Esto debe explicar lo que he escrito en varios comentarios en este tema:
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);
}
}
}
Es muy simple. La búsqueda de esta manera solo toma aproximadamente 2 + 4 ms (escaneando y buscando los puntos más cercanos).
También puede hacer la búsqueda recursivamente: primero con precisión = 1000, luego precisión = 100 y finalmente precisión = 10 para imágenes grandes. FindClosestPoints prácticamente le dará un área rectangular estimada donde el borde debe estar situado (generalmente los bordes son así).
Entonces podría utilizar el enfoque vectorial que he descrito en otros comentarios.
No estoy seguro de cuáles son las limitaciones de una solución. En el código editado, está almacenando las formas como una lista de píxeles. ¿Pueden ordenarse estos de alguna manera? ¿Podemos representar las formas en una matriz de 2 dimensiones con un desplazamiento? Si podemos hacer cosas así, la solución al problema se vuelve más rápida. – Yellowfog
La distancia entre 2 puntos es 'distance = Math.Sqrt (Math.Pow (Math.Abs (x1-x2), 2) + Math.Pow (Math.Abs (y1-y2), 2))'. Además, cuando encuentre 2 puntos de región, es probable que el borde esté en alguna parte entre ellos (no es seguro). Entonces puede verificar los píxeles usando el vector hasta que llegue a un borde (o falle). –
Ese es un algoritmo O (n^2), que se volverá muy lento cuando las formas tengan un tamaño significativo. Además, sqrt es una operación lenta. Por lo general, es más rápido cuadrar tu distancia y comparar los valores al cuadrado. –