Kann man einen GraphicsPath anklicken, um fehlerhafte Linien zu entfernen?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    Kann man einen GraphicsPath anklicken, um fehlerhafte Linien zu entfernen?

    Hi!
    Ich lade via OpenFileDialog ein Bild. Dieses wird zu einem Schwarz-Weiß-BIld gemacht (nicht mit grau verwechseln). Danach benutze ich einen Erosions- und Dilationsfilter, um die meisten Pixelfehler zu beheben. Nun habe ich ein „perfektes“ Schwarz-Weiß-Bild und starte die Prozedur zur Kantenerkennung. Diese arbeitet in 2 Stufen, hier als Beispiel Weiß umranden:
    • von oben nach unten und von links nach rechts. Sobald kein Schwarz mehr gesehen wird (und die nächsten Pixel weiß sind), wird sich der Punkt gemerkt, die innere Schleife wird verlassen; und es wird mit dem nächsten y weitergemacht
    • unten weitermachen, also von unten nach oben und von rechts nach links. Dito.
    Die Punkte kommen in eine List(of Point) (Private Liste_mit_Punkten As List(Of Point)). Mit dieser wird ein Graphics.Path gezogen. Leider ist es so, dass trotz Bildbearbeitung einige Fehler drin sind (siehe Bild 2). Kann man diese beheben?

    VB.NET-Quellcode

    1. Imports System.Drawing.Drawing2D
    2. Public NotInheritable Class AllesGrafische
    3. Public Shared Sub Paint_the_Rectangle(ByVal g As Graphics, ByVal recta As Rectangle)
    4. If g IsNot Nothing Then
    5. g.SmoothingMode = SmoothingMode.AntiAlias 'For Bezier curves, using GraphicsPath, you need SmoothingMode.AntiAlias
    6. g.CompositingQuality = CompositingQuality.HighQuality
    7. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    8. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    9. Using Pen_Hellblau As Pen = New Pen(Color.FromArgb(0, 200, 255), 1.0F)
    10. g.DrawRectangle(Pen_Hellblau, recta)
    11. End Using
    12. End If
    13. End Sub
    14. Public Shared Sub Draw_Curve(ByVal g As Graphics, ByVal theList As List(Of Point))
    15. If theList IsNot Nothing AndAlso theList.Count > 0 AndAlso g IsNot Nothing Then
    16. g.SmoothingMode = SmoothingMode.AntiAlias
    17. g.CompositingQuality = CompositingQuality.HighQuality
    18. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    19. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    20. Using gp As New GraphicsPath
    21. gp.AddLines(theList.ToArray())
    22. gp.CloseFigure()
    23. Using Pen_gelb As Pen = New Pen(Color.FromArgb(255, 255, 0), 2.0F)
    24. g.DrawPath(Pen_gelb, gp)
    25. End Using
    26. End Using
    27. End If
    28. End Sub
    29. End Class
    Bilder
    • Bild1 - Kopie.png

      820 Byte, 61×169, 514 mal angesehen
    • Bild2 - Kopie.png

      1,82 kB, 53×142, 517 mal angesehen
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @Bartosz Zur Detektion von Kanten nimmt man den Laplace-Filter, da kommt eine 1-Pixel breite Kurve raus.
    de.wikipedia.org/wiki/Laplace-Filter
    codeproject.com/Articles/37299…an-of-Gaussion-Edge-Detec

    Quellcode

    1. 0 1 0
    2. 1 -4 1
    3. 0 1 0

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Ich weiß, ich habe gestern die vb-paradise-Suche bedient, und habe unter anderem gesehen , dass du das öfter schreibst. Leider kam ich mit diesem Code-Projekt-Code nicht klar. Könntest du mir helfen, biite?
    ur Detektion von Kanten nimmt man den Laplace-Filter, da kommt eine 1-Pixel breite Kurve raus.

    de.wikipedia.org/wiki/Laplace-Filter

    codeproject.com/Articles/37299…an-of-Gaussion-Edge-Detec
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @Bartosz Wie solch ein Filter funktioniert:
    Du hast ein Array mit dem Mono-Image: ImageArray
    Du hast ein genau so großes Array für das gefilterte Bild: TempArray
    üblicherweise Byte oder UShort, dedr Code funktioniert mit beiden.
    Spoiler anzeigen

    C#-Quellcode

    1. public void Laplace()
    2. {
    3. // Hilfsfeld
    4. Array.Clear(this.TempArray, 0, this.Width * this.Height);
    5. for (int y = 1; y < this.Height - 1; y++)
    6. {
    7. int zeile = y * this.Width;
    8. for (int x = 1; x < this.Width - 1; x++)
    9. {
    10. int index = zeile + x;
    11. int sum = 0;
    12. if (Parameter.ContourBorderDark) // was stehenbleiben soll
    13. {
    14. // dunkle Seite ist Rand
    15. sum += this.ImageArray[index - this.Width];
    16. sum += this.ImageArray[index + this.Width];
    17. sum += this.ImageArray[index + 1];
    18. sum += this.ImageArray[index - 1];
    19. sum -= this.ImageArray[index] << 2;
    20. }
    21. else
    22. {
    23. // helle Seite ist Rand
    24. sum -= this.ImageArray[index - this.Width];
    25. sum -= this.ImageArray[index + this.Width];
    26. sum -= this.ImageArray[index + 1];
    27. sum -= this.ImageArray[index - 1];
    28. sum += this.ImageArray[index] << 2;
    29. }
    30. this.TempArray[index] = sum > 0 ? ushort.MaxValue : ushort.MinValue;
    31. }
    32. }
    33. // zurück in das Image-Array
    34. Array.Copy(this.TempArray, this.ImageArray, this.Width * this.Height);
    35. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Ok, das muss ich mir erstmal anschauen; wenn wieder den Kopf frei habe. Ich bin mir nicht sicher, ob ich das gut 'rübergebracht habe. Es geht darum, eine Figur komplett zu umranden. Wenn ich mir das Beispielbild auf dieser Seite anschaue, und ich solche Linien hätte, dann wüsste ich immer noch nicht, wie ich sagen dann: Die linke und die rechte dort und dort umranden den einen Körper; also die gehören zusammen. Weil bei meinem Verfahren sage ich einfach Close. Natürlich hat mein Verfahren Nachteile. Ich mache dann ein Testprojekt auf und lade das hier bereinigt und gezippt hoch.
    Ich bedanke mich trotzdem! Ich melde mich die Tage.

    Schnelle Lösung für heute: Ich habe nun eine Vorkehrung getroffen, die lange Linien von Point1 zu 2 nicht akzeptiert. Also der Betrag von (Vektor1 - Vektor2) darf nicht größer sein als 4. Also nichts von wegen nachträglich Linien löschen.

    $ \Delta s = norm( \left(\begin{array}{c} a \\ b \end{array}\right) - \left(\begin{array}{c} c \\ d \end{array}\right)) $


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Drawing2D
    2. Public NotInheritable Class AllesGrafische
    3. Public Shared Sub Paint_the_Rectangle(ByVal g As Graphics, ByVal recta As Rectangle)
    4. If g IsNot Nothing Then
    5. g.SmoothingMode = SmoothingMode.AntiAlias 'For Bezier curves, using GraphicsPath, you need SmoothingMode.AntiAlias
    6. g.CompositingQuality = CompositingQuality.HighQuality
    7. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    8. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    9. Using Pen_Hellblau As Pen = New Pen(Color.FromArgb(0, 200, 255), 1.0F)
    10. g.DrawRectangle(Pen_Hellblau, recta)
    11. End Using
    12. End If
    13. End Sub
    14. Public Shared Sub Draw_Curve(ByVal g As Graphics, ByVal theList As List(Of Point))
    15. If theList IsNot Nothing AndAlso theList.Count > 0 AndAlso g IsNot Nothing Then
    16. g.SmoothingMode = SmoothingMode.AntiAlias
    17. g.CompositingQuality = CompositingQuality.HighQuality
    18. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    19. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    20. Dim theList_neu As New List(Of Point)
    21. Using gp As New GraphicsPath
    22. For i As Integer = 1 To theList.Count - 1 Step 1
    23. Try
    24. Dim a As Integer = theList(i).X
    25. Dim b As Integer = theList(i).Y
    26. Dim c As Integer = theList(i - 1).X
    27. Dim d As Integer = theList(i - 1).Y
    28. Dim Entfernungsbetrag As Integer = CInt(Math.Round(Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2) + Math.Pow(c, 2) + Math.Pow(d, 2) - 2 * a * c - 2 * b * d), 0))
    29. If Entfernungsbetrag < 4 Then
    30. theList_neu.Add(theList(i))
    31. End If
    32. Catch ex As System.ArgumentOutOfRangeException
    33. End Try
    34. Next
    35. gp.AddLines(theList_neu.ToArray())
    36. gp.CloseFigure()
    37. Using Pen_hellrosa As Pen = New Pen(Color.FromArgb(255, 64, 239), 2.0F)
    38. g.DrawPath(Pen_hellrosa, gp)
    39. End Using
    40. End Using
    41. End If
    42. End Sub
    43. End Class

    Bilder
    • Screenshot 2021-01-13 190948 - Kopie.png

      1,71 kB, 59×134, 458 mal angesehen
    -1-
    Du solltest grundsätzlich verstehen was eine "Kantendetektion" macht: Begreife ein Bild mal für einen Moment als eine Funktion, die von IR^2 -> IR abbildet, das ist, eine 3-Dimensionale Funktion, dessen Farbwerte
    im Grunde die Höhe der Funktion an der Position (x, y) "kodiert".

    Hast du das verstanden, kannst du mathematische Ansätze wunderbar auf die Bildverarbeitung übertragen, z.B. sogenannte Faltungen oder - wie @RodFromGermany bereits angemerkt hat - Filter. Filter stellen mathematisch eigentlich eine diskrete 2D-Faltung dar (de.wikipedia.org/wiki/Faltung_(Mathematik)#Definition).

    Wozu brauchen wir aber Faltung/Filter? Nun, du solltest dir erstmal die Frage stellen, was "Kanten" in einem Bild eigentlich sind - konvertiere das RGB-Bild mal in ein Graubild, dann hast du eine Intensitätsfunktion I(x, y) die zu jedem x,y-Tupel eine Intensität z ∈ [0, 255] zuordnet - mit anderen Worten: Man kann ein Bild ebenso als ein (diskretes) Skalarfeld begreifen; ist es ein Skalarfeld kann darauf der Gradienten-Operator (de.wikipedia.org/wiki/Gradient…k)#Koordinatendarstellung) appliziert werden. Dieser gibt ein n-wertigen Vektor zurück, dessen Komponenten jeweils die partielle Ableitung der Funktion darstellen,
    das heißt, grad I(x, y) -> IR^2 - nun ist ein Bild nichts anderes als eine diskrete Funktion (mit anderen Worten: Es gibt zu JEDEM Bild eine Funktion, die das Bild eindeutig identifiziert, siehe z.B. Fourier-Transformation), die Komponenten des Gradienten wäre also z.B. das gewichtete Mittel zwischen
    (Pixel Links + Pixel Rechts) / (1 + 1)

    An was erinnert uns das? Richtig: Die Definition des Differentials (lim dx->0 (f(x + dx) + f(x))/dx). Weil ein Bild aber ja diskret ist, können wir selbstverständlich nicht Grenzwertverfahren nutzen, sondern müssen die minimal mögliche Distanz - also 1 - wählen. Und schon haben wir die Näherungsformel zu Berechnung der Ableitung der Funktion f:IR^2->IR an der Stelle (x, y) relativ zur X/Y-Achse.

    X-Achse wäre: (Pixel Links + Pixel Rechts) / 2
    Y-Achse wäre: (Pixel Oben + Pixel Unten) / 2

    Das heißt:

    Hx:

    Quellcode

    1. (-1 * I(x - 1, y) + 0 * I(x, y) + 1(x + 1, y))/2

    Hy:

    Quellcode

    1. (-1 * I(x, y - 1) + 0 * I(x, y) + 1(x, y + 1))/2


    Das erinnert uns aber stark an ein Filter!
    Wir können das also als Filter folgendergestalt zusammenfassen:

    Hx: [-1, 0, 1] * 0.5
    Hy: [-1, 0, 1]^T * 0.5

    Weil ja der Gradient komponentenweise als partielle Ableitung einer Funktion definiert ist, gibt der Filter an den Stellen des Bildes, an denen die Intensität relativ gleichverteilt ist einen sehr niedrigen -, an Stellen wo der Intensitätsverlauf sich rapide ändert jedoch einen sehr hohen Wert zurück: Und vóila - wir haben unsere Definition einer Kante: Eine Kante bezeichnet all diejenigen Bereiche des Bildes, dessen Intensitätsverteilung in einer NxN-Nachbarschaft sich arg verändert (jetzt mal grob zusammengefasst).
    Würde man ein Bild plotten, wobei die Intensitäten I(x, y) die Höhe eines Vertizes darstellen, wären Kanten die Ränder von Senkungen und Hebungen.

    Der Laplace-Filter ist dabei die "zweite" Ableitung; ein wesentlicher Grund warum man diesen verwendet ist, weil man nicht einen ganzen Bereich, sondern höchsten einen minimalen Bereich haben möchte, wo die Intensitätsveränderungen sehr hoch ist. Dafür bildet man quasi die Differenz der Differenz (die Ableitung der Ableitung), und schon hat man den Laplace-Operator (der nicht separabel ist - die Variante die @RodFromGermany ist aber sehr effizient).

    Ich finde es sehr wichtig die zugrundeliegenden, mathematischen Details zu verstehen. Code implementieren kann jeder, verständnisvoll diesen zu entwerfen ist halt Skill..
    _
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „φConst“ ()

    @φConst Danke für die anschauliche Beschreibung. Vor allem
    wären Kanten die Ränder von Senkungen und Hebungen.

    Gradient sagt mir tatsächlich etwas. Zwar aus der Elektrostatik, aber egal. „Das elektrische Feld zeigt in die Richtung, in der sich ϕ(r) am stärksten ändert.“
    $ \vec{E} = - \nabla \phi $


    Mit z = f(x, y) hatte ich auch zu tun, siehe Bild. Ist nur etwas länger her. Oder, was ich gerade wiedergefunden habe: die Eierpappe, hier ein paar Bilder von Wolfram Alpha. Hier sieht man sehr deutlichst die Senkungen und Hebungen und im Bild WA2 die „Höhenlinien“.
    Bilder
    • Unbenannt.PNG

      28,01 kB, 828×470, 107 mal angesehen
    • WA1 - Kopie.png

      58,19 kB, 589×501, 95 mal angesehen
    • WA2 - Kopie.png

      59,66 kB, 586×399, 102 mal angesehen
    Ja, also, naja, das sind halt Funktionen der Form f:IR^2->IR - und ja, der Gradient zeigt immer in Richtung des stärksten Anstieges, oder: Von Senkungen weg, respektive zu Höhen hinein.

    Bartosz schrieb:

    Mit z = f(x, y) hatte ich auch zu tun, siehe Bild. Ist nur etwas länger her

    Wie gesagt, ist einfach eine 2D-Funktion, jeder hat mal damit zu tun gehabt (-;, im Abitur mit f(x), im Studium dann f(x, y, ... ).

    Bartosz schrieb:

    Hier sieht man sehr deutlichst die Senkungen und Hebungen und im Bild WA2 die „Höhenlinien“.

    Richtig, und siehe da: Die Funktionswerte werden farblich kodiert, Kanten in deinem Bild WA2 wären also die Ränder der Hebungen und Senkungen der Funktion in WA1. Ein Bild ist also so gesehen die senkrechte Projektion einer 3D-Fläche auf eine Ebene.
    Und Gott alleine weiß alles am allerbesten und besser.
    Kanten in deinem Bild WA2 wären also die Ränder der Hebungen und Senkungen der Funktion in WA1. Ein Bild ist also so gesehen die senkrechte Projektion einer 3D-Fläche auf eine Ebene.
    Dann habe ich das richtig verstanden. Ich habe das Beispiel mit der Eierpappe gewählt (und die Bilder hochgeladen), weil ich in dieselbe Richtung gedacht habe. Ich hätte es nur nicht so formulieren können. Danke Dir!!
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Ok, ich habe es geschafft. Könntet ihr bitte einmal rübergucken?

    Ich habe mir gestern Nacht noch diese 2 Videos von Prof. Dr. Weitz angesehen. Ich kann diese Videos nur jedem empfehlen!

    1. Video
    2. Video

    Dann habe ich mich ans Programm gemacht. Für die, die das so machen wollen wie ich, ihr müsst euch über den Visual-Studio-eigenen Nuget_Manager die Emgu-Pakete herunterladen.
    Außerdem

    VB.NET-Quellcode

    1. Imports Emgu.CV


    Und stellt auf x86 um.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button_Kantenerkennung_professionell_Click(sender As Object, e As EventArgs) Handles Button_Kantenerkennung_professionell.Click
    2. 'Das Originalbild wird in ein Graustufenbild umgewandelt. Ich nutze die Emgu.CV-Sachen, da ich das am einfachsten finde und ich dann keine selbstgeschriebenen Matrizen hernehmen muss.
    3. Using bgr_img As Emgu.CV.Image(Of Emgu.CV.Structure.Bgr, Byte) = Picture1.ToImage(Of Emgu.CV.Structure.Bgr, Byte)
    4. Using imgGray As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) = bgr_img.Convert(Of Emgu.CV.Structure.Gray, Byte)()
    5. If PictureBox1.Image IsNot Nothing Then
    6. PictureBox1.Image = Nothing
    7. End If
    8. PictureBox1.Image = imgGray.ToBitmap()
    9. 'in ein 2D-Array kopieren
    10. Dim f(imgGray.Height - 1, imgGray.Width - 1) As Byte
    11. For y As Integer = 0 To imgGray.Height - 1 Step 1
    12. For x As Integer = 0 To imgGray.Width - 1 Step 1
    13. f(y, x) = imgGray.Data(y, x, 0)
    14. Next
    15. Next
    16. 'Höhe an der Stelle x, y soll der Farbwert an der Stelle x, y sein.
    17. 'Es erstreckt sich ein Gebirge zwischen 0 und 255.
    18. 'Das Graustufenbild wird also dreidimensional.
    19. '„Kanten“ sind die Übergänge – Stellen, an denen der Anstieg möglichst groß ist.
    20. 'Es wird nun der Gradient berechnet:
    21. Dim Gradient_x(imgGray.Data.Length - 1) As Int16
    22. Dim Gradient_y(imgGray.Data.Length - 1) As Int16
    23. Dim Betrag_des_Gradienten(imgGray.Data.Length - 1) As Int16
    24. Dim i As Integer = 0
    25. For y As Integer = 1 To imgGray.Height - 2 Step 1
    26. For x As Integer = 1 To imgGray.Width - 2 Step 1
    27. Gradient_x(i) = CShort(Math.Round((Math.Abs(CShort(f(y, x + 1)) - CShort(f(y, x - 1)))) / 2.0, 0))
    28. Gradient_y(i) = CShort(Math.Round((Math.Abs(CShort(f(y + 1, x)) - CShort(f(y - 1, x)))) / 2.0, 0))
    29. Betrag_des_Gradienten(i) = CShort(Math.Round(Math.Sqrt(Math.Pow(Gradient_x(i), 2) + Math.Pow(Gradient_y(i), 2)), 0))
    30. i += 1
    31. Next
    32. Next
    33. i = 0
    34. Dim Kantenbild As New Bitmap(imgGray.Width, imgGray.Height)
    35. Dim _Graphics As Graphics = Graphics.FromImage(Kantenbild)
    36. For y As Integer = 0 To imgGray.Height - 2 Step 1
    37. For x As Integer = 1 To imgGray.Width - 2 Step 1
    38. Kantenbild.SetPixel(x, y, Color.FromArgb(Betrag_des_Gradienten(i), Betrag_des_Gradienten(i), Betrag_des_Gradienten(i)))
    39. i += 1
    40. Next
    41. Next
    42. PictureBox1.Image = Kantenbild
    43. End Using
    44. End Using
    45. GC.Collect()
    46. End Sub

    Kantenbild.bmp

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    @φConst
    "Waaa? Hast du Abitur oder was?"
    Jetzt weiss ich wieder warum mein Berufsberater meinte, es gäbe kein Berufsbild "Türsteher auf Lehramt".
    Danke für die "Ausführung". ;)

    φConst schrieb:

    Ich finde es sehr wichtig die zugrundeliegenden, mathematischen Details zu verstehen. Code implementieren kann jeder, verständnisvoll diesen zu entwerfen ist halt Skill..


    So jetzt haste es geschafft, ich hole jetzt das alte "Analysis Buch" raus, und lerne mal Mathe. Habe bei Integralrechnung abgeschaltet...
    Daraus folgt zwingend diese hinreichende binäre "Ableitung": Hinsetzen, büffeln, und kein YouTube mehr, es sei denn es ist Lesch oder Weitz und Konsorten. lol (Ein Beweis ist nicht auszuführen.)

    @Bartosz

    EDIT: Eierkarton, ist das eine mathematische Funktion? Really...

    Ich wohne ja so halb bei Prof. Weitz um die Ecke, ich gehe mal hin und Knuddel den mal. Vielleicht hilft das bei Mathe und ich verwechsel dann Lagrange nicht mehr mit Laplace. lol

    Und Pflicht bei YouTube: Prof. Weitz seine Weihnachtsvorlesungen... (Nicht Prof. Witz)

    @all c.u. Joshi ohne Weitz aber mit LaLaPlace und LaGaragee... lalala 8|

    Ich bin dann mal am analogen Rechenschieber.

    Bartosz schrieb:

    Könntet ihr bitte einmal rübergucken?

    Naja, wieso du jetzt EmguCV verwendest ist mir ein Rätsel - im Grunde tust du alles das, was .NET sowieso grundlegend anbietet, Farbbild in ein Graubild umzuwandeln geht ganz einfach, um es zu beschleunigen nutzt du halt LockBits, dann verwendest du ein 2D-Array, auch nicht so effizient, dann führst du in der Schleife immer eine Division aus, was auch nicht gut ist.
    Mit Bit-Operatoren bist du wesentlich schneller dran, das heißt

    x >> 1 entspricht einer Division durch 2,
    x << 1 entspricht einer Multiplikation mit 2.

    Also:

    VB.NET-Quellcode

    1. Gradient_x(i) = CShort(f(y, x + 1) - f(y, x - 1)) >> 1
    2. Gradient_x(i) = CShort(f(y + 1, x) - f(y - 1, x)) >> 1
    3. Betrag_des_Gradienten(i) = CShort(Math.Sqrt((Gradient_x(i) << 1) + (Gradient_y(i) << 1))


    Was mich aber noch mehr wundert ist, wieso du überhaupt die Gradientenkomponenten abspeicherst, du berechnest doch die Beträge der Gradienten inplace.
    Du könntest dir eigentlich die Wurzel auch sparen und den resultierenden Wert einfach clampen, und dann halt .GetPixel(x, y) - nicht so performant. Ansonsten ja, das ist eine Variante eine Kantendetektion zu implementieren, gibt aber wesentlich bessere, die das ganze noch gewichten (Sobel-Operator).
    Geht also wesentlich effizienter, und vor allem generischer.
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()

    @φConst

    Voll positiv, bin nur kicherich...

    Ich wollte nur unbeholfen meine Wertschätzung zum Ausdruck bringen.

    Es erscheint mir das Wissensvermittlung, das Fachgerecht und lehrend, wie in deinem Fall hier, immer weniger wird.
    Auch eine zunehmende informations Konsumierung, im Gegensatz zur Gesellschaftlich erforderlichen informations Assimilierung, scheint statt zu finden.

    Zitat Josph Weizenbaum: "Wir suchen nach Erkenntnis, und ertrinken in Information."

    Zudem ist deine informations Entropie in deiner Ausführung extrem hoch (auf den ersten und zweiten Blick), im Gegensatz zu meinem "Kommentar" der sich bei (gefühlt) minus 3,5 befindet.

    Es ist auch nicht von der Hand zu weisen, das eine Spaltung der Gesellschaft bei Bildungsniveuas sich immer mehr abzeichnet, daher bitte ich um Verzeihung falls ich dazu beigetragen habe.

    Vielen Dank dir für deinen Beitrag, der regt zum Lernen an. :)

    @Bartosz
    Ja, habe nicht zum Thema beigetragen, ausser "Eiersalat".
    Das hilft mir und danke dir für die Bilder, jetzt nur noch ein "Wendepunkt" in Joshi´s Beiträgen und weiter gehts.

    c.u. Joshi
    @φConst Danke für dein Feedback!

    Stimmt, mit Bit-
    Operatoren sollte das besser sein.

    Was mich aber noch mehr wundert ist, wieso du überhaupt die Gradientenkomponenten abspeicherst, du berechnest doch die Beträge der Gradienten inplace.
    Meinst du, ich soll die Formel CShort(f(y, x + 1) - f(y, x - 1)) >> 1 und CShort(f(y + 1, x) - f(y - 1, x)) >> 1 direkt unten einsetzen?

    du könntest dir eigentlich die Wurzel auch sparen und den resultierenden Wert einfach clampen,
    Stimmt, hab' ich schon im Video gesehen. Naja, ich benutze die Wurzel. Im privaten Umfeld steht keiner mit 'ner Peitsche hinter mir.

    wieso du jetzt EmguCV verwendest ist mir ein Rätsel Der Hauptgrund ist eigentlich, dass ich diese selbstgeschriebenen Matrizen vermeiden wollte. Und such mal nach Graubild-Konvertierung. Du findest alles, aber du weißt nicht, welche Werte die richtigen sind. Und vor allem, ich weiß, dass es mit Emgu funktioniert – das ist das wichtigste. Könntest du mir bitte eine Sache vorschlagen, die .Net liefert?

    (Sobel-Operator)
    Ok, immer gut im Hinterkopf zu behalten, denke ich ^^

    @Joshi
    Das hilft mir und danke dir für die Bilder
    Gerne, gerne.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Bartosz“ ()

    @Joshi Freut mich, falls du von meinem Beitrag profitieren konntest (-:

    @Bartosz

    1.) Graubild in .NET erzeugen, nice work-around: stackoverflow.com/a/32843917/14727115

    2.)

    Bartosz schrieb:

    Meinst du, ich soll die Formel CShort(f(y, x + 1) - f(y, x - 1)) >> 1 und CShort(f(y + 1, x) - f(y - 1, x)) >> 1 direkt unten einsetzen?

    Du sollst diese einfach direkt in

    VB.NET-Quellcode

    1. ​ Betrag_des_Gradienten(i) = CShort(Math.Sqrt((Gradient_x(i) << 1) + (Gradient_y(i) << 1))

    einsetzen.


    3.)

    Bartosz schrieb:

    Im privaten Umfeld steht keiner mit 'ner Peitsche hinter mir

    Mit absoluten Beträgen ist es halt performanter (-;

    4.)

    Bartosz schrieb:

    Der Hauptgrund ist eigentlich, dass ich diese selbstgeschriebenen Matrizen vermeiden wollte

    .NET bietet das schon an: docs.microsoft.com/de-de/dotne…?view=dotnet-plat-ext-5.0

    Hoffe das beantwortet alle Fragen.
    Grüße.
    Und Gott alleine weiß alles am allerbesten und besser.
    @φConst @Bartosz Wenn Du die Länge einer Diagonale berechnest, solltest Du die Komponenten unter der Wurzel nicht vorher auf Short casten.
    Und
    a << 1 ist äquivalent zu 2 * a, nicht aber a * a.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Stimmt, da hatte ich falsch gedacht - danke für den Hinweis.
    Ich hoffe der TE sieht das noch.
    Bzgl des Casts: Ja, das ist richtig, ich habe aber einfach den Schnippsel des TE genutzt - wollte insbesondere zeigen, dass die Division durch 2 auch >> 1 -, und damit effizienter ist.
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()

    φConst schrieb:

    Division durch 2 auch >> 2
    Division durch 2 ist nn >> 1.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!