[gelöst] Bildrotation grafischer Fehler
-
Hi,
ich schreibe mir gerade selbst ein paar kleine Grafikfunktionen für SDL. Ich habe eine Funktion die Bilder skaliert und das Resultat wieder zentriert abspeichert. Diese Funktion funktioniert einwandfrei. Anschließend habe ich eine Funktion für das Rotieren von Bildern geschrieben. Diese funktionierte auch auf Anhieb, allerdings enthielten die rotierten Bilder jede Menge unbefüllter Pixel, in denen man den Hintergrund gesehen hat. Dies habe ich auf einen Rundungsfehler bei der Koordinatenbestimmung zurückgeführt und die Rotationsfunktion auf Anti-Aliasing umgeschrieben, so dass jeder Pixel auf vier Pixel je nach seiner genauen Koordinate aufgeteilt wird. Doch nun ist das Bild einfach mit der Hintergrundfarbe verfärbt, was optisch kaum anders als die Durchsetzung mit den Hintergrundpixeln wirkt. irgendwie hat das ganze immer das Aussehen eines nicht rotierten Schottenrocks^^.
Ich bin alles durchgegangen und finde keine Quelle für Rundungsfehler oder ähnliches. Kann mir jemand sagen, wo hier etwas nicht passt?Ich stelle es nun so um, dass Anti-Aliasing nur stattfindet, wenn ein Pixel schon eingefärbt wurde und dass der pixel sonst komplett überschrieben wird. Aber selbst wenn dies reicht, um die Lücken im Bild zu stopfen, haben die Kanten dann Pixelstufen und kein AA mehr. Also ich wäre echt dankbar, wenn jemand meinen Fehler findet.
//setpixel und getpixel sind von mir definierte Funktionen
void RotateBMP(SDL_Surface *bmpsmall, int SizeX, int SizeY, bool center, double Angle, int R[640][480], int G[640][480], int B[640][480], int A[640][480]) { //Winkel in Bogenmaß umrechnen Angle = Angle * 3.14159/180; //Alle Pixel auslesen Uint8 r, g, b, a = 0; for(int x = 0; x < bmpsmall->w; x++) { for(int y = 0; y < bmpsmall->h; y++) { getcolor(bmpsmall, x, y, r, g, b, a); R[x][y] = r; G[x][y] = g; B[x][y] = b; A[x][y] = a; } } //Ebene leeren SDL_FillRect(bmpsmall, 0, SDL_MapRGB(bmpsmall->format, 0, 0, 0)); //Jeden einzelnen Pixel um Mittelpunkt drehen und einfügen double PosX, PosY, RotX, RotY = 0; //Wenn Bild auf SDL_Surface zentriert ist diese Berechnung, sonst die Zweite if(center) { for(int x = (bmpsmall->w-SizeX)/2; x < SizeX+(bmpsmall->w-SizeX)/2; x++) { for(int y = (bmpsmall->h-SizeY)/2; y < SizeY+(bmpsmall->h-SizeY)/2; y++) { //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; //(bmpsmall->w-SizeX)/2 PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Koordinaten auf Bildmitte von Surface beziehen //Erster Schritt, wieder auf ursprüngliche Koordinaten beziehen PosX = RotX + bmpsmall->w/2; PosY = RotY + bmpsmall->h/2; //Punkt mit AA speichern (zwischen je zwei X und Y Koordinaten) //X/Y-Werte und Faktor bestimmen int X1, X2, Y1, Y2 = 0; //Faktoren für jedes der vier Pixelfelder double Fak1, Fak2, Fak3, Fak4 = 0; /* Struktur: 1 | 2 ----- 4 | 3 */ //Schneidet beim konvertieren Kommastellen einfach ab X1 = PosX; X2 = X1+1; Y1 = PosY; Y2 = Y1+1; //Pixelfeldfaktoren bestimmen Fak1 = 1.0-(PosX - X1); //X Fak1 *= 1.0-(PosY - Y1); //kombiniert mit Y Fak2 = PosX - X1; //X Fak2 *= 1.0-(PosY - Y1); //kombiniert mit Y Fak3 = PosX - X1; //X Fak3 *= PosY - Y1; //kombiniert mit Y Fak4 = 1.0-(PosX - X1); //X Fak4 *= PosY - Y1; //kombiniert mit Y Uint8 URot, UGruen, UBlau, UAlpha = 0; double dR, dG, dB, dA = 0; //Farbe von X1/Y1 auslesen getcolor(bmpsmall, X1, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak1) + R[x][y]*Fak1; UGruen = dG*(1-Fak1) + G[x][y]*Fak1; UBlau = dB*(1-Fak1) + B[x][y]*Fak1; UAlpha = dA*(1-Fak1) + A[x][y]*Fak1; setcolor(bmpsmall, X1, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y1 auslesen getcolor(bmpsmall, X2, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak2) + R[x][y]*Fak2; UGruen = dG*(1-Fak2) + G[x][y]*Fak2; UBlau = dB*(1-Fak2) + B[x][y]*Fak2; UAlpha = dA*(1-Fak2) + A[x][y]*Fak2; setcolor(bmpsmall, X2, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y2 auslesen getcolor(bmpsmall, X2, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak3) + R[x][y]*Fak3; UGruen = dG*(1-Fak3) + G[x][y]*Fak3; UBlau = dB*(1-Fak3) + B[x][y]*Fak3; UAlpha = dA*(1-Fak3) + A[x][y]*Fak3; setcolor(bmpsmall, X2, Y2, URot, UGruen, UBlau, UAlpha); //Farbe von X1/Y2 auslesen getcolor(bmpsmall, X1, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak4) + R[x][y]*Fak4; UGruen = dG*(1-Fak4) + G[x][y]*Fak4; UBlau = dB*(1-Fak4) + B[x][y]*Fak4; UAlpha = dA*(1-Fak4) + A[x][y]*Fak4; setcolor(bmpsmall, X1, Y2, URot, UGruen, UBlau, UAlpha); /*URot = R[x][y]; UGruen = G[x][y]; UBlau = B[x][y]; UAlpha = A[x][y]; setcolor(bmpsmall, X1, Y1, URot, UGruen, UBlau, UAlpha);*/ } } } else { for(int x = 0; x < SizeX; x++) { for(int y = 0; y < SizeY; y++) { //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - SizeX/2; PosY = y - SizeY/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Koordinaten auf Bildmitte von Surface beziehen //Erster Schritt, wieder auf ursprüngliche Koordinaten beziehen PosX = RotX + SizeX/2; PosY = RotY + SizeY/2; //Zweiter Schritt, auf Mitte verschieben PosX = PosX + SizeX/2; PosY = PosY + SizeY/2; //Punkt mit AA speichern (zwischen je zwei X und Y Koordinaten) //X/Y-Werte und Faktor bestimmen int X1, X2, Y1, Y2 = 0; //Faktoren für jedes der vier Pixelfelder double Fak1, Fak2, Fak3, Fak4 = 0; /* Struktur: 1 | 2 ----- 4 | 3 */ //Schneidet beim konvertieren Kommastellen einfach ab X1 = PosX; X2 = X1+1; Y1 = PosY; Y2 = Y1+1; //Pixelfeldfaktoren bestimmen Fak1 = 1-(PosX - X1); //X Fak1 *= 1-(PosY - Y1); //kombiniert mit Y Fak2 = PosX - X1; //X Fak2 *= 1-(PosY - Y1); //kombiniert mit Y Fak3 = PosX - X1; //X Fak3 *= PosY - Y1; //kombiniert mit Y Fak4 = 1-(PosX - X1); //X Fak4 *= PosY - Y1; //kombiniert mit Y Uint8 URot, UGruen, UBlau, UAlpha = 0; double dR, dG, dB, dA = 0; //Farbe von X1/Y1 auslesen getcolor(bmpsmall, X1, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak1) + R[x][y]*Fak1; UGruen = dG*(1-Fak1) + G[x][y]*Fak1; UBlau = dB*(1-Fak1) + B[x][y]*Fak1; UAlpha = dA*(1-Fak1) + A[x][y]*Fak1; setcolor(bmpsmall, X1, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y1 auslesen getcolor(bmpsmall, X2, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak2) + R[x][y]*Fak2; UGruen = dG*(1-Fak2) + G[x][y]*Fak2; UBlau = dB*(1-Fak2) + B[x][y]*Fak2; UAlpha = dA*(1-Fak2) + A[x][y]*Fak2; setcolor(bmpsmall, X2, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y2 auslesen getcolor(bmpsmall, X2, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak3) + R[x][y]*Fak3; UGruen = dG*(1-Fak3) + G[x][y]*Fak3; UBlau = dB*(1-Fak3) + B[x][y]*Fak3; UAlpha = dA*(1-Fak3) + A[x][y]*Fak3; setcolor(bmpsmall, X2, Y2, URot, UGruen, UBlau, UAlpha); //Farbe von X1/Y2 auslesen getcolor(bmpsmall, X1, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak4) + R[x][y]*Fak4; UGruen = dG*(1-Fak4) + G[x][y]*Fak4; UBlau = dB*(1-Fak4) + B[x][y]*Fak4; UAlpha = dA*(1-Fak4) + A[x][y]*Fak4; setcolor(bmpsmall, X1, Y2, URot, UGruen, UBlau, UAlpha); /*URot = R[x][y]; UGruen = G[x][y]; UBlau = B[x][y]; UAlpha = A[x][y]; if(PosX > 640 || PosY > 480 || PosX < 0 || PosY < 0) {} else { setcolor(bmpsmall, PosX, PosY, URot, UGruen, UBlau, UAlpha); }*/ } } } }
-
Du transformierst die Position jedes Pixelzentrums des Quellbildes in das Zielbild.
Dadurch werden zwangslaeufig Punkte auf den gleichen Zielpixel abgebildet und entsprechend viele Pixel bleiben leer.
Bilde stattdessen per inverser Transformation alle Zielpixel in das Quellbild ab.
-
Aber wieso landen die Pixel des Quellbilds auf den selben Koordinaten? Und müsste das bei einer inversen Transformation nicht auch passieren? Vor allem müsste ich erst bestimmen, welche Pixel zu einem rotierten Bild gehören, bevor ich sie invers Pixeln des Quellbildes zuweisen kann. Klingt für mich irgendwie umständlich und unbegreiflich. Da dieser Fehler, das Löcher im Bild auftreten ja auch auftreten müsste, wenn ich die Pixel des Zielbildes drehe. Wird ja exakt das gleiche gemacht.
-
Aber wieso landen die Pixel des Quellbilds auf den selben Koordinaten?
Weil Du nur das Pixelzentrum transformierst und nicht die gesamte Pixelflaeche.
Und müsste das bei einer inversen Transformation nicht auch passieren?
Nein, weil Du dann ja auf jeden Pixel des Zielbildes einen Pixel des Quellbildes setzt.
-
Little Programmer schrieb:
Vor allem müsste ich erst bestimmen, welche Pixel zu einem rotierten Bild gehören, bevor ich sie invers Pixeln des Quellbildes zuweisen kann.
Jetzt musst du fuer jeden Pixel des Quellbildes testen, ob er nach der Rotation im Zielbild liegt - na und?
hellihjb schrieb:
Und müsste das bei einer inversen Transformation nicht auch passieren?
Nein, weil Du dann ja auf jeden Pixel des Zielbildes einen Pixel des Quellbildes setzt.
Doch das passiert dann genauso. Es wird einige Pixel aus dem Quellbild geben, die auf mehrere Pixel abgebildet werden. Es wird einige Pixel aus dem Quellbild geben, die auf ueberhaupt keinen Pixel abgebildet werden. Der Vorteil ist nur, das die Loecher jetzt im Quellbild sind, und das wird nicht angezeigt - darum faellt es weniger auf. f'`8k
AutocogitoGruß, TGGC (Was Gamestar sagt...)
-
Wenn du ein Bild rotierst und das Bild nicht gerade exakt rund ist, fehlen da am Ende zwangsläufig die Ecken bei ungünstigen Winkeln, oder du machst das Zielbild größer und hast leere Bereiche.
Irgendwie erinnert mich das fast schon an Sampeln von Texturen was du vorhast.
-
Ich habe jetzt das Programm so umgeschrieben, dass es nur drei Eckpunkte dreht, und dann daraus die positionen der restlichen Pixel im gedrehten Bild möglichst ohne Rundungen an irgendeiner Stelle berechnet. Das Resultat ist trotzdem noch exakt das Alte.
Neuer Quelltext (nur der Part mit dem Drehen, die Pixelfarben vom Quellbild sind schon ausgelesen):
//Rotationsvariablen erstellen double PosX, PosY, RotX, RotY = 0; double Punkt1X, Punkt1Y, Punkt2X, Punkt2Y, Punkt3X, Punkt3Y = 0; //Drei Eckpunkte drehen if(center) { int x, y = 0; //Erster Eckpunkt, 0|0 x = (bmpsmall->w-SizeX)/2; y = (bmpsmall->h-SizeY)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt1X = RotX + bmpsmall->w/2; Punkt1Y = RotY + bmpsmall->h/2; //Zweiter Eckpunkt, SizeX|0 x = SizeX + (bmpsmall->w-SizeX)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt2X = RotX + bmpsmall->w/2; Punkt2Y = RotY + bmpsmall->h/2; //Dritter Eckpunkt, 0|SizeY x = (bmpsmall->w-SizeX)/2; y = SizeY + (bmpsmall->h-SizeY)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt3X = RotX + bmpsmall->w/2; Punkt3Y = RotY + bmpsmall->h/2; //Entfernungen bestimmen double EntfX1, EntfY1, EntfX2, EntfY2 = 0; EntfX1 = Punkt2X - Punkt1X; EntfY1 = Punkt2Y - Punkt1Y; EntfX2 = Punkt3X - Punkt1X; EntfY2 = Punkt3Y - Punkt1Y; //Punkt übertragen for(int x = (bmpsmall->w-SizeX)/2; x < SizeX+(bmpsmall->w-SizeX)/2; x++) { for(int y = (bmpsmall->h-SizeY)/2; y < SizeY+(bmpsmall->h-SizeY)/2; y++) { //Punkt verschieben double Temp = (bmpsmall->w-SizeX); Temp /= 2; double TempX = x; Temp = TempX - Temp; //double Temp = x-(bmpsmall->w-SizeX)/2; <- rundet double Temp2 = (bmpsmall->h-SizeY); Temp2 /= 2; double TempY = y; Temp2 = TempY - Temp2; //double Temp2 = y-(bmpsmall->h-SizeY)/2; <- rundet PosX = Punkt1X + Temp/SizeX*EntfX1; PosX += Temp2/SizeY*EntfX2; PosY = Punkt1Y + Temp/SizeX*EntfY1; PosY += Temp2/SizeY*EntfY2; //Punkt mit AA speichern (zwischen je zwei X und Y Koordinaten) //X/Y-Werte und Faktor bestimmen int X1, X2, Y1, Y2 = 0; //Faktoren für jedes der vier Pixelfelder double Fak1, Fak2, Fak3, Fak4 = 0; /* Struktur: 1 | 2 ----- 4 | 3 */ //Schneidet beim konvertieren Kommastellen einfach ab X1 = PosX; X2 = X1+1; Y1 = PosY; Y2 = Y1+1; //Pixelfeldfaktoren bestimmen Fak1 = 1.0-(PosX - X1); //X Fak1 *= 1.0-(PosY - Y1); //kombiniert mit Y Fak2 = PosX - X1; //X Fak2 *= 1.0-(PosY - Y1); //kombiniert mit Y Fak3 = PosX - X1; //X Fak3 *= PosY - Y1; //kombiniert mit Y Fak4 = 1.0-(PosX - X1); //X Fak4 *= PosY - Y1; //kombiniert mit Y Uint8 URot, UGruen, UBlau, UAlpha = 0; double dR, dG, dB, dA = 0; //Farbe von X1/Y1 auslesen getcolor(bmpsmall, X1, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak1) + R[x][y]*Fak1; UGruen = dG*(1-Fak1) + G[x][y]*Fak1; UBlau = dB*(1-Fak1) + B[x][y]*Fak1; UAlpha = dA*(1-Fak1) + A[x][y]*Fak1; setcolor(bmpsmall, X1, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y1 auslesen getcolor(bmpsmall, X2, Y1, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak2) + R[x][y]*Fak2; UGruen = dG*(1-Fak2) + G[x][y]*Fak2; UBlau = dB*(1-Fak2) + B[x][y]*Fak2; UAlpha = dA*(1-Fak2) + A[x][y]*Fak2; setcolor(bmpsmall, X2, Y1, URot, UGruen, UBlau, UAlpha); //Farbe von X2/Y2 auslesen getcolor(bmpsmall, X2, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak3) + R[x][y]*Fak3; UGruen = dG*(1-Fak3) + G[x][y]*Fak3; UBlau = dB*(1-Fak3) + B[x][y]*Fak3; UAlpha = dA*(1-Fak3) + A[x][y]*Fak3; setcolor(bmpsmall, X2, Y2, URot, UGruen, UBlau, UAlpha); //Farbe von X1/Y2 auslesen getcolor(bmpsmall, X1, Y2, r, g, b, a); dR = r; dG = g; dB = b; dA = a; URot = dR*(1-Fak4) + R[x][y]*Fak4; UGruen = dG*(1-Fak4) + G[x][y]*Fak4; UBlau = dB*(1-Fak4) + B[x][y]*Fak4; UAlpha = dA*(1-Fak4) + A[x][y]*Fak4; setcolor(bmpsmall, X1, Y2, URot, UGruen, UBlau, UAlpha); } } } else { //fehlt }
Hier ich habe das Resultat mal hochgeladen, vielleicht hilfts jemandem weiter. Wie gesagt, es ist ein völlig gleichmäßiges Muster:
http://img341.yfrog.com/img341/8889/grafikfehler.png
EDIT: Jetzt probiere ich mal diese Rückwärtsmethode. Vielleicht ist die ja erfolgreicher.
-
Kann es sein, dass das rotierte Bild mehr Pixel als das Quellbild besitzt?
Ich wollte gerade mit der invertierten Form beginnen, bei der ich Zielkoordinaten koordinaten im Quellbild zuweise. Dazu wollte ich die Zielkoordinaten wie im letzten geposteten Quelltext berechnen, also so:
//Rotationsvariablen erstellen double PosX, PosY, RotX, RotY = 0; double Punkt1X, Punkt1Y, Punkt2X, Punkt2Y, Punkt3X, Punkt3Y = 0; //Drei Eckpunkte drehen if(center) { int x, y = 0; //Erster Eckpunkt, 0|0 x = (bmpsmall->w-SizeX)/2; y = (bmpsmall->h-SizeY)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt1X = RotX + bmpsmall->w/2; Punkt1Y = RotY + bmpsmall->h/2; //Zweiter Eckpunkt, SizeX|0 x = SizeX + (bmpsmall->w-SizeX)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt2X = RotX + bmpsmall->w/2; Punkt2Y = RotY + bmpsmall->h/2; //Dritter Eckpunkt, 0|SizeY x = (bmpsmall->w-SizeX)/2; y = SizeY + (bmpsmall->h-SizeY)/2; //Koordinaten auf Bildmitte als Nullpunkt beziehen PosX = x - bmpsmall->w/2; PosY = y - bmpsmall->h/2; //Rotieren, dabei ist Bildmitte Nullpunkt RotX = PosX * cos(Angle) + PosY * sin(Angle); RotY = -PosX * sin(Angle) + PosY * cos(Angle); //Wieder auf ursprüngliche Koordinaten beziehen Punkt3X = RotX + bmpsmall->w/2; Punkt3Y = RotY + bmpsmall->h/2; //Entfernungen bestimmen double EntfX1, EntfY1, EntfX2, EntfY2 = 0; EntfX1 = Punkt2X - Punkt1X; EntfY1 = Punkt2Y - Punkt1Y; EntfX2 = Punkt3X - Punkt1X; EntfY2 = Punkt3Y - Punkt1Y; //Punkt übertragen for(int x = (bmpsmall->w-SizeX)/2; x < SizeX+(bmpsmall->w-SizeX)/2; x++) { for(int y = (bmpsmall->h-SizeY)/2; y < SizeY+(bmpsmall->h-SizeY)/2; y++) { //Punkt verschieben double Temp = (bmpsmall->w-SizeX); Temp /= 2; double TempX = x; Temp = TempX - Temp; double Temp2 = (bmpsmall->h-SizeY); Temp2 /= 2; double TempY = y; Temp2 = TempY - Temp2; PosX = Punkt1X + Temp/SizeX*EntfX1; PosX += Temp2/SizeY*EntfX2; PosY = Punkt1Y + Temp/SizeX*EntfY1; PosY += Temp2/SizeY*EntfY2; Uint8 R = 255; Uint8 G = 255; Uint8 B = 255; Uint8 A = 255; setcolor(bmpsmall, PosX, PosY, R, G, B, A); } } }
Und hier das Resultat:
http://img231.imageshack.us/img231/9638/grafikfehler2.png
Obwohl es jetzt kein AA hat und nur die Positionen der Pixelzentren zeigt, sieht man gleich wieder das Muster im Bild. Wie soll ich denn selbst invertiert die Zielpixel dem Quellbild zuweisen, wenn jede Methode die Zielpixel zu ermitteln immer diese Löcher hat? Da hab ich ja dann das gleiche Problem wie umgekehrt.
-
Blaze schrieb:
Irgendwie erinnert mich das fast schon an Sampeln von Texturen was du vorhast.
Das ist das Sampeln von Texturen. Die Textur (Bild) wird mit einer Matrix (Rotationsmatrix) auf ein Polygon (rotiertes Bild) projeziert. Es gibt da nicht so viel Mathematik dahinter. f'`8k
Gruß, TGGC (Was Gamestar sagt...)
-
ja, mathematisch müsste ja auch sowohl meine erste, wie auch meine zweite Möglichkeit funktionieren. Meine Frage ist ja, warum tun es beide auf die selbe Weise nicht?
-
Little Programmer schrieb:
ja, mathematisch müsste ja auch sowohl meine erste, wie auch meine zweite Möglichkeit funktionieren. Meine Frage ist ja, warum tun es beide auf die selbe Weise nicht?
Weil sie mathematisch gesehen nicht funktioniert. Wenn z.b. die Matrix eine Streckung enthielte, dann wuerde eine Textur mit 4x4 Pixel auf dem Bildschirm 20x20 Pixel einnehmen - deine tolle Methode wuerde aber statt 400 Pixeln nur 16 zeichnen. Und da fragst du noch, wo die Loecher herkommen? f'`8k
Gruß, TGGC (Was Gamestar sagt...)
-
obwohl die sache mathematisch natuerlich funktioniert und richtig sein wuerde, rechnest du hier leider nicht mit unendlicher genauigkeit, sondern mit pixel-einheiten, beim rotieren wirst du also immer von float auf int runden und dabei dabei werden an manchen stellen pixel zusammenfallen und die fehlen dann an anderen stellen.
die transformation inverse zu machen, also fuer das ziel die passenden quell-pixel suchen verhindert dass du luecken hast, aber es wird bei der rotation dennoch vorkommen, dass dafuer manche pixel aus dem quell-bild garnicht vorkommen, jedoch faellt das weniger auf.
-
rapso schrieb:
obwohl die sache mathematisch natuerlich funktioniert und richtig sein wuerde, rechnest du hier leider nicht mit unendlicher genauigkeit, sondern mit pixel-einheiten
Es ist ja nicht so, das die Mathematik im Computer nicht definiert waere und dann irgendwelche zufaelligen Fehler entstehen. Diese Fehler existieren nicht nur praktisch, sie ergeben sich schon im theoretischen Modell, mit dem der Computer arbeitet. Der Computer verpasst nicht irgendwelche Pixel, weil er falsch gerundet hat. Er hat natuerlich immer korrekt gerundet, ansonsten waere er defekt und nicht zu gebrauchen. Der Fehler liegt an der Stelle wo jemand dilletantisch versucht affine Transformationen in einem Computerprogramm umzusetzen. f'`8k
Gruß, TGGC (Was Gamestar sagt...)
-
TGGC schrieb:
rapso schrieb:
obwohl die sache mathematisch natuerlich funktioniert und richtig sein wuerde, rechnest du hier leider nicht mit unendlicher genauigkeit, sondern mit pixel-einheiten
Es ist ja nicht so, das die Mathematik im Computer nicht definiert waere und dann irgendwelche zufaelligen Fehler entstehen.
Ja, dann solltest du lieber darauf bezug nehmen statt zu behaupten etwas funktioniert schon rein mathematisch nicht.
Diese Fehler existieren nicht nur praktisch, sie ergeben sich schon im theoretischen Modell, mit dem der Computer arbeitet. Der Computer verpasst nicht irgendwelche Pixel, weil er falsch gerundet hat. Er hat natuerlich immer korrekt gerundet, ansonsten waere er defekt und nicht zu gebrauchen.
Ich sehe du hast meinen text sehr schnell aufgefasst.
Der Fehler liegt an der Stelle wo jemand dilletantisch versucht affine Transformationen in einem Computerprogramm umzusetzen.
Ja, jeder ist irgendwo dillenantisch. Traurig wird es wenn jemand auf seinem niveau stehen bleibt, da warst du gerade echt vorbildlich.
-
Nach deiner Logik funktioniert ein Computer an sich schon rein mathematisch nicht. Das ist aber Quatsch. Er kann halt keine natuerlichen Zahlen oder reelen Zahlen, aber er hat ein anderes mathematisches Modell. Und dieses Modell ist in sich schluessig und funktioniert auch korrekt. Mit dieser Mathematik funktionieren einige Sache und andere nicht.
Aber da du ehh schon wieder auf deinen ich bin Mod und habe eh recht Trip bist - Guten Tag. f'`8k
Gruß, TGGC (Was Gamestar sagt...)
-
@ rapso und @ TGGC, sorry das ich das jetzt sagen muss, aber ihr habt mal total am Thema vorbeigeschrieben.
@ TGGC, wie kommst du bitte schön auf die Idee, dass ich das Bild strecken würde? Das Ziel- und Quellbild sind gleich groß. es war nirgends von einer Streckung die Rede.
@ rapso, wie ich glaube ich schon mehrmals hier im Topic geschrieben habe und wie es auch auffällig in der Hälfte des Quelltextes steht, runde ich meine Koordinaten nicht sondern nutze oversampling, um Pixel über mehrere pixel verteilt an der Korrekten Stelle anzuzeigen. Generell ist die gesamte Berechnung möglichst rundungsfrei auf doubles beschränkt, damit keine Rundungsfehler irgendeiner Form auftreten.Invers tranformieren funktioniert aus den selben Fehlern wie die andere nicht, da im Zielbild bei den aktuellen beiden Berechnungsarten Pixel fehlen, daran würde sich dann gar nichts ändern. Ich versuche nun eine dritte Berechnungsart und bedanke mich hier erstmal für die Hilfe und erkläre das Thema für gelöst. Neue Erkenntnisse kommen hier wohl nicht mehr zustande.
-
Little Programmer schrieb:
Invers tranformieren funktioniert aus den selben Fehlern wie die andere nicht, da im Zielbild bei den aktuellen beiden Berechnungsarten Pixel fehlen, daran würde sich dann gar nichts ändern.
das ist nicht moeglich, man setzt pixel fuer pixel, wie soll da ein pixel fehlen?
-
Little Programmer schrieb:
Invers tranformieren funktioniert aus den selben Fehlern wie die andere nicht, da im Zielbild bei den aktuellen beiden Berechnungsarten Pixel fehlen, daran würde sich dann gar nichts ändern. Ich versuche nun eine dritte Berechnungsart und bedanke mich hier erstmal für die Hilfe und erkläre das Thema für gelöst. Neue Erkenntnisse kommen hier wohl nicht mehr zustande.
Natürlich funktioniert invers transformieren.
Und ganz egal ob du mit Nearest-Pixel Filter oder Bilinear/Qubisch/... arbeitest, wenn du vom rotierten Bild auf das Original zurückrechnest hast du keinen Schottenrock mehr.
Probier's einfach mal aus.
-
Habe eine andere Lösung gefunden, die das Bild fehlerfrei rotiert. Einmal habe ich eine Rechenleistung sparende Drehberechnung, welche nur einen einzigen Punkt drehen muss und aus dem Drehwinkel und der Position dieses Pixels die Positionen der anderen Pixel berechnet. Und zweitens fiel mir ein simpler aber funktionierender Trick ein.
//PosX und PosY sind doubles und enthalten nun schon die Koordinaten des neuen Pixels //Punkt PrintAA(bmpsmall, PosX, PosY, x, y, R, G, B, A); //Ein Viertel weiter PosX += 0.25; PosY += 0.25; PrintAA(bmpsmall, PosX, PosY, x, y, R, G, B, A); //Eine Hälfte weiter PosX += 0.25; PosY += 0.25; PrintAA(bmpsmall, PosX, PosY, x, y, R, G, B, A); //Drei Viertel weiter PosX += 0.25; PosY += 0.25; PrintAA(bmpsmall, PosX, PosY, x, y, R, G, B, A);
Durch dieses Weiterrücken fülle ich den Leerraum zwischen zwei Pixeln vollständig auf. Alle 0.25-Pixel wird nun ein Punkt gesetzt. Auch wenn jeder Punkt so viermal gesetzt wird, wieht man dies im Endbild nicht. Dies ist nun perfekt farbecht mit Oversampling gedreht.
-
Brillant!
-
@Little Programmer:
Das meinst du jetzt hoffentlich nicht ernst...?