Ein paar Probleme nach Konvertierung von C# in VB

Terminator2

Erfahrenes Mitglied
Hallo,

Habe im Internet ein dshow Projekt gefunden und muss dieses in Visual Basic konvertieren, da ich sonst einfach gar nichts vom Quellcode verstehe.

Jetzt habe ich soweit die einzelnen Module und Namespaces konvertiert. Allerdings bleiben einen Haufen Fehlermeldungen über, wo ich bei folgenden absolut keine Ahnung habe, wie ich das lösen könnte:

Fehlermeldung:
"end of-Anweisung erwartet"
Code:
            Dim ptr As Byte* = CByte(data.Scan0.ToPointer())
'Der Typ Byte* ist mir nicht bekannt und funktioniert auch nicht...

            For y As Integer = 0 To height - 1
                Dim x As Integer = 0
                While x < width
                    count += ((*ptr) >> 7)
                    x += 1
                    ptr += 1
                End While
                ptr += offset
            Next


Fehlermeldung:
"Class "MotionDetector2" muss "Property MotionLevelCalculation() As Boolean" für die IMotionDetector-Schnittstelle implementieren. Die implementierende Eigenschaft muss übereinstimmende ReadOnly- oder WriteOnly-Spezifizierer aufweisen."
"Class "MotionDetector2" muss "ReadOnly Property MotionLevel() As Double" für die IMotionDetector-Schnittstelle implementieren. Die implementierende Eigenschaft muss übereinstimmende ReadOnly- oder WriteOnly-Spezifizierer aufweisen."
"Class "MotionDetector2" muss "Sub ProcessFrame(ByRef image As System.Drawing.Bitmap)" für die IMotionDetector-Schnittstelle implementieren. "
"Fehler 9 Class "MotionDetector2" muss "Sub Reset()" für die IMotionDetector-Schnittstelle implementieren."
Code:
Namespace motion
    Public Class MotionDetector2
        Implements IMotionDetector
'Wenn man einfach die Implementierung entfernt, ist der Fehler weg, aber sicherlich funktioniert dann das Programm auch nicht...

Fehlermeldung:
"Public Event Alarm(sender As Object, e As System.EventArgs)" ist ein Ereignis und kann nicht direkt aufgerufen werden. Verwenden Sie eine RaiseEvent-Anweisung, um ein Ereignis aufzurufen.
Code:
Imports System
Imports System.Drawing
Imports System.Threading
Imports VideoSource

Namespace motion

    Public Class Camera

        Public Event Alarm As EventHandler

Private Sub video_NewFrame(ByVal sender As Object, ByVal e As CameraEventArgs)
                    If (motionDetecotor.MotionLevel >= alarmLevel) AndAlso (Alarm IsNot Nothing) Then
                        Alarm(Me, New EventArgs())
                    End If
                End If

Und noch eine Warnung:
"property "AutoSize" führt Shadowing für eine überschreibbare Methode in Basis-class "Control" durch. Wenn Sie die Basismethode überschreiben möchten, muss die Methode als "Overrides" deklariert werden."
Code:
Namespace motion
    Public Class CameraWindow
        Inherits System.Windows.Forms.Control
        Private m_camera As Camera = Nothing
        Private m_autosize As Boolean = False
        Private needSizeUpdate As Boolean = False
        Private firstFrame As Boolean = True

        Private timer As System.Timers.Timer
        Private flash As Integer = 0
        Private rectColor As Color = Color.Black

        ' AutoSize property
        <DefaultValue(False)> _
        Public Property AutoSize() As Boolean
            Get
                Return m_autosize
            End Get
            Set(ByVal value As Boolean)
                m_autosize = value
                UpdatePosition()
            End Set
        End Property

Wäre echt toll, wenn mir da jemand weiterhelfen könnte :)
 
Zuletzt bearbeitet:
Hallo Terminator2,

womit hast Du denn den Quelltext konvertiert? Oder hast Du es von Hand gemacht?

C# unterstützt sogenannte Zeiger, die einen direkten Zugriff auf die Speicherstelle einer Variablen erlauben. Visual Basic kennt dazu keine Entsprechung. Daher hast Du mehrere Alternativen:

  1. Du lässt den Code, wie er ist, und lagerst ihn in eine C#-DLL aus, die Du in Dein VB-Projekt einbindest. Anschließend rufst Du die entsprechende Funktion aus VB heraus auf.
  2. Du versuchst, C# zu lernen oder zumindest Zeiger zu verstehen, damit Du den Quelltext auch in C# richtig interpretieren kannst.
  3. Du verwendest Visual Basic und gehst den Umweg über das sog. Marshalling (suche danach hier im Forum, da gibt es einiges dazu :rolleyes:).
Zur Klasse MotionDetector2:
Wie lauten denn Deine übersetzten Eigenschaften und Funktionen? Da C# Eigenschaften auf anderem Wege mit Lese- und Schreibrechten ausstattet als VB, wäre die Frage, ob Du nicht tatsächlich hinter die betreffenden Property-Anweisungen eine ReadOnly- bzw. WriteOnly-Anweisung einfügen musst. Zudem scheinen zwei Funktionen der Schnittstelle noch nicht implementiert zu sein. Du müsstest also mal nachsehen, ob Du alle Funktionen übersetzt hast.

Zur video_newFrame-Funktion:
Die Ereignis-Systeme von C# und VB unterscheiden sich ein bisschen. Während in C# überprüft werden muss, ob das Ereignis überhaupt aufrufbar ist und anschließend das Ereignis wie eine Funktion behandelt wird, kennt VB dafür eine Kurzform: Die RaiseEvent-Anweisung. Du müsstest den Code also folgendermaßen abändern:

Code:
 If motionDetector.MotionLevel >= alarmLevelRaiseEvent Alarm(Me, EventArgs.Empty)
End If
Zum letzten Problem:
Die Eigenschaft AutoSize ist bereits Bestandteil der Basisklasse Control. Da die neue Klasse ebenfalls eine Eigenschaft AutoSize implementiert, musst Du angeben, wie in diesem Fall verfahren werden soll:

  1. Du verwendest vor Property das Shadows-Schlüsselwort, um anzugeben, dass beide Eigenschaften verwendet werden.
  2. Du verwendest vor Property das Overrides-Schlüsselwort, um anzugeben, dass Du die AutoSize-Eigenschaft der Control-Klasse überscheibst und damit ausblendest.
Ich hoffe, dass ich verständlich geschrieben habe. Versuche, die Änderungen umzusetzen. Bei Fragen kannst Du Dich gerne wieder melden.

Gruß
PhoenixLoe
 
Hey,

Deine Erklärung ist wirklich gut.
Mittlerweise habe ich mich wohl dazu entschlossen, alles in C# zu schreiben. Das war zwar anfangs ziehmlich schwer, aber ich bin jetzt fast fertig mit dem Programm.
Also wenn ich ein Fazit ziehen müsste, Visual Basic finde ich bei weitem besser, es gibt nur wenige Dinge, die mir bisher bei C# positiv aufgefallen sind.
Trotzdem ist es gut, auch mal eine andere Sprache zu schreiben, da doch sehr viele Projekte in C# zu finden sind :)
 
Hallo Terminator2,

mit demselben "Problem" wie du hatte ich auch zu kämpfen.
Den Code den du hier übersetzen wolltest stammt doch sicher von Sourceforge? Kommt mir sehr bekannt vor. Habe auch mit gekämpft. :)

Was du da hast ist die "Rohfassung" oder auch ein Teil des Aforge Frameworks:
http://www.aforgenet.com/framework/

Da gibts mit Version 2 auch Motion(detector) komplett drin, glaube ich. Solltest du dir ansehen, bevor du alles selber machst.
 
Ich habe den motion detector von codeprojekt runtergeladen und dann versucht ihn zu übersetzen. Aber das hätte Tage gedauert... Nach geschlagenen 10 Stunden lief es fast, aber ich hab jetzt soweit alles in C# geschrieben.
Leider bleibt jetzt auf dem AMD PC, auf dem ich das Programm laufen lassen will, das Bild alle 5 Sekunden hängen, das für 5 Sekunden, und läuft dann wieder weiter.
Keinen Schimmer, wie das kommt, aber es sieht nach einem Timer aus. Nur dumm, dass da eigentlich gar kein Timer sein dürfte, der so ein Phänomen hervorruft...
Kann das vielleicht daran liegen, dass es ein AMD CPU ist, mit ATI (AMD) Chipsatz und einer onboard Grafikkarte von ATI? Habe den Grafikspeicher auf 256MB gesteigert, dann schien es wunderbar zu klappen, leider nur für kurze Zeit.
 
Kann es sein, dass du irgendwo im MotionDetector Bilder speicherst und nicht wieder freigibst?
Ansonsten war es bei mir so, dass eine lokal angeschlossene Kamera(Webcam) einfach so schnell Bilder geliefert hat, dass der Rechner kaum nachkam und dadurch insgesamt langsam wurde (hohe CPU-Last).

Auf jeden Fall solltest du dir Aforge ansehen, dass brauchst du eigentlich nur einzubinden und fertig ist. Wenn die CPU zu sehr belastet wird, setze die maximale Framerate runter. Es gibt eine entsprechende Property da drin.
 
Zuletzt bearbeitet:
Das hört sich ganz gut an. Ich habe auch schon überlegt, ob irgendwelche Objekte nicht wieder gelöscht werden, habe allerdings nichts finden können.
Die Einstellung der maximalen Framerate würde ich gerne ändern, aber ich habe die Einstellung nicht finden können. Weder im Camera Objekt noch sonst wo...

