Autor Beitrag
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Do 17.01.13 16:56 
Hallo,

hat jemand ein gutes Bespiel um einen Viertelkreis zuverlässig aus einem Color[,] herausfiltert.
Ich möchte damit erkennn wo sich entsprechender Viertelkreis befindet und ihn durch ein Eck ersetzen.

Praktisch soll später aus einem ( ein [ werden. Das ( als Halbkreis vorstellen.

//EDIT
Es handelt sich übrigens um eine Monochrome Bitmap, also habe ich nur schwarz und weiß, was die Farberkennung recht einfach gestaltet.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 18.01.13 00:07 
Wirklich eine Antwort habe ich nicht, aber ich habe eine Idee, wie es vielleicht funktionieren könnte.

Und zwar habe ich in einem anderen Forum ein ähnliches Thema angeschnitten. Dort ging es darum, Dublikate schnell und einfach zu entfernen und ich hab dazu eben ein kleines Mini-Konsolen-Tool geschrieben. Im Laufe der Diskussion sind wir dann dazu gelangt, ähnliche Bilder zu filtern und das ist meine Idee, die dir vielleicht helfen kann.

Denn vielleicht funktioniert es, wenn du einen Halbkreis als Bild vor gibst und dann mit Teilen des anderen Bildes vergleichst.
Die Methode, wie du ähnliche Bilder vergleichst, kann ich dir geben, allerdings Ungetestet, da es dort ein Problem gab, nämlich schlicht der Faulheit, einen notwendigen Wert, der nur experimentell bestimmt werden kann, heraus zu finden. ^^

Hier erst einmal die Methode:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
        static bool IstÄhnlich(Bitmap _img1, Bitmap _img2, int grenzwert)
        {
            // größere Kantenlängen bewirken eine genauere Rechnung, da mit jedem Pixel kleinere Bildbereiche abgetastet werden
            // Allerdings ist das sehr Performancelastig und größere Kantenlängen verlangsamen die Methode
            int width = 25;
            int hight = 25;

            Bitmap img1 = verkleinern(_img1, width, hight);
            Bitmap img2 = verkleinern(_img2, width, hight);

            int sum = 0;
            for (int y = 0; y < hight; y++)
                for (int x = 0; x < width; x++)
                    sum += (int)(Math.Pow(img1.GetPixel(x, y).R - img2.GetPixel(x, y).R, 2) +
                        Math.Pow(img1.GetPixel(x, y).G - img2.GetPixel(x, y).G, 2) +
                        Math.Pow(img1.GetPixel(x, y).B - img2.GetPixel(x, y).B, 2));

            return sum < grenzwert || grenzwert == 0;
        }

        // Diese Methode verkleinert die Bilder auf eine gleiche Größe, sodass Kanten verwischen und
        // die Bilder auch Abweichungen aufweisen können.
        static Bitmap verkleinern(Bitmap image, int width = 25int hight = 25)
        {
            Bitmap bmpOutput = new Bitmap(width, hight, PixelFormat.Format24bppRgb);
            Graphics gOutput = Graphics.FromImage(bmpOutput);
            Rectangle rectOutput = new Rectangle(00, bmpOutput.Width, bmpOutput.Height);

            ImageAttributes ia = new ImageAttributes();
            ia.SetWrapMode(WrapMode.TileFlipXY);

            gOutput.InterpolationMode = InterpolationMode.HighQualityBilinear;
            gOutput.PixelOffsetMode = PixelOffsetMode.Half;
            gOutput.CompositingMode = CompositingMode.SourceCopy;

            gOutput.DrawImage(image, rectOutput, 00, image.Width, image.Height, GraphicsUnit.Pixel, ia);
            bmpOutput.Save("output.bmp", ImageFormat.Bmp);

            return bmpOutput;
        }



Nun fehlt aber der Parameter
ausblenden C#-Quelltext
1:
grenzwert					
.
Intern wird nämlich ein Wert errechnet, der dann mit grenzwert verglichen wird.
Wenn der intern errechnete Wert 0 ist, dann sind die Bilder gleich, wenn er über grenzwert liegt, wird false zurück gegeben.

Wo dieser Wert nun liegt, damit dein Halbkreis auch richtig bestimmt wird, musst du selber aus testen. Dafür hab ich die obere Methode so umgeschrieben:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
        static int IstÄhnlich(Bitmap _img1, Bitmap _img2)
        {
            int width = 25;
            int hight = 25;

            Bitmap img1 = verkleinern(_img1, width, hight);
            Bitmap img2 = verkleinern(_img2, width, hight);

            int sum = 0;
            for (int y = 0; y < hight; y++)
                for (int x = 0; x < width; x++)
                    sum += (int)(Math.Pow(img1.GetPixel(x, y).R - img2.GetPixel(x, y).R, 2) +
                        Math.Pow(img1.GetPixel(x, y).G - img2.GetPixel(x, y).G, 2) +
                        Math.Pow(img1.GetPixel(x, y).B - img2.GetPixel(x, y).B, 2));
            return sum;
        }


Die Methode gibt den errechneten Wert nun einfach zurück. Wenn du nun mehrere Tests durchführst, dann rechnest du aus den Werten den Mittelwert aus und probierst, ob dieses Ergebnis für grenzwert reicht.

Wenn du weißt, dass der Halbkreis ganz exakt genauso ist, wie in der Vorlage, dann kannst du ja gleich testen, ob der Wert 0 ist. Oder du errechnest von den Bildern dir den Hash-Wert und vergleichst den, was sehr viel schneller gehen würde und Performance ist bei dem, was du vor hast, Gold wert.
Das funktioniert aber nur, wenn die Bitmaps wirklich exakt, also Pixel für Pixel gleich sind und selbst dann bin ich mir nicht sicher. Beim Vergleich von Bildern aus Dateien funktioniert es ganz gut und schnell.



Wenn du nun so weit bist und ein Halbkreis erfolgreich erkannt wird, dann musst du den Halbkreis finden und da fällt mir, ohne tief greifende Kenntnisse, keine andere Möglichkeit ein, als jede Position abzusuchen. Du nimmst also deine Vorlage und vergleichst es mit jeder Position in dem großen Bild, angefangen von der linken oberen Ecke. Dann die Auswahl ein Pixel weiter verschieben und wieder vergleichen. Das Gleiche in der nächsten Zeile und das so lange, bis du eine Übereinstimmung findest.

Ich hatte noch etwas über eine Methode gelesen, bei der man ein Bild nach einem bestimmten Raster durchsucht, aber da weiß ich nicht, wie das geht und habe auch noch nichts, was dir da helfen kann. Allerdings denke ich, dass es sicher die eine oder andere Bibliothek gibt, die entsprechende Funktionen und Klassen zur Verfügung stellt.



Gruß
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mi 23.01.13 14:59 
Also ich habe jetzt mal einige Zeit rumprobiert. Ich werde jetzt keine Viertelkreise, sondern Vollkreise erkennen.
Die Kreise sind so aufgebaut dass sie immer 2 Pixel dick sind. Der äußere Kreis ist dabei weiß und der Innere schwarz.

Ich erstelle meine Kreise aus 2 Methoden:
1. Über Bitmap und die Graphics-Klasse, lasse ich dann ein Kreis reinzeichnen (der ist nicht symmetrisch)
2. Über eine Methode die den Bresenham-Algorithmus benutzt (der ist symmetrisch).

jetzt habe ich bei keiner der Methoden einen Durchschlagenden Erfolg. Ich brauche bei beiden Varianten eine Toleranz von 25% (-> 75% aller verglichenen Pixel müssen überein stimmen) um Kreise ab Durchmesser = 6 zu erkennen. Bei einem kleineren Kreis brauche ich eine größere Toleranz, was wiederum zu Fehlern führt und Kreise erkannt werden, wo gar keine sind.

Nun zu meiner Frage. Was für Algorithmen gibt es um einen Kreis zu zeichnen?
Dann könnte ich nämlich vor dem Scannen des Bildes einfach den entsprechenden Algo auswählen.

Hier noch der Code für Methode 1: Bitmap und Graphics (Ist noch in Testphase, daher sehr unsauber. Die Klasse RoBitmap hab ich iwo aus dem Netz, die arbeitet nicht mit GetPixel() und SetPixel())
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
    private void RemoveCurves(Bitmap bitmap, int minRadus, int maxRadius, float scale)
    {
      bool replaceFast = true;
      List<Point> drillPos = new List<Point>();

      Stopwatch watch = new Stopwatch();
      watch.Start();

      RoBitmap pic = new RoBitmap(bitmap);        // RoBitmap ist eine schnellere Instanz als Bitmap
      pic.Image = new Bitmap(pic.GetFormat1BppIndexed(0.2f));

      Graphics picGraphics = Graphics.FromImage(pic.Image);
      

      boxImage.Image = pic.Image;

      bool[,] mapPic = new bool[pic.Width,pic.Height];  // bool[] anstelle der Bitmap benutzen -> erhöht Tempo
      for (int x = 0; x < pic.Width; x++)
        for (int y = 0; y < pic.Height; y++)
          mapPic[x, y] = pic.GetPixel(x, y).ToArgb() == ARGB_WHITE;


      RoBitmap tmp = new RoBitmap(new Bitmap(pic.Width, pic.Height));
      for (int x = 0; x < pic.Width; x++)
        for (int y = 0; y < pic.Height; y++)
          tmp.SetPixel(x, y, mapPic[x, y] ? Color.White : Color.Black);

      dbView.boxBuf1.Image = tmp.Image;

      barProgress.Maximum = (maxRadius - minRadus + 1) * pic.Height - (maxRadius - (maxRadius - minRadus + 1));
      barProgress.Value = 0;

      for (int r = maxRadius; r >= minRadus; r--)    // Redius-Spektrum ablaufen
      {
        labRadius.Text = string.Format("r = {0}px", r);

        int d = 2 * r;
        int size = (int)Math.Round(d * scale);
        int offset = (int)Math.Round((size - d) / 2d);
        Bitmap buffer = new Bitmap(size, size);    // Puffer erzeugen


        Graphics g = Graphics.FromImage(buffer);  // Graphics initialisieren

        g.Clear(Color.Green);            // Puffer färben
        // Scan-Bereich zeichnen
        g.FillRectangle(new SolidBrush(Color.White), offset - 1, offset - 1, (size - 2 * offset) + 2, (size - 2 * offset) + 2);
        g.FillEllipse(new SolidBrush(Color.Black), offset, offset, size - 2 * offset, size - 2 * offset);
        // Ignorier-Bereich zeichnen
        g.FillEllipse(new SolidBrush(Color.Red), offset + 2, offset + 2, (size - 2 * offset) - 4, (size - 2 * offset) - 4);    

        
        RoBitmap circle = new RoBitmap(buffer);

        dbView.boxBuf5.Image = circle.Image;

        Dictionary<Point, bool> comparor = new Dictionary<Point, bool>();  // Punkte die zu vergleichen sind
        List<Point> replacer = new List<Point>();  // Punkte, die bei Übereinstimmung zu ersetztn sind
        Rectangle replacerFast = new Rectangle(00, circle.Width, circle.Height);


        for (int x1 = 0; x1 < circle.Width; x1++)
        {
          for (int y1 = 0; y1 < circle.Height; y1++)
          {
            int c = circle.GetPixel(x1, y1).ToArgb();

            if (c == ARGB_WHITE || c == ARGB_GREEN) replacer.Add(new Point(x1 - offset, y1 - offset));

            if ((c == ARGB_WHITE || c == ARGB_BLACK) && x1 - offset >= 0 && y1 - offset >= 0)
              comparor.Add(new Point(x1 - offset, y1 - offset), c == ARGB_WHITE);
          }
        }

        tmp = new RoBitmap(new Bitmap(circle.Width, circle.Height));
        foreach (var pair in comparor) tmp.SetPixel(pair.Key.X, pair.Key.Y, pair.Value ? Color.White : Color.Black);
        dbView.boxBuf4.Image = tmp.Image;

        for (int y = 0; y < pic.Height - d; y++) // Y im Bild
        {
          barProgress.Value++;

          for (int x = 0; x < pic.Width - d; x++) // X im Bild
          {
            int compareMax = comparor.Count;    // Max. mögliche Übereinstimmungen
            int compareSum = 0;            // Übereinstimmungen
            int tolerance = (int)(2.5 * r);      // Vergleichstoleranz


            foreach (var pair in comparor)
              if (mapPic[pair.Key.X + x, pair.Key.Y + y] == pair.Value) // Auf Übereinstimmung prüfen
                compareSum++;

            if (compareMax > compareSum + tolerance) // Wenn außerhalb der Toleranz, nächsten Durchgang starten
              continue;

            // Bohrung wurde erkannt.
            // Nun wird sie ausewertet...

            labDetects.Text = (int.Parse(labDetects.Text) + 1).ToString();

            //bool escape = false;

            //for (int x1 = -1; x1 < circle.Width + 1; x1++)    // Suchen ob Verbidungen zu anderen Flächen bestehen
            //{ 
            //    if (!mapPic[x1 + offset + x, y+ -1]) continue;    // Wenn Punkt schwarz = keine Verbindung
              
            //    for (int y1 = 0; y1 < circle.Height / 2; y1++)  // Nachsehen ob Verbindung schon vorher bestand
            //    {
            //        if (!mapPic[x1 + offset + x, y1 + offset + y]) 
            //        {
            //            escape = true;
            //            break;
            //        }
            //    }

            //    if (escape)
            //    {
            //        break;
            //    }
            //}

            //if (escape)
            //{
            //    escapeCount++;
            //    dbView.lab1.Text = string.Format("esc {0}", escapeCount);
            //    continue;
            //}

            //for (int y1 = -1; y1 < circle.Width + 1; y1++)    // Suchen ob Verbidungen zu anderen Flächen bestehen
            //{
            //    if (!mapPic[x+ -1, y1 + offset + y]) continue;  // Wenn Punkt schwarz = keine Verbindung
              
            //    for (int x1 = 0; x1 < circle.Width / 2; x1++)  // Nachsehen ob Verbindung schon vorher bestand
            //    {
            //        if (!mapPic[x1 + offset + x, y1 + offset + y]) 
            //        {
            //            escape = true;
            //            break;
            //        }
            //    }

            //    if (escape) break;
            //}

            //if (escape)
            //{
            //    escapeCount++;
            //    dbView.lab1.Text = string.Format("esc {0}", escapeCount);
            //    continue;
            //}

            if (!replaceFast)
            {
              foreach (Point p in replacer)  // Entsprechende Punkte ersetzten
              {
                if (p.X + x >= pic.Width || p.Y + y >= pic.Height) continue;
                pic.SetPixel(p.X + x, p.Y + y, Color.White);        // Teilkreis ersetzten durch Rechteck
              }
            }
            else
            {
              picGraphics.FillRectangle(new SolidBrush(Color.White), x - offset, y - offset,
                replacerFast.Width, replacerFast.Height);
              drillPos.Add(new Point(x + replacerFast.Width, y + replacerFast.Height));
            }

            boxImage.Image = pic.Image;
          }
        }

      }

      RoBitmap drillPic = new RoBitmap(new Bitmap(pic.Width, pic.Height));
      drillPic.Image.SetResolution(pic.Image.VerticalResolution, pic.Image.HorizontalResolution);
      drillPic.Image = drillPic.GetFormat1BppIndexed();

      foreach (Point p in drillPos) drillPic.SetPixel(p.X, p.Y, Color.White);

      dbView.boxBuf1.Image = drillPic.Image;

      watch.Stop();
      labTime.Text = watch.ElapsedMilliseconds.ToString();
      boxImage.Image = pic.Image;
      butStart.Enabled = true;
    }


und hier für Methode 2: Bresenham
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
  private void RemoveCurves_Method3(Bitmap bitmap, int minRadus, int maxRadius, float scale, float tolerance)
    {       
      bool replaceFast = true;
      List<Point> drillPos = new List<Point>();

      Stopwatch watch = new Stopwatch();
      watch.Start();

      RoBitmap pic = new RoBitmap(bitmap);        // RoBitmap ist eine schnellere Instanz als Bitmap
      pic.Image = new Bitmap(pic.GetFormat1BppIndexed(0.2f));

      Graphics picGraphics = Graphics.FromImage(pic.Image);
      

      boxImage.Image = pic.Image;

      bool[,] mapPic = new bool[pic.Width,pic.Height];  // bool[] anstelle der Bitmap benutzen -> erhöht Tempo
      for (int x = 0; x < pic.Width; x++)
        for (int y = 0; y < pic.Height; y++)
          mapPic[x, y] = pic.GetPixel(x, y).ToArgb() == ARGB_WHITE;  // schwaz = falst, weiß = true


      RoBitmap tmp = new RoBitmap(new Bitmap(pic.Width, pic.Height));
      for (int x = 0; x < pic.Width; x++)
        for (int y = 0; y < pic.Height; y++)
          tmp.SetPixel(x, y, mapPic[x, y] ? Color.White : Color.Black);

      dbView.boxBuf1.Image = tmp.Image;

      barProgress.Maximum = (maxRadius - minRadus + 1) * pic.Height - (maxRadius - (maxRadius - minRadus + 1));
      barProgress.Value = 0;

      for (int r = maxRadius; r >= minRadus; r--)    // Redius-Spektrum ablaufen
      {
        labRadius.Text = string.Format("r = {0}px", r);

        int d = 2 * r;
        int size = (int)Math.Round(d * scale);
      //  int offset = (int)Math.Round((size - d) / 2d);

        IEnumerable<Point> comparorWhite = GetCircle(new Point(00), r + 1);
        IEnumerable<Point> comparorBlack = GetCircle(new Point(00), r);
        IEnumerable<Point> replacer = GetRectangleWithCircle(size, size, new Point(size / 2), comparorBlack);

        RoBitmap bmp = new RoBitmap(new Bitmap(d + 4, d + 4));
        foreach (Point p in comparorWhite) bmp.SetPixel(p.X + r + 1, p.Y + r + 1, Color.White);
        foreach (Point p in comparorBlack) bmp.SetPixel(p.X + r + 1, p.Y + r + 1, Color.Black);

        dbView.boxBuf1.Image = bmp.Image;

        bmp = new RoBitmap(new Bitmap(size, size));
        foreach (Point p in replacer) bmp.SetPixel(p.X, p.Y, Color.Black);

        dbView.boxBuf5.Image = bmp.Image;

        int maxFails = (int)(tolerance * (comparorWhite.Count() + comparorBlack.Count()));  // Vergleichstoleranz

        for (int y = r + 1; y < pic.Height - r - 1; y++) // Y im Bild
        {
          barProgress.Value++;

          for (int x = r + 1; x < pic.Width - r - 1; x++) // X im Bild
          {
            int fails = 0;            // Übereinstimmungen

            foreach (Point p in comparorBlack)
            {
              if (mapPic[x + p.X, y + p.Y]) fails++;
              if (fails > maxFails) break;
            }

            foreach (Point p in comparorWhite)
            {
              if (fails > maxFails) break;
              if (!mapPic[x + p.X, y + p.Y]) fails++;
            }

            if (fails > maxFails) continue;    // Bei zuhoher Fehlerzahl nächsten Punkt abfragen

            labDetects.Text = (int.Parse(labDetects.Text) + 1).ToString();

            if (!replaceFast)
            {
              foreach (Point p in replacer)  // Entsprechende Punkte ersetzten
                pic.SetPixel(p.X + x - size / 2, p.Y + y - size / 2, Color.White);
            }
            else
            {
              picGraphics.FillRectangle(new SolidBrush(Color.White), x - size/2, y - size/2, size, size);
              drillPos.Add(new Point(x + size, y + size));
            }

          }
        }
      }

      watch.Stop();
      labTime.Text = watch.ElapsedMilliseconds.ToString();
      boxImage.Image = pic.Image;
      butStart.Enabled = true;

    }


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
public static IEnumerable<Point> GetCircle(Point midpoint, int radius)
    {
      Point returnPoint = new Point();
      int f = 1 - radius;
      int ddF_x = 1;
      int ddF_y = -2 * radius;
      int x = 0;
      int y = radius;

      returnPoint.X = midpoint.X;
      returnPoint.Y = midpoint.Y + radius;
      yield return returnPoint;
      returnPoint.Y = midpoint.Y - radius;
      yield return returnPoint;
      returnPoint.X = midpoint.X + radius;
      returnPoint.Y = midpoint.Y;
      yield return returnPoint;
      returnPoint.X = midpoint.X - radius;
      yield return returnPoint;

      while (x < y)
      {
        if (f >= 0)
        {
          y--;
          ddF_y += 2;
          f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;
        returnPoint.X = midpoint.X + x;
        returnPoint.Y = midpoint.Y + y;
        yield return returnPoint;
        returnPoint.X = midpoint.X - x;
        returnPoint.Y = midpoint.Y + y;
        yield return returnPoint;
        returnPoint.X = midpoint.X + x;
        returnPoint.Y = midpoint.Y - y;
        yield return returnPoint;
        returnPoint.X = midpoint.X - x;
        returnPoint.Y = midpoint.Y - y;
        yield return returnPoint;
        returnPoint.X = midpoint.X + y;
        returnPoint.Y = midpoint.Y + x;
        yield return returnPoint;
        returnPoint.X = midpoint.X - y;
        returnPoint.Y = midpoint.Y + x;
        yield return returnPoint;
        returnPoint.X = midpoint.X + y;
        returnPoint.Y = midpoint.Y - x;
        yield return returnPoint;
        returnPoint.X = midpoint.X - y;
        returnPoint.Y = midpoint.Y - x;
        yield return returnPoint;
      }
    }

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mi 23.01.13 19:00 
Als letztes wüsste ich nur noch das gute alte Pixel suchen. Also du durchläufst alle Pixel und prüfst dann, ob dieser Pixel Teil des Kreises sein kann, also ob entsprechende Pixel an entsprechenden Personen darum herum liegen.

Aber mehr weiß ich jetzt auch nicht :/
Ich persönlich hab das auch noch nie gebraucht, beruht also alles auf der reinen Theorie und was ich mal so irgendwann gelesen habe.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 23.01.13 21:05 
Ich weiß nicht, ob es bessere Ergebnisse liefert als dein eigener Algorithmus, aber ein allgemeines Verfahren zum Erkennen von Kreisen ist die Hough-Transformation.

_________________
>λ=
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Do 24.01.13 11:40 
Hmmm. Also bei der Hough Transformation ist dass komisch :/. Ich habe mir Testweise mal das AForge.NET Framework runtergeladen und ein Sample mit der Hough Transformation gestartet. Als ich mein Bild ausgewählt hatte, hatte ich nach Beendigung - etwa 10min - 281422 gefundene Kreise. Bei meiner Methode - die auch schneller ist - sind es ca. 100 (je nach Toleranz).
Im Anhang findet sich das Bild, dass ich scanne.
Einloggen, um Attachments anzusehen!
_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Do 24.01.13 13:56 
Dann machst du irgendwas falsch :wink:

Ic habe das gerade mal in Matlab gebaut, hier mein Skript:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
bild = imread('board.bmp');
bild = imresize(bild, 2); % Bikubisch vergrößern
kantenbild = edge(bild, 'canny'); % Kantenfilter
[centers_1,radii_1] = imfindcircles(kantenbild,[10 25]);
[centers_2,radii_2] = imfindcircles(kantenbild,[25 60]);

centers = [centers_1; centers_2]; % Arrays zusammenfügen
radii = [radii_1; radii_2]; % Arrays zusammenfügen

count = size(radii, 1);

imshow(bild);
viscircles(centers, radii,'EdgeColor','b');


Das Ergebnis anbei. Du brauchst auf jeden Fall einen Kantendetektor und wenn du ein höher aufgelöstes Bild hast, wäre das auch ganz gut. Was die Funktionen machen kannst du in der matlab Hilfe nachschlagen: www.mathworks.de/de/help/matlab/index.html

Ich habe auch bei den viertelkreisen schon an Hough gedacht, aber da hat das nicht funktioniert. Für gnaze Kreise ist der Ansatz aber schon sehr gut.

Das Skript findet genau 116 Kreise und liefert direkt alle Radien und Mittelpunkte.
Einloggen, um Attachments anzusehen!
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Do 24.01.13 16:21 
Hmm. Also ich kapier das nicht so ganz mit dem Hough Algorithmus. Kann mir dass jemand erklären? Am Besten noch mit einem Beispiel.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Do 24.01.13 17:19 
user profile iconC# hat folgendes geschrieben Zum zitierten Posting springen:
Hmm. Also ich kapier das nicht so ganz mit dem Hough Algorithmus. Kann mir dass jemand erklären? Am Besten noch mit einem Beispiel.

Hmmm ... ich nehme mal an dass die die Wikipedia nicht so weitergeholfen hat, daher versuche ich das jetzt einfach zu erklären :)

1. Für eine Hough-Transformation musst du wissen was du suchst und wieviele Parameter das hat. Ein Kreis hat bspw. 3 Parameter: Mittelpunktskoordinaten und den Radius.
2. Für jeden Pixel im Bild der zu einem Objekt gehören könnte, malst du jetzt in einem "Zielbild" (das Teil hat so viele Dimansionen wie das Objekt Parameter) alle Stellen etwas heller, deren Parameter den aktuellen Pixel erklären würden.
3. In dem resultierenden Bild bestimme man die Maxima.

Nehmen wir an, wie suchen einen Kreis mit Radius 50 und vertikal in Bildmitte. (Damit ist es besonders einfach, wir haben nur noch einen Parameter!)
eins
Jetzt gehen wir jeden Pixel durch und entdecken an einer Stelle einen schwarzen Pixel: Zum Beispiel den in dem roten Kreis.
An dieser Stelle könnten es aber zwei Kreise sein die hier einen schwarzen Pixel bewirken:
2
Wenn wir jetzt noch eine Achse und eine Skala hinzufügen können wir die beiden möglichen Mittelpunkte quantifizieren und eine Art Strichliste führen:
drei

Die 45 wird auf dieser Strichliste ganz weit vorne liegen während alle anderen Zahlen verschwindend wenige Striche bekommen. Dann können wir sagen: Der Kreis war wohl bei der Koordinate 45.

Für dein Beispiel bedeutet das: Es wird quasi ein 3D-Quader im Parameterraum aufgespannt und bei jedem Pixel wird eine Kegelmantelfläche an Werten inkrementiert.
Also wenn an Position (100, 250) ein Pixel gefunden wurde, dann könnte das ein Kreis mit Durchmesser 10 sein, dessen Mittelpunkt irgendwo auf einem Kreis mit Radius 5 liegt. Oder ein Kreis mit Durchmesser 12 dessen Mittelpunkt 6 Pixel entfernt liegt. Oder Durchmesser 14, dann aber 7 Pixel entfernt.

Ist das einigermaßen klar geworden?
Einloggen, um Attachments anzusehen!
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 25.01.13 08:46 
Danke für die Erklärung. Ich glaube ich bin etwas schwer von Begriff :D
Könntest du das mit der Strichliste etwas genauer erklären? Also wenn sich jetzt wie in Bild 2 die Kreise schneiden, woher weis ich, dass das andere Objekt auch ein Kreis ist und nicht nur eine Linie? Und was hat es mit der Kegelmantelfläche auf sich?
Also ich habe meinen Quader, der - so wie ich es verstanden habe - x, y und r representiert. Und da drin befindet sich jetzt ein Kegel der meine neuen Parameter gibt.
Ist das soweit richtig?

/// EDIT
Habe noch einen Crosspost in Tutorials.de eröffnet.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Fr 25.01.13 15:58 
user profile iconC# hat folgendes geschrieben Zum zitierten Posting springen:
Danke für die Erklärung. Ich glaube ich bin etwas schwer von Begriff :D
Könntest du das mit der Strichliste etwas genauer erklären? Also wenn sich jetzt wie in Bild 2 die Kreise schneiden, woher weis ich, dass das andere Objekt auch ein Kreis ist und nicht nur eine Linie?

Das weißt du nicht. Aber durch die Aufaddierung bekommt der Kreismittelpunkt dennoch einen viel höheren Wert.

Für jeden schwarzen Pixel wird immer die Annahme getroffen dass dieser durch einen Kreis entstanden ist. Falls da Linien in dem Bild sein sollten, dann erzeugen diese nur ein geringes Grundrauschen.

Nehmen wir einmal den obersten Pixel des Kreises: Der kann wirklich nur durch den Kreis an Position 45 erklärt werden. Macht einen Strich bei 45. der oben erklärte Pixel könnte durch zwei Kreise entstanden sein. Macht einen Strich für 45 und einen für 10 und einen für 45. In der gleichen Bildzeile weiter rechts ist noch ein schwarzer Pixel. Macht einen Strich für 25 und einen für 70.
Eine Zeile drunter sind wieder zwei schwarze Pixel: Der eine kann durch 45 und 9 erklärt werden. Also Striche für 9 und 45. Der nächste Pixel erzeugt Striche bei 45 und 71. Eine Zeile drunter dann das gleiche Spiel: Striche für 8, 45 (links) und 45, 72 (rechts).
dann wieder: jetzt vielleicht 6, 45, 45, 74.

Du siehst, die 45 taucht ständig auf.

Ich habe das mal in Matlab programmiert:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
%% Kreis
bild = imread('kreis_2.png');
bild = im2bw(bild, 0.15);

strichliste = zeros(500,1);
radius = 84;

for x = 1:500
    for y = 1:381
        if bild(y, x) == 0
            dist = 381/2 - y;
            offset_sqr = radius^2 - dist^2;
            if offset_sqr > 0 % Zwei Lösungen
                k1 = x + round(sqrt(offset_sqr));
                strichliste(k1) = strichliste(k1) + 1;
                
                k2 = x + round(-sqrt(offset_sqr));
                if k2 >0
                    strichliste(k2) = strichliste(k2) + 1;
                end
            end
        end
    end
end

bar(strichliste);
max(strichliste)


Hier mal die Testbilder mit der Strichlist. (Die Strichliste ist als Balkendiagramm dargestellt. Wie du siehst ist das Maximum konsistent an der richtigen Stelle. Die Linien erzeugen ein bisschen Dreck, aber das Maximum bleibt.)

Hier mal die Strichliste von dem Originalbild oben:
bar1

Und hier ein etwas schwierigeres Testbild mit der Strichliste:
test2bar2
Einloggen, um Attachments anzusehen!
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 01.02.13 18:24 
Update: Dieses Thema wird mal etwas zurückgestuft. Da ich bei der Arbeit vorübergehend eine andere Arbeit erhalten habe, wird dieses Projekt für ein paar Wochen zurückgestellt.
Ich schreibe wieder wenn ich wieder Fortschritte mache.

Danke an alle die bisher geholfen haben.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mo 11.02.13 19:19 
Hallo.

Habe jetzt mal weiter gemacht und mir dein Beispiel nochmal genauer angesehen, habs - denke ich :D - verstanden.
Aber mein Code funktioniert immer noch nicht so ganz und ich weis nicht woran es liegen könnte.

Hier der Code der Suche
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
RoBitmap img = new RoBitmap(bitmap);
      RoBitmap newImg = new RoBitmap(new Bitmap(img.Width, img.Height));
      Graphics g = Graphics.FromImage(newImg.Image);
      img.Image = img.GetFormat1BppIndexed(0.2f);
      bool[,] pic = new bool[img.Width,img.Height];
      ushort[,] map = new ushort[img.Width,img.Height];
      
      // binäres Array erstellen
      for (int w = 0; w < img.Width; w++)
        for (int h = 0; h < img.Height; h++)
          pic[w, h] = img.GetPixel(w, h).ToArgb() == ARGB_BLACK;

      for (int r = minRadus; r < maxRadius; r++)
      {
        for (int x = 0; x < img.Width; x++)
        {
          for (int y = 0; y < img.Height; y++)
          {
            if (!pic[x, y]) continue// Farbe == Weiß == wertlos 

            int dist = img.Height / 2 - y;
            int offset = r ^ 2 - dist ^ 2;

            if (offset <= 0continue;

            int offX1 = x + (int)Math.Round(Math.Sqrt(offset));
            int offX2 = x - (int)Math.Round(Math.Sqrt(offset));

            Debug.WriteLine("Detected on {0}, {1}:\toffset={2}\toffX1={3}\toffX2={4}",
                            x, y, offset, offX1, offX2);

            // Sicherheitsprüfungen, ob der neue X-Wert außerhalb vom Index liegt
            if (offX1 >= 0 && offX1 < img.Width) map[offX1, y]++; 
            if (offX2 >= 0 && offX2 < img.Width) map[x, offX2]++;
          }
        }

        for (int x = 0; x < img.Width; x++)
        {
          for (int y = 0; y < img.Height; y++)
          {
            // Gefunden Kreise ins neue Bild übertragen
            if (map[x, y] < minValue) continue;
            newImg.SetPixel(x, y, Color.Green);
            g.DrawEllipse(new Pen(Color.Red), x - r, y - r, x + r, y + r);
          }
        }
      }

      boxImage.Image = newImg.Image;

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Mo 11.02.13 21:59 
Also erstmal ist "funktioniert nicht" keine akzeptable Fehlermeldung :P

Desweiteren hast du mein eindimennsionales beispiel kopiert, was erstmal nicht falsch ist, aber du hast ein paar klitzekleine Fehlerchen gemacht :wink:

 ushort[,] map Da mein Beispiel eindimensional ist, brauchst du hier nur eine Dimension. also ushort[]

ausblenden C#-Quelltext
1:
2:
map[offX1, y]++; 
map[x, offX2]++;
x und y erübrigen sich dann hier auch. In offX1 und offX2 ist die interessante info.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
using (var g = Graphics.FromImage(newImg.Image))
        for (int i = 0; x < map.length; x++)
        {          
            // Gefunden Kreise ins neue Bild übertragen
            if (map[i] < minValue) continue;
            Point c = new Point(i, img.Height / 2);
            newImg.SetPixel(c, Color.Green);
            g.DrawEllipse(new Pen(Color.Red), c.x - r, c.y - r, c.x + r, c.y + r);          
        }

So in etwa. ich habe das ganze jetzt nicht getestet. Die graphhics-Klasse impelmentiert IDisposable und muss daher freigegeben werden; ein using-Block bietet sich an dieser Stelle an.
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mo 11.02.13 22:08 
Ah Eindimensional :autsch: Dann macht das ganze etwas mehr Sinn mit k1 und k2 :D. Ich war nur verwirrt wegen der Initialisierung mit zeros(500, 1) verwirrt, was mir aber gerade klar wird weil dein zweiter parameter 1 ist omg.
Und zum Thema Fehlerangabe dachte ich gerade dass Gleiche, wollte grad den Post bearbeiten und dann Stand plötzlich die Antwort drunter xD.
Werde es gleich mal probieren. Danke für die viele Hilfe.

//P.S. Das mit Graphics ist ja theoretisch egal oder? Wenn ichs nicht frei gieb macht doch der GC nach Abschluss der Methode oder?


///EDIT
Was mir aber gerade auffällt - abgesehen davon dass es immer noch net funzt xD - ist, dass bei deinem Beispiel ja nur eine Unbekannte existier und dass ist x.
Den Radius bekomme ich ja auch weg durch meine for Schleife, aber da bei mir später x und y unbekannt sind, bin ich doch auf ein 2D Array angewiesen.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Mo 11.02.13 22:54 
Also ich habs jetzt so probiert:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
for (int r = minRadus; r < maxRadius; r++)
      {
        for (int y = 0; y < img.Height; y++)
        {
          for (int x = 0; x < img.Width; x++)
          {
            for (int y1 = 0; y1 < img.Height; y1++)
            {
              if (!pic[x, y1]) continue;

              int dist = y - y1;
              int offset = r ^ 2 - dist ^ 2;

              if (offset <= 0continue;

              int offX1 = x + (int)Math.Round(Math.Sqrt(offset));
              int offX2 = x - (int)Math.Round(Math.Sqrt(offset));

              // Sicherheitsprüfungen, ob der neue X-Wert außerhalb vom Index liegt
              //if (offX1 >= 0 && offX1 < img.Width)
              map[offX1, y1]++;
              if (offX2 > 0) map[offX2, y1]++;
            }
          }
        }
        for (int y = 0; y < img.Height; y++)
        {
          for (int x = 0; x < img.Width; x++)
          {
            // Gefunden Kreise ins neue Bild übertragen
            if (map[x, y] < minValue)
            {
              newImg.SetPixel(x, y, Color.White);
              continue;
            }

            Debug.WriteLine("Drawing Circle at {0}, {1} with radius={2}", x, y, r);
            newImg.SetPixel(x, y, Color.Green);
          }
        }

Aber da erhalte ich ein seltsames Wackelbild bestehend aus den Mittelpunkten angeblcher Kreise :/

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Di 12.02.13 11:53 
Schon wieder :roll:
Wenn du schon Bilder als Ergebnis bekommst, meinst du nicht es wäre praktisch diese anzuhängen??
Ich habe dir weiter oben versucht, ein Beispiel vorzurechnen und dafür die Freiheitsgrade (Fg) reduziert so dass nur noch einer übrig bleibt. Du bastelst da dann immer direkt 'rum und versucht ihn auf 3 Fg zu erweitern. Ich würde dir erstmal empfehlen das ganze mit einem Fg zum laufen zu bekommen - und dann wenn es funktioniert auf 3 Fg erweitern.

Aber vielleicht hast du das auch schon gemacht und das nur nicht geschrieben. (Du musst echt noch klarer bei deinen Antworten werden, Probleme raten macht nicht so viel Spaß...)

Bei deinem letzten Code: Das ist irgendwie mehr "1D auf 3d hingefrickelt" statt "Algorithmus verstanden und erweitert"

Also gehen wir nochmal an den Anfang, also vor die Schleife. Deine Kreise haben 3 Fg, daher brauchst du ein 3D Array:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
var minRadius = 10;
var maxRadius = 20;
var radius_range = maxRadius - minradius + 1:

ushort[,,] map = new ushort[radius_range, img.Width, img.Height];// 3 Fg ==> 3 dimendionales Array!


Die Schleifen brauchst du dann auch nur 3 mal:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
for (int radius = minRadius; r < maxRadius; r++)
{
  for (int y = 0; y < img.Height; y++)
  {
    for (int x = 0; x < img.Width; x++)
    {
      if (!pic[x, y]) continue;

      // das hier geht mit Sicherheit auch einfacher! Ggf. in eine Methode auslagern.
      for (int i = x-radius; i <= x+radius; i++)
        for (int j = y-radius; i <= y+radius; j++)
        {
          // ToDo: Bounds überprüfen
          int error = (x-i)*(x-i) + (y-j)*(y-j) - radius*radius
          if (error <= 1)
          map[radius - minRadius, i, j]++;
        }
    }
  }
}


Da sind bestimmt noch Fehler drin, aber ich hoffe das Prinzip wird klar.

Bitte versuche jetzt mal, den Code zu verstehen und falls das nicht klappt, den einfacheren, eindimensionalen Code zum laufen zu bekommen und zu verstehen.
C# Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Di 12.02.13 22:32 
Entschuldigung für diese Beiträge... Ich habe mehr vor mir her geschrieben als einen sinnvollen Beitrag zu machen.
Also die 1 Fg Methode funktioniert bei mir. Ich weis jetzt auch wo der Fehler lag, dass es nicht geklappt hat: Ich durfte nicht
ausblenden C#-Quelltext
1:
int offset = r ^ 2 - dist ^ 2;					

schreiben, da das keine Potenzrechnung sondern die Bitweise XOR Verknüpfung ist. Also hab ich
ausblenden C#-Quelltext
1:
int offset = (int)(Math.Pow(r, 2) - Math.Pow(dist, 2));					

eingesetzt und siehe da es klappt.

Ich wollte ein 2D Array nehmen, weil bei 3D extrem viel Speicher benötigt wird, vor allem bei Bilder die mal in über 1000x1000 gehn und bei der mit 5 versch. Radien gesucht wird -> 5.000.000 Elemente im Array. Deshalb werde ich das Array schon innerhalb der Radius-Schleife filtern, und alle Koordinaten, die über den minValue kommen, in eine Liste packen.

Das grundlegende Prinzip der Funktion habe ich schon verstanden. Jetzt Versuche ich noch die 3Fg Technik zum laufen zu bekommen.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler