- Labornetzteil AliExpress         
Ergebnis 1 bis 10 von 390

Thema: Rasenrobo mit Induktionsschleife, Schaltbilder, Hallsensor

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    14.05.2006
    Beiträge
    260

    Objekterkennung mit webcam, Navigation

    Hallo,

    vor einiger Zeit ist noch mal nach Bildverarbeitung/webcam gefragt worden. Da ich vor Kurzem von VB6 auf vb.net umgestiegen bin, stelle ich hier noch mal meine Erfahrungen und Codeschnipsel zusammen. Vielleicht ist es ja dem einen oder anderen hilfreich Als erstes ein kurzes Video, vom Monitor mitgeschnitten:



    Die webcam ist im 2.Stockwerk angebracht. Die Videoüberwachung besteht im wesentlichen aus:
    1. Erstellen von bitmaps aus dem laufenden mjpg-stream
    2. Korrektur der schrägen, verzerrten Bildern in eine Aufsicht von oben
    3. Objekterkennung des Rasenrobo
    4. Steuerung des Rasenrobo entlang eines vorgezeichneten Kurses

    Für Objekterkennung könnte man auch OpenCV einsetzen. Ginge sicher flotter, wollte mir aber mal alles zu Fuß erarbeiten. Aforge habe ich kurz angetestet. Nachdem es eine gefühlte Ewigkeit dauerte, bis der live-stream auf dem Monitor war, habe ich auch das gelassen und alles nur mit vb.net Bordmittel programmiert.

    zu 1.: Habe eine Klassenbibliothek "streamtoimage.dll" gestrickt (in OpenCV gibt´s dafür sicher fertige .dll):
    Code:
    Imports System.Drawing, System.Drawing.ImagingImports System.Net, System.IO
    Imports System.Net.Sockets
    Public Class Streamtoimage
        Shared img As Bitmap, flag As Integer = 0, flag2 As Integer = 0
        Shared flag3 As Integer = 0, z As Integer = 0, z5 As String, ii As Integer = 0
        Shared tcpclient As TcpClient
        Shared enc As System.Text.Encoding = System.Text.Encoding.Default
        Shared st As String 
        Shared buffer5(400000) As Byte, buffer6(200000) As Byte, remotehost2 As String = "", schnipsel2 As String = ""
        Shared WithEvents t1 As Timers.Timer
    
        Public Shared Function zeit()
            Return z
        End Function
    
        Public Shared Sub starten()
            If flag3 = 1 Then Exit Sub
            flag3 = 1 : ii = 0 : flag = 0 : flag2 = -200
            tcpclient = New Net.Sockets.TcpClient()
            tcpclient.ReceiveBufferSize = 100000
            tcpclient.Client.Connect(remotehost2, 80)
            st = "GET /" + schnipsel2 + " HTTP/1.1" + vbCrLf + "Host: 192.168.1.15" + vbCrLf + "Connection: keep-alive" + vbCrLf + vbCrLf ' + "Referer: http://" + "192.168.1.35/live.asp?r=20121005" + vbCrLf + vbCrLf
            tcpclient.Client.Send(enc.GetBytes(st))
            t1 = New Timers.Timer : t1.Interval = 30 : t1.Enabled = True
            flag3 = 0
        End Sub
    
        Public Shared Function streamtoimage(ByVal remoteHost As String, ByVal schnipsel As String)
            remoteHost2 = remoteHost : schnipsel2 = schnipsel
            If IsNothing(tcpclient) = True Then starten()
            If tcpclient.Connected = False Then starten()
            Return (img)
        End Function
    
        Protected Overrides Sub Finalize()
            t1.Enabled = False
            tcpclient.Close()
            MyBase.Finalize()
        End Sub
    
        Private Shared Sub t1_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles t1.Elapsed
            If flag > 0 Then Exit Sub
            flag = 1 : flag2 = flag2 + 1 : If flag2 = 50 Then starten()
            Dim data As String, i As Integer = 0, iii As Integer
            Dim länge As Integer, anf As Integer
            If tcpclient.Client.Available > 0 Then
                i = tcpclient.Client.Receive(buffer6)
                If ii + i >= 400000 Then ii = 0
                    Array.Copy(buffer6, 0, buffer5, ii, i) : ii = ii + i
                    data = enc.GetString(buffer5, 0, ii)
                    iii = InStr(data, "Content-Length")
                    If iii > 0 And ii > iii + 50 Then
                        länge = (Val(Trim(Mid(data, iii + 15, 7))))
                        anf = InStr(iii + 18, data, vbCrLf + vbCrLf)
                        If anf + 3 + länge <= ii Then
                            Array.Copy(buffer5, anf + 3, buffer6, 0, länge)
                            img = Bitmap.FromStream(New MemoryStream(buffer6))
                            z = Now.Second * 1000 + Now.Millisecond
                            ii = 0 : flag2 = 0
                        End If
                    End If
            End If
            flag = 0
        End Sub
    End Class
    Aus dem Programm können dann laufend mit img=streamtoimage("IPwebcam","Anfrage") Bilder aus dem web-stream geladen werden. Tricky ist der Ausdruck für "Anfrage". Der ist von der webcam abhängig und z.B. für meine Edimax IC-3115W: snapshot.cgi Gibt man z.B. im webbrowser
    http://IPwebcam/snapshot.cgi
    ein, kommt sofort der livestream. Für andere webcam läßt sich der Ausdruck aus dem Quellcode rausfischen.

    2. das image packt man in ein array (buffer1):
    Code:
            Dim bd1 As BitmapData
            Dim rect As New Rectangle(0, 0, img.Width, img.Height)
            bd1 = img.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
            dim max as integer =   bd1.Stride * bd1.Height - 1
            dim buffer1(max) as integer
            Copy(bd1.Scan0, buffer1, 0, max) : img.UnlockBits(bd1)
    dann verschiebt man die Pixel im Array buffer um eine Aufsicht von oben zu erhalten. Stichwort Koordinatentransformation,Projektion

    Code:
    matrix()
    .
    .
    .
    For i = 1 To max : Bildneu(i) = buffer1(matrixxy(i)) : Next
    .
    .
    .
     Sub matrix()
            Dim x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer
            Dim a As Integer, b As Integer, f As Single, yschräge As Integer
            a = 1400 : b = 800 : yschräge = 70
            For k = 0 To img.Height - 1 : For i = 0 To img.Width - 1
                x1 = img.Height - k : y1 = i - yschräge * (x1 / img.Height) '- d
                f = (a * b - x1 * a - y1 * b) : If f < 1 Then f = 1
                f = a * b / f
                y1 = (f * y1 * 0.5) : x1 = (f * x1 * 0.5)
                x1 = img.Height - x1
                 if x1 >= 0 And y1 >= 0 And x1 < img.Height And y1 < img.Width Then
                    For a1 = 0 To 2 : For a2 = 0 To 2 : For a3 = 0 To 2
                      y2 = y1 + a1 : x2 = x1 + a2
                      If k*stride + i*3 + a3 <= max And x2*stride + y2*3 + a3 <= max Then
                           matrixxy(x2 * stride + y2 * 3 + a3) = k * stride + i * 3 + a3
                      End If 
                     Next : Next : Next
                  End If
            Next i : Next k
     End Sub
    Die Unterseite des Videobildes kann man bereits durch Ausrichten der webcam parallel zur x-Achse einstellen. Dann sind noch 3 Parameter einzustellen, die man am besten durch probieren ermittelt. Mit yschräge wird die y-Achse senkrecht zu x-Achse ausgerichtet. a und b entsprechen dem Abstand der Fluchtpunkte (Horizont) in x und y Richtung vom Nullpunkt.

    3. Erkennung des rasenrobo: Der Robo hat einen roten Fleck. Grob gesagt wird zu jedem Pixel der Wert 3 * rot - blau - grün bestimmt. Dann bestimmt man die größte positive und negative Änderung dieses Parameters von einem Bild zum nächsten und mittelt noch über mehrere benachbarte Pixel. Wer´s genauer wissen will, muss sich leider durch folgenden Code arbeiten:
    Code:
    schritt=2 ' um´s etwas zu beschleunigen 
    
    For k = 0 To img.Height - 1 Step schritt 
       For i = 0 To (img.Width - 1) Step schritt
               blau = Bildneu(k * stride + i * 3) 
               grün = Bildneu(k * stride + i * 3 + 1) 
               rot = Bildneu(k * stride + i * 3 + 2)
               blaualt = Bildalt(k * stride + i * 3) 
               grünalt = Bildalt(k * stride + i * 3 + 1) 
               rotalt = Bildalt(k * stride + i * 3 + 2)
            S5(i, k) = 3 * rot - blau - grün - 3 * rotalt + blaualt + grünalt
    Next i : Next k
    
    Bildneu.CopyTo(Bildalt, 0)
    
    'als nächstes Mittelung mit benachbarten Pixel
    For k = 1 To img.Height - 1 Step schritt 
      For i = 1 To (img.Width - 1) Step schritt
         If S5(i, k) <> 0 Then 
                 S1(i, k) = S5(i, k) + (S1(i - 1, k) + S1(i, k - 1)) / 9 * 4
         Endif
         ii = img.Width - i - schritt : kk = img.Height - k - schritt
         If S5(ii, kk) <> 0 Then 
                S2(ii, kk) = S5(ii, kk) + (s2(ii + 1, kk) + s2(ii, kk + 1)) / 9 * 4
         endif
    Next i : Next k
    
    '   Maximum- und Minimumwerte suchen
    For k = 0 To img.Height - 1 Step schritt 
       For i = 0 To (img.Width - 1) Step schritt
               S1(i, k) = S1(i, k) + s2(i, k)
               If smax < S1(i, k) Then smax = S1(i, k) : xmax = i : ymax = k
               If smin > S1(i, k) Then smin = S1(i, k) : xmin = i : ymin = k
    Next i : Next k
    If smax < 200 Then xmax = -100 : ymax = -300       'nichts gefunden
    If smin > -200 Then xmin = -200 : ymin = -400        'nichts gefunden
    
    
    xmit = 0 : ymit = 0  
     '    nur wenn max und min nahe beieinander liegen auswerten
    '    Mittelpunkt zwischen Maximum und Minimum ermitteln (Schwerpunkt)
    If abs(ymax - ymin) < 40 And abs(xmax - xmin) < 40 Then
           ymit = (ymax + ymin) / 2 : xmit = (xmax + xmin) / 2
           If ymit Mod 2 = 1 Then ymit = ymit + 1
           If xmit Mod 2 = 1 Then xmit = xmit + 1
           x = 0 : y = 0 : m1 = 0
           For i = xmit - 30 To xmit + 30 Step schritt 
              For k = ymit - 30 To ymit + 30 Step schritt
                 If i > 0 And k > 0 Then
                   x = x+i*abs(S1(i, k)): y = y+k*abs(S1(i, k)): m = m+abs(S1(i, k))
                 End If
            Next : Next 
    xmit = x / m : ymit = y / m
    End If
    xmit und ymit sind dann die gesuchten Koordinaten. Anschließend kann man noch evtl. Ausreißer von xmit und ymit verwerfen. Die Werte machen ja keine großen Sprünge.

    Dann braucht man noch etwas an Krimskrams für ne GUI drumrum. Uff, das war´s dann. Von denen die sich mit Objekterkennung auskennen, hätte ich natürlich gerne gewußt, ob´s z.B. mit OpenCV wesentlich besser und einfacher geht.

    Beste Grüße

    Christian
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken Original.JPG   Korrigiert.JPG  
    Geändert von Christian H (05.06.2013 um 11:07 Uhr)

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    06.08.2008
    Ort
    Graz
    Beiträge
    521
    Danke für die Info über die Bilderkennung. Jetzt muss ich noch ein Tutorial für vb.net für dummies suchen
    Wäre ein rotes Licht nicht einfacher/zuverlässiger zu erkennen?

    LG!
    alles über meinen Rasenmäherroboter (wer Tippfehler findet darf sie gedanklich ausbessern, nur für besonders kreative Fehler behalte ich mir ein Copyright vor.)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress