Profil-/Linienlaser + Bildverarbeitung

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von nafets.

    Profil-/Linienlaser + Bildverarbeitung

    Hallo,

    möglicherweise bahnt sich ein Projekt an, bei dem die Geometrie rechteckiger keiliger Steine per Linienscanner erfasst werden sollen. Per Rotation des Steines + Profilscanner kann ich die Rohdaten der Steingeometrie per x/y/z-Koordinaten sauber erfassen. Nun bin ich auf der Suche, ob es evtl. Bibliotheken zur Bildverarbeitung / Konturerkennung gibt, die mir aus der Datenflut die Geometrie ableiten können. Quasi möchte ich jede Seite des Steines frontal abbilden und das Volumen bestimmen können. Hat jemand Erfahrung mit solch einer Aufgabenstellung und kennt evtl. Bibliotheken oder kommerzielle Software, die aus solch einer Datenwolke ein 3D-Modell erzeugen kann?

    Danke und Gruß
    Peterle
    Moin @Peterle,
    ich hätte etwas zum Stichwort Kantenerkennung. Habe ein neues Projekt aufgesetzt. Ich wollte es eben bereinigt hochladen, leider wird gesagt, die Datei ist zu groß.

    Als Erstes gehst du in den Visual-Studio-eigenen Nuget-Paketmanager und lädst dir dort die Emgu-Bibliotheken und den besseren OpenFileDialog herunter (s. Bild).




    Dann nimmst du einen Button, um das Bild zu laden, und einen Button für die Prozedur. Du brauchst noch eine Picturebox.
    Originalbild
    hiervon.



    Und damit kannst du dann weiterarbeiten. Hier erst einmal der Code:


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports Microsoft.VisualBasic.ControlChars
    2. Imports Emgu.CV
    3. Imports Microsoft.WindowsAPICodePack.Dialogs
    4. Public Class FormMain
    5. Public Shared Property LoadedPicture As Bitmap
    6. Public filepath_image As String = ""
    7. Private Shared Property Kantenbild0 As Bitmap
    8. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    9. End Sub
    10. Private Async Sub Button_Kantenbild_Click(sender As Object, e As EventArgs) Handles Button_Kantenbild.Click
    11. Await Task.Run(Sub() Kantenerkennung())
    12. End Sub
    13. Private Sub Kantenerkennung()
    14. '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.
    15. Using bgr_img As Emgu.CV.Image(Of Emgu.CV.Structure.Bgr, Byte) = LoadedPicture.ToImage(Of Emgu.CV.Structure.Bgr, Byte)
    16. Using imgGray As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) = bgr_img.Convert(Of Emgu.CV.Structure.Gray, Byte)()
    17. If PictureBox1.Image IsNot Nothing Then
    18. Me.Invoke(Sub() PictureBox1.Image = Nothing)
    19. End If
    20. Me.Invoke(Sub() PictureBox1.Image = imgGray.ToBitmap()) ' bei Belieben
    21. 'in ein 2D-Array kopieren
    22. Dim f(imgGray.Height - 1, imgGray.Width - 1) As Byte
    23. For y As Integer = 0 To imgGray.Height - 1 Step 1
    24. For x As Integer = 0 To imgGray.Width - 1 Step 1
    25. f(y, x) = imgGray.Data(y, x, 0)
    26. Next
    27. Next
    28. 'Höhe an der Stelle x, y soll der Farbwert an der Stelle x, y sein.
    29. 'Es erstreckt sich ein Gebirge zwischen z = 0 und 255.
    30. 'Das Graustufenbild wird also dreidimensional.
    31. '„Kanten“ sind die Übergänge – Stellen, an denen der Anstieg möglichst groß ist.
    32. 'Es wird nun der Gradient berechnet:
    33. Dim Betrag_des_Gradienten(imgGray.Data.Length - 1) As Double
    34. Dim i As Integer = 0
    35. For y As Integer = 1 To imgGray.Height - 2 Step 1
    36. For x As Integer = 1 To imgGray.Width - 2 Step 1
    37. 'Pythagoras
    38. 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))
    39. i += 1
    40. Next
    41. Next
    42. i = 0
    43. Using Kantenbild_lokal As New Bitmap(imgGray.Width, imgGray.Height, Imaging.PixelFormat.Format32bppArgb)
    44. Dim Max As Double = 0.0
    45. For a As Integer = 0 To Betrag_des_Gradienten.Length - 1 Step 1 'maximalen Wert aller Werte finden.
    46. If Betrag_des_Gradienten(a) > Max Then
    47. Max = Betrag_des_Gradienten(a)
    48. End If
    49. Next
    50. Dim Faktor As Double = 255.0 / Max
    51. For y As Integer = 0 To imgGray.Height - 2 Step 1
    52. For x As Integer = 1 To imgGray.Width - 2 Step 1
    53. Kantenbild_lokal.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))))
    54. i += 1
    55. Next
    56. Next
    57. If PictureBox1.Image IsNot Nothing Then
    58. Me.Invoke(Sub() PictureBox1.Image = Nothing)
    59. End If
    60. Kantenbild0 = Nothing
    61. Kantenbild0 = New Bitmap(Kantenbild_lokal)
    62. Me.Invoke(Sub() PictureBox1.Image = Kantenbild0)
    63. End Using
    64. End Using
    65. End Using
    66. GC.Collect()
    67. End Sub
    68. Private Sub Button_Bild_laden_Click(sender As Object, e As EventArgs) Handles Button_Bild_laden.Click
    69. PictureBox1.Image = Nothing
    70. Using OFD As New CommonOpenFileDialog
    71. OFD.Title = "Datei zum Öffnen auswählen"
    72. OFD.Filters.Add(New CommonFileDialogFilter("Bilder", ".jpg;.jpeg;.bmp;.png"))
    73. Dim di As New IO.DirectoryInfo(Application.StartupPath)
    74. If di.Parent.Name = "bin" Then
    75. di = di.Parent.Parent.Parent ' AnyCPU
    76. ElseIf di.Parent.Parent.Name = "bin" Then
    77. di = di.Parent.Parent.Parent.Parent ' x64, x86
    78. End If
    79. If System.IO.Directory.Exists(di.FullName) Then
    80. OFD.InitialDirectory = di.FullName
    81. Else
    82. OFD.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    83. End If
    84. If OFD.ShowDialog() = CommonFileDialogResult.Ok Then
    85. filepath_image = OFD.FileName
    86. Else
    87. Return
    88. End If
    89. End Using
    90. LoadedPicture = Nothing
    91. LoadedPicture = New Bitmap(filepath_image)
    92. PictureBox1.Image = LoadedPicture
    93. End Sub
    94. End Class



    PS: Die Kantenerkennungs-Prozedur läuft asynchron, also in einem anderen Thread als den GUI-Thread. Das ist bei großen Bildern hilfreich. Den Code kann man noch verbessern, vor allem SetPixel durch LockBits ersetzen, aber du kommst jetzt erstmal klar. Das habe ich einst mithilfe diesen Forums und den Videos von Prof Weitz geschafft.

    ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

    Was Image Processing anbelangt, da kannst du dir
    – auch bei Nuget die Accord.Imaging.Filters herunterladen. Diese Bib bietet dir Erosions-, Smoothing- und Dilations-Filter an. Das habe ich einst benutzt, weil auf einem eingescannten DIN-A4-Blatt immer ein paar Fehlpixel entstehen. Nachdem du das Bild durch den Filter gejagt hast, ist das Blatt wieder weiß ^^ Falls es das ist, was du suchst, mach ich morgen mal ein Beispielprojekt.
    @Peterle Mach mal so was:
    Medianfilter zur Eliminierung von Ausreißern
    Diskretisieren (alle Grau-Bilder in SW-Bilder konvertieren)
    Opening | Closing zum Durchbrechen heller und dunkler Brücken
    Kaplace-Filter zur Kantenfindung.
    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!
    Also in der Industrie holt man sich für sowas oft Systeme, wo die Software zum Laserlinienscanner dazu gehört. Ich weiß jetzt nicht, ob das für dich ne Option ist. Wenn ja, schau mal bei Micro-Epsilon oder Cognex, ggf. auch Faro vorbei - das sind zwei der typischen Anlaufstellen für solche Sachen. Micro-Epsilon speziell bietet auch grob zu deinem Problem ähnliche Systeme schon als Komplettpaket an: micro-epsilon.de/measurement-s…reifengeometrie-pruefung/

    Wenn solche gebündelte Systeme aus Hard- & Software nicht infrage kommen, wird es glaube ich potenziell eher etwas schwieriger, was gutes zu finden - an der Stelle habe ich in der Praxis bisher hauptsächlich die Software selbst gebaut, was in deinem Fall auch nicht sonderlich komplex, aber halt aufwendig wäre.
    Hm okay, mit Micro-Epsilon-Scannern hab ich ehrlich gesagt bisher nur Systeme mit komplett eigener Verarbeitung gebaut. Ich hatte jetzt erwartet, dass die, wenn sie solche Anwendungen wie die mit dem Reifenprofil schon im Angebot haben, auch solche 3D-Rekonstruktions-Features in ihrer Software drin hätten :D
    Also die haben Software zur 3D-Modellierung und auch kommerzielle Features in ihrer Suite, die Radien etc. bestimmen können. Wir müssen aber z.B. Durchbiegung, Aufwölbung, Parallelität und Verzug zwischen Vorder- und Rückseite bestimmen und das kann deren Software nicht. Was hattest du denn konkret für Anwendungen? Zur Auswertung hast du also auf keinerlei Bibliotheken zurückgegriffen?
    Ich habe generell an industriellen Qualitätskontrollsystemen für einige verschiedene Bauteilen gearbeitet, nichts einzelnes spezifisches. Bei Cognex hab ich schon ein bisschen was mit deren Software gemacht, aber generell bin ich eigentlich in der Forschung unterwegs und hab entsprechend fast alles selbst entwickelt, da halt experimentell (bei meiner Arbeit ging's genau darum, die Verarbeitung mit neuen Methoden zu machen, also hätte es keinen Sinn ergeben, da "alte" groß zu verwenden). Ich hatte jetzt abgesehen von der Fehlererkennung und -korrektur (und die ist ja normalerweise auch in der Library drin, über die man den Scanner ansteuert) aber auch keine Probleme, das einfach selbst zu implementieren. Mir fehlt da auch einfach etwas das Wissen, wie das bei Entwicklern läuft, die sowas auch deployen müssen und nicht nur nach dem Proof of Concept und ggf. dem Konferenzpaper fertig sind.

    Ich hab mal noch kurz nen Kollegen gefragt, der sich mehr mit der Entwicklung auskennt - der hat empfohlen, vielleicht mal die PCL anzuschauen: pointclouds.org/
    Die ist zwar auch nicht primär für solche Fälle gedacht, aber Surface Reconstruction kann die generell ganz gut. Du müsstest nur deine Laserlinienscans kurz räumlich zusammenbauen (ich hoffe du hast den Winkel relativ zu deinem Objekt, ordentliche robuste Registrierung wäre da glaube ich ziemlich anstrengend zu implementieren) und dann hast du ja auch schon ne klassische Punktwolke, die du an die PCL geben kannst. Und mit dem rekonstruierten 3D-Modell kannst du dann ja wiederum deine Parameter bestimmen. Vielleicht gibt's aber auch einfachere Methoden, da bin ich nur nicht erfahren. Da müsstest du hoffen, dass es hier noch jemand anderes gibt, der/die auf dem Gebiet arbeitet und dann hier noch antwortet. Hat aber halt wenig mit Softwareentwicklung zu tun - da bist du vermutlich hier im Forum nicht in der richtigen Community.

    Edit: Um meinen Hintergrund zu dem Thema etwas mehr zu erläutern, weil es so, wie ich es davor erklärt hatte, vermutlich etwas komisch klingt: Ich beschäftige mich eigentlich mit Machine Learning-Forschung, mit speziellem Fokus auf Bilder/Videos und Audio, aber hin und wieder auch mal anderen Sachen. Bei meiner Arbeit mit Laserlinienscannern gings hauptsächlich darum, zu versuchen, die Programmierung von solchen Systemen los zu werden und die Kontrolle von schwer zu quantifizierenden Sachen durch Machine Learning auszuprobieren. Nebenher hab ich auch mal ein paar kleine simple Sachen mit den Dingern gemacht, daher meine Erfahrung mit Cognex-Sachen, aber generell ist meine Erfahrung bzgl der Umsetzung von Sachen für den Produktiveinsatz ziemlich gering. Ich habe hier ursprünglich nur geantwortet, weil ich dachte, dass du vielleicht selbst die "ganz simplen" Sachen nicht im Blick hast (gibt's hier im Forum häufig), aber bei den tieferen Fragen kann ich selbst kaum helfen - da müsste ich auch andere fragen.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „nafets“ ()