Ich poste aber mal den Code, der das Bild bei der Bewegungserkennung verarbeitet, wenn irgendwo was falsch läuft, dann bestimmt hier:
Code:
		// Process new frame
		public void ProcessFrame(ref Bitmap image)
		{
			if ( backgroundFrame == null )
			{
				// create initial backgroung image
				backgroundFrame = grayscaleFilter.Apply( image );

				// get image dimension
				width	= image.Width;
				height	= image.Height;

				// just return for the first time
				return;
			}

			Bitmap tmpImage;

			// apply the grayscale file
			tmpImage = grayscaleFilter.Apply( image );

			// set backgroud frame as an overlay for difference filter
			differenceFilter.OverlayImage = backgroundFrame;

            // apply difference filter
            Bitmap tmpImage2 = differenceFilter.Apply( tmpImage );

            // lock the temporary image and apply some filters on the locked data
            bitmapData = tmpImage2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

            // threshold filter
            thresholdFilter.ApplyInPlace( bitmapData );
            // erosion filter
            Bitmap tmpImage3 = erosionFilter.Apply( bitmapData );
            
            // unlock temporary image
            tmpImage2.UnlockBits( bitmapData );
            tmpImage2.Dispose( );

			// dispose old background
			backgroundFrame.Dispose( );
			// set backgound to current
			backgroundFrame = tmpImage;

			// extract red channel from the original image
			Bitmap redChannel = extrachChannel.Apply( image );

            //  merge red channel with moving object
            mergeFilter.OverlayImage = tmpImage3;
            Bitmap tmpImage4 = mergeFilter.Apply(redChannel);
            redChannel.Dispose();

            // replace red channel in the original image
            replaceChannel = new ReplaceChannel(RGB.R, tmpImage4);
            Bitmap tmpImage5 = replaceChannel.Apply(image);
            tmpImage4.Dispose();

            image.Dispose();
            image = tmpImage5;

            //Falls Alarm-Fenster vorhanden sind:
            if (MainForm.Instance.AlarmWindow.Count > 0)
            {
                //Erst einmal die Bildausschnitte extrahieren:                
                Single W_korrektur = (Single)1 / (Single)100 * (Single)tmpImage3.Width;
                Single H_korrektur = (Single)1 / (Single)100 * (Single)tmpImage3.Height;

                bool AlarmActivated = MainForm.Instance.tmrBildSperre.Enabled;

                for (int i = 0; i < MainForm.Instance.AlarmWindow.Count; i++)
                {
                    //Da die Koordinaten sortiert vorliegen, kann die Breite einfach errechnet werden
                    int X1 = (int)((Single)MainForm.Instance.AlarmWindow[i].Pos1_X * W_korrektur);
                    int Y1 = (int)((Single)MainForm.Instance.AlarmWindow[i].Pos1_Y * H_korrektur);

                    //Prozentualer Anteil an bewegten Pixel im Fenster in Objekt schreiben:
                    MainForm.Instance.AlarmWindow[i].AlarmLevel = (int)Pixels(GetPicturePart(tmpImage3, new Rectangle(X1, Y1, ((int)((Single)MainForm.Instance.AlarmWindow[i].Pos2_X * W_korrektur) - X1), ((int)((Single)MainForm.Instance.AlarmWindow[i].Pos2_Y * H_korrektur) - Y1))));

                    if ((int)MainForm.Instance.AlarmWindow[i].AlarmLevel >= (int)MainForm.Instance.AlarmWindow[i].AlarmMinLevel)
                    {
                        MainForm.Instance.AlarmWindow[i].AlarmActive = true;
                        if (AlarmActivated == false)   
                        {
                            AlarmActivated = true;  //Jetzt wird ein Signal gesendet:
                            MainForm.Instance.tmrBildSperre.Enabled = true;   
                            MainForm.Instance.tmrSavePicture.Enabled = true;   
                        }
                    }
                    //Speicher freigeben
                    //Puffer.Dispose();
                }
            }
            tmpImage2.Dispose();
            tmpImage3.Dispose();
        }

Prinzipiell funktioniert das alles auch. Auf dem Notebook macht die Webcam bei ca. 8fps keine Probleme. Auf dem AMD PC macht die selbe WebCam bei 16fps aber nach einer gewissen Zeit den Fehler...
 
Ich weiß nicht ob es daran liegt, aber nach dem Durchzählen der verwendeten Images fehlt für tmpImage und tmpImage5 jeweils das Dispose.
 
Das stimmt.
Habe schon versucht, die beiden zu disposen, dann wird aber kein Bild mehr angezeigt. Auch bei nur einem der beiden Bilder funktioniert es nicht.
Man müsste die Rückgabe evtl. als neues Bild zurückgeben, und dafür die anderen beiden disposen. Werde das gleich mal ausprobieren.
 
Zurück