Go Down

Topic: Mathe- oder Codeproblem? (Read 565 times) previous topic - next topic

Helmuth

Hi, LED Matrix mal wieder und eigentlich ein einfaches Problem...

Ich will den Inhalt eines Rechtecks in ein (nicht überlappendes) zweites Rechteck hineinskalieren (vergrößern/verkleinern/verzerren).

Gegeben sind 8 Werte:
x und y von Quellrechteck und Zielrechteck jeweils Punkt oben links und Punkt unten rechts.

x0, y0 und x1, y1 definieren die Quelle;
x2, y2 und x3, y3 definieren das Ziel.

Lösungsidee:

1. Länge und Breite des Ziels ermitteln, 2 verschachtelte for-Schleifen, um jeden Punkt des Ziels anzusprechen.
2. proportional entsprechenden Punkt aus der Quelle suchen und Inhalt ins Ziel kopieren.

Lösung dafür (Betrachtung nur x-Achse):
Länge Ziel/aktueller x Wert im Ziel = Länge Quelle/gesuchten Punkt

Umgestellt: gesuchter Punkt = ((x1-x0) * x)/(x3-x2)

Komplett in Code:
Code: [Select]
void Scale(byte x0, byte y0, byte x1, byte y1, byte x2, byte y2 ,byte x3, byte y3) {
   for(int y = y2; y < y3+1; y++) {
    for(int x = x2; x < x3+1; x++) {
      leds[XY(x,y)] = leds[XY(
        x0 + ( x * ( (x1-x0) / (x3-x1) ) ),
        y0 + ( y * ( (y1-y0) / (y3-y1) ) ) )];
    }
  }
}


Funktioniert aber nicht.

Jemand 'ne Idee, wo der Fehler liegt, oder wie man es  besser macht?

Helmuth


udoklein

Das Problem ist, daß Du mit Bytes rechnest. D.h. die Multiplikation bringt Dich vermutlich aus dem Zahlenbereich raus und die Division liefert dann nur noch Müll.

Schritt 1: Die Werte auf uint16_t casten.
Schritt 2: Falls das nicht das gewünschte Ergebnis liefert nochmal genau beschreiben wozu Du das genau brauchst.
Check out my experiments http://blog.blinkenlight.net

jurs


Funktioniert aber nicht.

Jemand 'ne Idee, wo der Fehler liegt, oder wie man es  besser macht?


Wenn Du das Rechteck nicht entweder 1:1 kopierst oder mit einer ganzen Zweierpotenz in einer Achsenrichtung skalierst, gibt es keine 1:1 Entsprechung zwischen einem LED-Punkt der Quelle zu einem LED-Punkt im Ziel.

Das einzige, was Du dann direkt übernehmen kannst, sind die vier Eckpunkte (links/oben, rechts/oben, links/unten, rechts/unten), die im Zielrechteck genau so aussehen wie im Quellrechteck.

Alle anderen LED-Punkte des Zielrechtecks sitzen quasi irgendwo "zwischen" den LEDs des Quellrechtecks. Und in das Zielrechteck müßtest Du einen interpolierten Wert aus vier LEDs des Quellrechtecks übernehmen.

Das Verfahren, um aus vier umgebenden Werten den Wert eines virtuellen Zwischenwertes zu ermitteln, nennt sich bilineare Interpolation, also lineare Interpolation in zwei Richtungen (x und y):
http://de.wikipedia.org/wiki/Bilineare_Filterung

Helmuth

#3
Jun 28, 2014, 12:44 pm Last Edit: Jun 28, 2014, 12:46 pm by Helmuth Reason: 1
@Udo: Danke für den Hinweis, jetzt macht die Funktion, was sie soll.

@jurs: Ja, "schön" ist das Ergebnis nicht, aber dafür schnell...

Für Effekte reicht es mir im Moment. Natürlich hast Du Recht, dass für schickere Ergebnisse zw. vergrößern und verkleinern unterschieden werden muss und bei ersterem interpoliert/gedithert werden sollte, bei letzterem eine gewichtete Mittelwertbildung hilfreich ist.

Beste Grüße

Helmuth.

Code: [Select]
void Scale(int x0, int y0, int x1, int y1, int x2, int y2 ,int x3, int y3) {
  for(int y = y2; y < y3+1; y++) {
   for(int x = x2; x < x3+1; x++) {
     leds[XY(x,y)] = leds[XY(
       x0 + ( x * (x1-x0) / (x3-x1) ),
       y0 + ( y * (y1-y0) / (y3-y1) ) )];
   }
 }
}


Go Up