Hallo,
Da ich in meinem letzten Thread einige Tipps + Tricks zum Thema Bildverarbeitung bekommen habe, sitz ich nun hier und würde generell wissen, welche Schnittstelle ihr mir raten würdet wenn ich:
benötige ?
Bisher läuft alles über DirectShow.NET und ich hol mir über das ISampleGrabberCB Interface den aktuellen Frame des AVIs und stell's in einer Picturebox dar. Jedoch lagt das nach einer Zeit extrem und führt manchmal zum kompletten Stillstand. Jetzt ist schon ein Buffer gebastelt worden, der 5 Bilder im voraus speichert, aber das ist auch eher "Notgedrungen" und nicht gerade sauber.
Wie würdet ihr das angehen ? Ich hätte z.b. die Idee, das AVI direkt mit DirectShow anzeigen zu lassen, aber bisher stoße ich auf das Problem, dass DirectShow das Fenster, in dem ich es zeichne, komplett überschreibt und keine eigenen Objekte zulässt.
Vielen Dank für jede Hilfe !
lg
Phil
Hallo,
Ich habe nun herausgefunden, warum es manchmal hängt:
Das Bitmap, welches ich zum zeichnen verwende, wird über eine managed DirectX Methode aus einem AVI-Film gelesen (war nicht anders möglich) und dann über diese Schnittstelle ausgelesen.
Jetzt kann es aber manchmal sein, dass beim schnellen Scrollen das Image gerade gezeichnet wird, jedoch die API noch beim auslesen des Bitmaps aus dem AVI Film ist. Sprich sie greifen auf den gleichen Speicher zu.
Du hast recht mit deiner Vermutung, dass das _bitmap Array ein Bitmap Buffer ist (hat damals vor paar Jahre ein Kollege programmiert, den hab ich erst jetzt fragen können), damit man diesem Problem Herr wird. 100% funktionieren tut's aber nicht.
Meine weitere Frage zu dem Thema:
Gibt es eine Möglichkeit, den Image-Speicher bei schnellem Scrollen synchron zu halten?
Vielen Dank für die Inputs soweit
@Picturebox. Mittlerweile bin ich soweit, dass ich die Picturebox vererbe und in der vererbten Klasse das Bild direkt mit pe.Graphics.DrawImage() zeichne .. Ist das schneller? Oder gibt's da noch schnellere Möglichkeiten (native ? )
lg
Philipp
Puh,
Das ist ja mal eine gute Optimierung.
@1. OK das ist klar. Ehrlich gesagt war mit nicht bewusst, dass das direkte Casten große Probleme machen kann
@2. Wow .. OK SO genau wusste ich's dann auch nicht.
Aber es ging mit deinem Code gut (außer dass input + output vertauscht war)
Die Strides sind gleich groß, also konnte ich den Wert von data.Stride auch für den Output übernehmen.
Dein Code ist nochmal um ein Stück schneller als bisher ..
Das schlimmste ist jetzt das hochzählen von "y" in der for Schleife .. Wahnsinn ^^ .. Danke!
Da du dich scheinbar echt gut auskennst noch eine Frage, die du zufällig wissen könntest:
Im Prinzip lese ich ein Video aus und stelle aus zwei verschiedenen AVI-Streams die jeweiligen Bilder in einer Picturebox dar. Ab und zu bleibt das Bild einfach hängen beim schnellen durch-scrollen und ich brauch ca. 5Sekunden bis zu 1 Minute damit das Programm wieder reagiert ... Kann es da zu einem Memoryproblem kommen ?
Der gesamte Quelltext der Funktion sieht jetzt so aus, vllt kannst du das aus dem Quelltext heraus erkennen..
Vielen Dank auf jeden Fall !!! 😃
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
{
Bitmap bitmap = _bitmaps[(_currentBitmap + 1)%NUM_BITMAPS];
if (bitmap == null || bitmap.Height != VideoHeight || bitmap.Width != VideoWidth)
{
_bitmaps[(_currentBitmap + 1)%NUM_BITMAPS] = new Bitmap(VideoWidth, VideoHeight,
PixelFormat.Format24bppRgb);
bitmap = _bitmaps[(_currentBitmap + 1)%NUM_BITMAPS];
}
if (bufferLen == bitmap.Width * bitmap.Height * 3)
{
var r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData data = bitmap.LockBits(r, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
int inputStride = data.Stride;
int outputStride = data.Stride;
int bytesPerLine = VideoWidth*3;
for (int y = 0; y < VideoHeight; y++)
{
int reverseY = (VideoHeight - 1) - y;
IntPtr inputLine = pBuffer + (reverseY*inputStride);
IntPtr outputLine = data.Scan0 + (y*outputStride);
RtlMoveMemory(outputLine, inputLine, bytesPerLine);
}
bitmap.UnlockBits(data);
_currentBitmap++;
Changed(this, null);
}
return 0;
}
lg
Phil
Ha du bist gut .. Darauf hätte ich auch selber kommen können aufKopfklatsch
Von 33% auf 14,8% runter .. Danke dir =)
Sieht jetzt so aus:
unsafe
{
int stride = m_videoWidth * 3;
//RtlMoveMemory(data.Scan0, pBuffer, stride);
byte* dst = (byte*)data.Scan0.ToPointer();
byte* src = (byte*)pBuffer.ToPointer();
for (int i = 0; i < this.m_videoHeight; i++)
{
byte* str = src + (this.m_videoHeight - i - 1) * stride;
RtlMoveMemory((IntPtr)dst, (IntPtr)str, stride);
dst += stride;
}
}
Danke nochmals
lg
Phil
Liebe MyCshapr Community,
Ich bin beim Performance testen auf folgende Schwachstelle in meinem Programmcode gekommen
unsafe
{
int stride = m_videoWidth * 3;
//RtlMoveMemory(data.Scan0, pBuffer, stride);
byte* dst = (byte*)data.Scan0.ToPointer();
byte* src = (byte*)pBuffer.ToPointer();
for (int i = 0; i < this.m_videoHeight; i++)
{
byte* str = src + (this.m_videoHeight - i - 1) * stride;
for (int j = 0; j < stride; j++)
{
*(dst++) = *(str++);
}
}
}
Hat wer von euch eine Idee, wie ich diesen Codeblock beschleunigen könnte?
Im Speziellen verursacht "*(dst++) = *(str++)" den Performanceverlust (Laut Visual Studio bis zu 33% Programmweit O_O)
Vielen Dank
lg
Philipp
Na gut, ich schein glaub ich zu viel um den heißen Brei rumzureden.
Ich such seit Tage schon nach einer ausführlichen Beschreibung der Vector3D und Matrix3D Klassen, uzw. nicht nur "M12 is first row, second column" sondern auch deren Bedeutungen usw. Ich dachte, daß ich das hier mal frage und wollte mit dem Beispiel gleich erklären warum ich das suche. Einfach weil beim AutoCAD und beim WPF nicht die gleichen Ergebenise rauskommen. Das Koordinatensystem ist bei beiden gleich, was ich bisher feststellen konnte.
Den Auszug mit dem "Fehler" war jetzt nicht gemeint, daß es darum geht, sondern galt als Hintergrund warum ich überhaupt das Ganze mache. (Quasi als Einleitung des restlichen Codes, den ich zuletzt gepostet habe)
Einzelschrittdebugging verwende ich schon. Ich hänge halt, wie gesagt, schon bei der ersten Rotation, die mir nicht das gleiche auswirft. Bzw. ich nicht weiß, ob die Matrix Rotation z.b. das Quadrantenproblem schon ausmerzt oder in welche Richtung ich drehe wenn ich positiv drehe. Bei der Methode steht "Appends a rotation transform to the current Matrix3D. " und das war's .. Kein Beispiel, keine Zeichnung wie man sich das vorstellen kann oder so. Klar normalerweise braucht man so etwas auch nicht, weil's ja, wie du richtig festgestellt hast, es schon implementiert ist und man es einfach nur verwenden muss. .. Aber gerade bei solchen Funktionen wäre es wichtig zu wissen, was für mathematische Operationen da im Hintergrund ablaufen, um den Input anzupassen
mhmm .. und was ich letztendlich suche ist z.b. ein Beispiel oder eine Referenz, das mir eine saubere Transformationsimplementierung beschreibt anhand der ich debuggen kann. (Aber nicht in 2D, da gibt's genug, das stimmt 😃 )
lg
Phil
Mhmm .. OK so wie du klingst schein ich einen völlig falschen Ansatz zu verfolgen kopfkratz
Ich meinte nicht die Rotation an sich als quellcode, sondern wie man sich das vorstellen kann, in welche Richtung es dreht etc.
Anders gefragt... Was würdest du für so eine Transformation verwenden ? Scheinbar nicht die PresentationBase vom WPF ..
Es ist im Moment so, daß wir diese Transformation über eine lange Funktion mit diversen mathematischen Operationen realisiert haben. So jetzt ist da nur irgendwo ein kleiner Fehler drinnen und wie so oft typisch, gibt es den Typen nicht mehr, der diesen Code geschrieben hat. So und meine Aufgabe wäre jetzt, das ganze nachzuvollziehen (ok das geht noch) und einfacher zu programmieren, damit es leichter verwaltbar wird.
Ich dachte mir an sowas z.b.:
// Relativer Vektor von der Kamera zum Objekt
Point3D point = new Point3D(1.257, -0.875, -11.379);
Point3D output;
Matrix3D resFromDll = Matrix3D.Identity;
// Verdrehung der Kamerawinkel zur IMU einrechnen
resFromDll.Rotate(new Quaternion(new Vector3D(1, 0, 0), 90 - (11 + 0.502)));
resFromDll.Rotate(new Quaternion(new Vector3D(0, 0, 1), -10));
// Kameraoffsets zur IMU
resFromDll.Translate(new Vector3D(-1.236, 0.121, 2.406));
// Verdrehungen nach pitch/nick
resFromDll.Rotate(new Quaternion(new Vector3D(0, 1, 0), -2.133));
resFromDll.Rotate(new Quaternion(new Vector3D(1, 0, 0), -0.502));
// Verdrehung heading
resFromDll.Rotate(new Quaternion(new Vector3D(0, 0, 1), 180 + 95.323));
// Absolute Koordinaten einbeziehen
resFromDll.Translate(new Vector3D(7180.147, 347923.101, 161.904));
output = point*resFromDll;
Das wär der aktuelle Quellcode, der aber nicht genau (paar meter daneben) zum gewünschten Ergebnis kommt (ok das will ich jetzt auch net erfragen, aber wollte eben wissen ob solche Beispiele mit der PresentationCore überhaupt sinnvoll sind ..) ..
Hmm .. Im Prinzip ja, sry dass ich dich damit verwirrt habe, ich dachte nur ich erzähl von dem Einsatzzweck damit klar ist, was ich machen will..
Wenn man's genau nimmt ist es aber so, dass die absolute Koordinate in der IMU, also im Fahrzeuginneren gespeichert ist. D.h. ich muss den Vektor vom Kamerastandort aus in die IMU transformieren und dort dann mit der absoluten Koordinate verknüpfen.
Mein Grundlegendes Problem ist aber immer noch, dass egal in welchem Quadranten ich die Rotation durchführe, ich nie zum gleichen Ergebnis komme wie mit AutoCAD.
Gibt es für die Matrix3D Klasse eine vernünftige Anleitung, was genau bei der Rotation passiert? Klar ich kann im dissasembler nachschauen welche Zellen multipliziert werden, aber ich bin, wie man sicher schon gemerkt hat 😉, kein Mathematiker und kann mir das Modell visuell zwar herleiten, aber sollte es mit einer vernünftigen Matrix abbilden
Vielen Dank für deine Hilfe soweit 😃
lg
OK, sry .. ich versuch's noch mal weniger wirr zu schreiben ^^
Also gegeben ist ein Stereokamerasystem.. Die Parameter besitze ich alle um erfolgreich transformieren zu können (also die Verdrehungen und Transformationen). Und aus dem System messe ich einen relativen Vektor zu einem Objekt.
Achja und ich meine nicht den Algorithmus zur Bestimmung des relativen Vektors aus dem Bild heraus, sondern dieser Vektor ist schon vorhanden, er muß "lediglich" in absolute Weltkoordinaen gebracht werden.
Und die Aufgabe meines Systems wäre die transformation des relativen Vektors zu einer absoluten Koordinate. Wie gesagt die Angaben hab ich alle dafür.
Um zu verdeutlichen, was ich meinte, hab ich im AutoCAD einen Block gezeichnet mit den Maßen 1 / 1 / 1, was einem Vektor 1 / 1 / 1 entspricht. Diesen Block hab ich um die X und dann um die Z Achse um je 10° gedreht und erhalte die oben genannten Werte für die Diagonale des Blocks (also quasi als ob ich den Vektor gedreht hätte) --> 0,8112 / 1,3145 / 0,78636
Das wollte ich 1:1 mittels Matrix3D abbilden, aber irgendwie komm ich nicht auf das gleiche Ergebnis. Ich hab mir schon gedacht, dass es vllt an einem Quadrantenproblem liegt und hab alle Möglichkeiten probiert. Also von 90, 180 und 270 jeweils die 10° dazu oder abgezogen. Das "beste" Ergebnis ist immer noch wenn ich 180 - 10° verwende, nur dann ist x und z gespiegelt negativ --> -0,78636 / 1,3145 / -0,8112
Gibt es für Matrix3D vllt irgendeine genauere Beschreibung außer der MSDN ?
Vielen Dank auf jeden fall schon mal für die Identity Matrix und dem Tipp für die Matrixmultiplikation. Manchmal denk ich einfach zu kompliziert ..
lg
[EDIT]
Wenn ich eine Translation in der Matrix ausführe und nacher den Vektor mit der Matrize multipliziere, wird die Translation nicht berücksichtigt 😦 .. Darum hab ich diesen MatrixTransform3D verwendet .. Warum verwendet der *-operator keine Translation ? Hab per reflector nachgeguckt, er leitet es quasi an die Transform Methode der Matrix3D weiter und die macht einfach keine Translation
Hallo MyCSharp Team,
Zur Zeit arbeite ich mit der Matrix3D und Vector3D Klasse der PresentationCore Library.
Mein Ziel ist eine "echte" Affine Transformation, in der ich auf Basis von relativen Vektoren absolute Koordinaten berechne, indem ich eben die Koordinaten transformiere.
Jetzt ist es aber so, daß ich einfach nicht auf die gleichen Werte wie meine Excel Berechnungen komme. Als Validierung verwende ich AutoCAD. Wenn ich im AutoCAD eine Drehung ausführe, und sie mithilfe der "Rotate" Funktion von Matrix3D nachmache, ist der resultierte Vektor nicht identisch.
Verwende ich die Matrix3D Klasse falsch oder was für Tipps habt ihr für den Umgang damit?
[Edit] Als Beispiel:
Im AutoCAD einen Block, mit
1 / 1 / 1
gezeichnet und ihn nach X um 10° und nach Z um 10° gedreht ergibt:
0,8112 / 1,3145 / 0,78636
In C# hab ich adäquat folgendes versucht:
Matrix3D testMatrix = new Matrix3D();
testMatrix.Rotate(new Quaternion(new Vector3D(1, 0, 0), 10));
testMatrix.Rotate(new Quaternion(new Vector3D(0, 0, 1), 10));
Point3D inputPoint = new Point3D(1, 1, 1);
Point3D outputPoint = new Point3D();
MatrixTransform3D outputTest = new MatrixTransform3D();
outputTest.Matrix = testMatrix;
outputTest.TryTransform(inputPoint, out outputPoint);
Das Ergebnis ist:
0,84395 / 0,97248 / 1,158455
[/Edit]
Vielen Dank
[Edit2]
Oder weiß vllt jemand eine bessere Lösung. Meine grundlegende Aufgabe:
Gegeben ist ein relativer Vektor eines Stereokamerasystems und dieser Vektor muss zum Fixpunkt des Wagens gebracht werden und dann in das Weltkoordinatensystem. Klingt einfach, ist aber aufgrund der verschiedenen Verdrehungen (roll / pitch / heading) nicht so einfach ..
[/Edit2]
lg
Phil