Matrix rotieren
-
Hallo,
Ich habe verschiedene Filtermatritzen (3x3, 5x5, .. NxN). Diese will ich rotieren:
Bsp.:
original: 45° 90°
-1 -2 -1 0 -1 -2 1 0 -1
0 0 0 1 0 -1 2 0 -2
1 2 1 2 1 0 1 0 -1Ich hab mir das mal für 3x3 und 5x5 Matritzen augeschrieben, aber keine allgemeine Formel gefunden, um aus der Position, im Array allgemeingültig die Ziellposition zu bestimmen.
Mit 'ner normalen Rotation habe ich es schon versucht:void CImgProc::Rotate( int iXRot, int iYRot, int iXSrc, int iYSrc, float& fXDest, float& fYDest, int Picture_width, int Picture_height, float phi) { float set_phi = phi * (3.1415926f/180); int iDeltaX = iXSrc - iXRot; int iDeltaY = (iYSrc - iYRot); float fSinPhi = sin(set_phi); float fCosPhi = cos(set_phi); fXDest = (iDeltaX * fCosPhi ) - (iDeltaY * fSinPhi) + iXRot; fYDest = (iDeltaX * fSinPhi ) + (iDeltaY * fCosPhi) + iYRot; }
aber dann kommen einige Matrixelemente spätestens bei der 5x5 - Matrix durch die Ganzzahlrundung aufeinander und andere Stellen bleiben leer.
Danke für eure Hilfe für einen mathematischen Tiefflieger
-
Also 90° ist einfach. Das ist ja quasi nur die Transponierte an der "Seitenkante" gespiegelt.
Bei 45° ist es etwas komplizierter. Da musst du quasi immer einen Rahmen nehmen (also die Elemente die alle den gleichen Abstand vom Element im Zentrum haben) und die Objekte in dem Rahmen herumschieben.
Bei deinem Beispiel:
äußeren Rahmen rausschrieben
-1 -2 -1 0 1 2 1 0
eins hinten weg nehmen und vorne ran schieben...
0 -1 -2 -1 0 1 2 1
und zurückschreibenWieviele Elemente du wegnehmen und vorne ranschieben muss ist von der Dimensionierung des Rahmens abhängig.
Alle anderen "Rotationen" kannst du als Kombinationen aus 45° und 90° Rotationen darstellen, falls es keine feineren Zwischenschritte geben soll.
-
Danke,
genau das 45° Problem ist bei mir auch aufgetaucht und das mit dem Abstand hab ich soweit auch rausgefunden:
Die Verschiebung in den einzelnen Bändern ist demnach Gleich dem Abstand von der Mitte. Außerem ist logischerweise das ganze insgesamt symetrisch zur Mitte -> d.h. die Verschiebungsfaktoren werden ab dem Mittenindex einfach nur negativ umgekehrt.
Das mit dem Verschieben in den Bändern ist schon simpel. Die Problematik liegt dann eher im Bänderweisen "aufdröseln" der Matrix bzw. dem anschließenden Zurückschreiben nach der Verschiebung. (ich mach mich schonmal an die Arbeit )
Trotzdem würde mich ein allgemeiner Algo dafür interessieren. Anscheinend scheint es ja doch in jedem Band eine wiederkehrende Regel für die Positionsänderung zu geben -> ergo soltte es mit einem Algo zu beschreiben sein.
-
Ich habs jetzt hingebastelt (im wahrsten Sinne des Wortes ). Es ist ein
ziemlick häßliches Konstrukt aus -zig Schleifen geworden, in dem ich die Matrix in die einzelnen "Bänder" abwickel, verschiebe und dann wieder zusammenrolle.
Der Code ist so häßlich (und dementsprechend groß), das ich ihn hier nicht zur Schau stellen werde :).Danke @Walli :
ohne Deinen Post würde ich wohl jetzt noch nach 'ner formalen Beschreibung suchen
Wer jetzt noch 'ne schöne Lösung hat kann sie posten und mich ärgern :p
-
@TheBigW: poste mal deinen code, der würd mich trotzdem interessieren obwohl er lang ist....
thx+cu
-
such dir doch ein Algo zum bilder drehen. möglichst einen mit subpixeling.
die laufen über die Zielmatrix rechnen die Lage in der alten matrix und interpolieren danach bilinear den Wert über die nachbarn.
-
@paule1
naja, im Prinzip sind es zwei funktionen: eine, die die einzelnen "Bänder" einliest und wieder schreibt und eine, die den shift macht, so wie es Walli schon erklärt hat.
Die Lese/Schreib - Funktion ist im Prinzip der schwerste Part, da links, oben, rechts und unten seperat behandelt werden müssen. Ich werd ihn bei gelegenheit mal posten (wenn ich ihn zumindest kommentiert habe ).Beim interpolieren kommt am ende trotzdem nicht genau das raus, was dem rotierten Filter entspricht, da ja Positionen, die normalerweise einen exakten Wert haben sollten eine bessere "Rundung" zugewiesen bekommen. Interploation ist doch grob betrachtet auch nur ein besseres Wort für "Ergebnis hinmogeln", auch wenn es für den von Dir genannten Anwendungsfall (und Rotationen) doch gute Ergebnisse liefert.
Genau gesagt Interpolation kommt dicht ran, trifft es aber nicht genau .
-
wenn du die Matrix schon als mathematische Funktion hast, dann kannst du eigentlich direkt das Koordinatensystem wechsel.
x'=x*cos(arc)-y*sin(arc)
y'=x*sin(arc)+y*cos(arc)
zB
v=-y^2;
x=-1 .. 1;
y=-1 .. 1;
für so eine matrix-1 0 -1 -1 0 -1 -1 0 -1
v'= -(x*sin(arc)+y*cos(arc))^2
bei Rotation um 45°
sin45=cos45= 0,5sqrt(2);
sin(45)^2=0,252=0,5;
eingesetzt
v'= - 0,5*(x+y)^2-0,5*(-1+1)^2, -0,5*(0+1)^2, -0,5*(1+1)^2 -0,5*(-1+0)^2, -0,5*(0+0)^2, -0,5*(1+0)^2 -0,5*(-1-1)^2, -0,5*(0-1)^2, -0,5*(1-1)^2 0,0 -0,5 -2,0 -0,5 0,0 -0,5 -2,0 -0,5 0,0
Btw.
v=x2+y2 braucht man nicht zu drehen da die Funktion Rotationssymetrisch ist...
das heißt
v=2 - x^2 - y^20 1 0 1 2 1 0 1 0
wird nach einer Drehung nicht zu
1 0 1 0 2 0 1 0 1
das ist zb die funktion
v=2-x^2 + y^2 + x2*y2wenn keine mathematische Formulierung da ist, kann man bei einer 3x3 Matrix ein Polynom ansetzen
v=a_1 + a_2*x + a_3*y ++ a_4*x*y + a_5*x^2 + a_6*y^2 + a_7*x^2*y +a_8*x*y^2 +a_7*x2*y2
das macht 9 Gleichungen für 9 unbekannte...
und wenn es dir Spass macht kannst du auch noch einen Term für die Funktionsfläche ansetzen den du dann minimierst, ansonsten hat man etwas Probleme beim Funktionsverlauf zwischen den Stützstellen.