Kann man einen GraphicsPath anklicken, um fehlerhafte Linien zu entfernen?
- VB.NET
- .NET (FX) 4.5–4.8
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.
-
-
@RodFromGermany
Wenn Du die Länge einer Diagonale berechnest, solltest Du die Komponenten unter der Wurzel nicht vorher auf Short casten.
Habe ich auch schon gesehen, danke dir trotzdem ! Ich hatte das erst gemacht, weil doch tatsächlich f(y + 1, x)) - f(y - 1, x) einen Überlauf verursacht hat – der hintere war größer als der vordere, sodass etwas Negatives herauskommt, was in Byte nicht geht. Jetzt ist eh alles in Double. (und asynchron und heller)
VB.NET-Quellcode
- Private Async Sub Button_Kantenerkennung_professionell_Click(sender As Object, e As EventArgs) Handles Button_Kantenerkennung_professionell.Click
- Await Task.Run(Sub() Kantenerkennung_professionell())
- End Sub
- Private Sub Kantenerkennung_professionell()
- '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.
- Using bgr_img As Emgu.CV.Image(Of Emgu.CV.Structure.Bgr, Byte) = Picture1.ToImage(Of Emgu.CV.Structure.Bgr, Byte)
- Using imgGray As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) = bgr_img.Convert(Of Emgu.CV.Structure.Gray, Byte)()
- If PictureBox1.Image IsNot Nothing Then
- Me.Invoke(Sub() PictureBox1.Image = Nothing)
- End If
- Me.Invoke(Sub() PictureBox1.Image = imgGray.ToBitmap())
- 'in ein 2D-Array kopieren
- Dim f(imgGray.Height - 1, imgGray.Width - 1) As Byte
- For y As Integer = 0 To imgGray.Height - 1 Step 1
- For x As Integer = 0 To imgGray.Width - 1 Step 1
- f(y, x) = imgGray.Data(y, x, 0)
- Next
- Next
- 'Höhe an der Stelle x, y soll der Farbwert an der Stelle x, y sein.
- 'Es erstreckt sich ein Gebirge zwischen 0 und 255.
- 'Das Graustufenbild wird also dreidimensional.
- '„Kanten“ sind die Übergänge – Stellen, an denen der Anstieg möglichst groß ist.
- 'Es wird nun der Gradient berechnet:
- 'Dim Gradient_x(imgGray.Data.Length - 1) As Double
- 'Dim Gradient_y(imgGray.Data.Length - 1) As Double
- Dim Betrag_des_Gradienten(imgGray.Data.Length - 1) As Double
- Dim i As Integer = 0
- For y As Integer = 1 To imgGray.Height - 2 Step 1
- For x As Integer = 1 To imgGray.Width - 2 Step 1
- 'Gradient_x(i) = (CDbl(f(y, x + 1)) - CDbl(f(y, x - 1))) / 2.0
- 'Gradient_y(i) = (CDbl(f(y + 1, x)) - CDbl(f(y - 1, x))) / 2.0
- 'Pythagoras
- Betrag_des_Gradienten(i) = Math.Sqrt(Math.Pow((CDbl(f(y, x + 1)) - CDbl(f(y, x - 1))) / 2.0, 2) + Math.Pow((CDbl(f(y + 1, x)) - CDbl(f(y - 1, x))) / 2.0, 2))
- i += 1
- Next
- Next
- i = 0
- Dim Kantenbild As New Bitmap(imgGray.Width, imgGray.Height, Imaging.PixelFormat.Format32bppArgb)
- Dim _Graphics As Graphics = Graphics.FromImage(Kantenbild)
- Dim Max As Double = 0.0
- For a As Integer = 0 To Betrag_des_Gradienten.Length - 1 Step 1 'maximalen Wert aller Werte finden.
- If Betrag_des_Gradienten(a) > Max Then
- Max = Betrag_des_Gradienten(a)
- End If
- Next
- Dim Faktor As Double = 255.0 / Max
- For y As Integer = 0 To imgGray.Height - 2 Step 1
- For x As Integer = 1 To imgGray.Width - 2 Step 1
- Kantenbild.SetPixel(x, y, Color.FromArgb(CInt(Math.Round(Betrag_des_Gradienten(i) * Faktor, 0)), CInt(Math.Round(Betrag_des_Gradienten(i) * Faktor, 0)), CInt(Math.Round(Betrag_des_Gradienten(i) * Faktor, 0))))
- i += 1
- Next
- Next
- Me.Invoke(Sub() PictureBox1.Image = Kantenbild)
- Kantenbild0 = Kantenbild
- End Using
- End Using
- End Sub
-
Grundsätzlich kannst du diese Operationen ganzzahlig ausführen. Ist meines Erachtens nicht so gut zwischen double und int hin -und her zu casten. Du kannst statt pow(x, 2), einfach x * x schreiben (und nicht wie ich erwähnt hatte << 1, das wäre tatsächlich * 2), Wurzel brauchst du da sowieso nicht, weil die Wurzelfunktion stetig im Definitionsbereich ist und damit Ordnungen beibehält, dass heißt wenn x^2 kleiner ist als y^2, dann ist betragsmäßig x auch kleiner als y. Dein Kantenbild wird sich also nicht verändern, du brauchst nur halt einen zusätzlichen Proportionalitätsfaktor um den Wert in einen gewünschten Bereich zu drücken - oder du arbeitest von vornherein mit Farbwerten die jeweils zwischen 0 und 1 liegen - aber ob diese ganzen Optimierungen jetzt was grundlegend ändert.. wenn's funktioniert ist es erstmal ja gut.Und Gott alleine weiß alles am allerbesten und besser.
-
Ich muss mich nochmal an euch wenden. Ich möchte, wie in Post1 beschrieben, einen Bereich auswählen; und die Erkennung soll in dem Rechteck suchen und einen Körper umranden. Aufgrund der Kantenerkennung funktioniert das besser, aber nicht 100%ig perfekt. Ich habe mir 2 Hilfen eingebaut. Einmal eine Schwarzweißschwelle („Wie starkes Weiß (0 bis 255) muss ich sehen?“), und eine Einstellung, wie lang eine Strecke zwischen 2 Punkten maximal sein darf. Je nach Foto sind natürlich die Einstellungen leicht verschieden. Man kann jedoch immer sagen: Zu streng ist Mist, zu locker ist Mist. Irgendwo dazwischen ist das Optimum, jedoch muss das Wort Optimum nicht ‘gut’ heißen. Das Ergebnis-Bild ist im Anhang.
Was kann man noch machen? Am liebsten wäre mir, und daher der Titelname, dass ich den GraphicsPath manuell korrigieren kann. Aber ich finde nichts Gescheites bei sta**********. Ich habe bisher nur gefunden, wie man komplett selbst zeichnet und dann habe ich dort einen Löschvorgang eingebaut. Das habe ich mal hochgeladen. Allerdings bekomme ich es nicht hin, beides zu tun. Any help is appreciated
Spoiler anzeigen C#-Quellcode
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- namespace selbst_zeichnen
- {
- public partial class Form1 : Form
- {
- private GraphicsPath _drawingPath = new GraphicsPath();
- private Point lastMouseLocation;
- private bool drawing = false;
- public Form1()
- {
- InitializeComponent();
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- }
- private void Form1_MouseDown(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Right)
- {
- _drawingPath = new GraphicsPath();
- Invalidate();
- }
- }
- private void Form1_MouseMove(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- drawing = true;
- _drawingPath.AddLine(lastMouseLocation, e.Location);
- Invalidate();
- }
- if (e.Button == MouseButtons.None && drawing)
- {
- drawing = false;
- _drawingPath.StartFigure();
- }
- lastMouseLocation = e.Location;
- }
- private void Form1_Paint(object sender, PaintEventArgs e)
- {
- e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
- e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
- e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
- e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
- using (SolidBrush b = new SolidBrush(Color.Blue))
- using (Pen p = new Pen(b, 51))
- {
- e.Graphics.DrawPath(p, _drawingPath);
- }
- using (SolidBrush b = new SolidBrush(Color.LightGreen))
- using (Pen p = new Pen(b, 50))
- {
- e.Graphics.DrawPath(p, _drawingPath);
- }
- }
- }
- }
-
-
@φConst Ja, gerne. Ich sage es vorsichtshalber: es geht mir nicht um Elektronik, sondern ich brauchte einfach irgendein Bild, wo größere und kleinere geschlossene Teile drin sind – das Holstentor kann man schlecht umrahmen; ist auch nicht das Ziel.
Du kannst allerdings jedes beliebige Foto hernehmen. -
Exemplarische Vorgehensweise:
Image-Segmentation anwenden, ich habe mal eine Segmentierung basierend auf sogenannte Graph-Cuts gewählt (in MatLab geladen, und dann entsprechend Vorder -und Hintergrund markiert), Resultat:
Nun kann ich einen Treshold festlegen - alles gelb-markierte wird betont, alles andere auf 0 gesetzt, Resultat:
Darauf die Kantendetektion anwenden, und dann einfach mit dem Urbild addieren - schon hast du eine präzise, MODIFIZIERBARE, Kantendetektion implementiert.
Dein Beispiel wäre:
Näheres:
Was du per se vorhast, ist nicht zu unterschätzen. Das geht tief in die Materie, wenn du das präziser haben willst, und individuell die Kurven setzen ist auch kein Kompromiss, weil du dadurch Akkuratesse und Präzision verlieren könntest.Und Gott alleine weiß alles am allerbesten und besser.Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()
-
Danke für die Idee. Das Video schaue ich mir morgen an.
individuell die Kurven setzen ist auch kein Kompromiss, weil du dadurch Akkuratesse und Präzision verlieren könntest.
1) „Programm soll möglichst gut erkennen, damit ich keine anderen Programme brauche und weil ich sonst Präzision verliere.“
2) „Das ist schwer zu implementieren, ich muss individuell Kurven setzen.“
Daher finde ich deine Vorgehensweise geeignet. -
Bartosz schrieb:
„Wie starkes Weiß (0 bis 255) muss ich sehen?“
Dann finde Deine Kanten,mit dem oben beschriebenen Filter.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! -
Zum Abschluss möchte ich das, was innerhalb des GraphicsPaths ist, auf ein neues Bild übertragen, siehe Schema. Ich habe bisher keine Möglichkeit gefunden, dies in ein neues Bild zu übertragen; daher dachte ich mir, ich schreibe mir eine Funktion, welche prüft, ob das derzeitige x, y innerhalb oder außerhalb des Paths liegt. Wenn außerhalb: transparent, sonst wie im Originalbild. Wie kann in nun diese Liste durchgehen, wenn es mehrere gleiche y oder x gibt?
Ich habe schon mal den Code für „ein neues Bild basierend auf dem Rechteck erstellen“.
Spoiler anzeigen VB.NET-Quellcode
- Using Extracted As Bitmap = New Bitmap(rect.Width, rect.Height, Imaging.PixelFormat.Format32bppArgb)
- Using Grp As Graphics = Graphics.FromImage(Extracted)
- Grp.DrawImage(Form1.Picture1, 0, 0, rect, GraphicsUnit.Pixel)
- End Using
- If System.IO.Directory.Exists("C:\Users\xy\Desktop") Then
- Extracted.Save("C:\Users\xy\Desktop\1.png", Imaging.ImageFormat.Png)
- End If
- End Using
-
Hi, kurzes Update: ich habe für die letztgenannte Sache eine Möglichkeit gefunden. Muss nur ins VB.Net übersetzt werden. Damit setze ich diesen Thread auf erledigt.
stackoverflow.com/questions/33…e-in-a-specific-shape-net
converter.telerik.com/
-
Benutzer online 2
2 Besucher
-
Ähnliche Themen
-
Im Chart linien am Rand entfernen
Hotdogxxxx - - Sonstige Problemstellungen -
OOP-Problem bei Zeichenroutine
FreakJNS - - Sonstige Problemstellungen -
Klenix - - Multimedia- und Spieleprogrammierung
-
4 Benutzer haben hier geschrieben
- Bartosz (14)
- φConst (10)
- RodFromGermany (5)
- Joshi (2)