Kreisförmige Bildskalierung

SuperPCFan

Mitglied
Ich suche eine möglich ein Bild kreisförmig um den Mittelpunkt zu skalieren.
Vermutlich habe ich bei Google dafür einfach nicht den richtigen Begriff eingegeben.

Also ich habe ein Bild (BufferedImage), den Startwinkel und den Bogenwinkel (extent).
Nun möchte ich, dass das Bild wie ein Tortenstück vom Startwinkel bis zum Endwinkel (Start + Extent) reicht.
Dabei soll der Bildinhalt aber nicht maskiert (überdeckt), sondern skaliert (gestaucht) werden.

Anders ausgedrückt, dass Bild soll am Startwinkel in ein 360°-Tortenstück geschnitten werden
und dann bis zum Extent-Winkel kreisförmig um den Mittelpunkt zusammengeschoben werden.

Ich hoffe ich habe das verständlich ausgedrückt. :)
Wie würde man so eine kreisförmige Skalierung in Java umsetzen?
Ich habe nur lineare skalierfunktionen gesehen.
 

SuperPCFan

Mitglied
Tut mir leid den Ansatz verstehe ich nicht. Das Graphics2D Objekt eines BufferedImage skaliert nach meinem Verständnis immer die gesamte Bildhöhe und/oder Bildbreite linear mit einem (demselben) bestimmten Faktor. Es gibt doch nur kartesische Skalierfunktionen, oder?

Wenn ich das also richtig verstehe, müsste ich den Farbwert jedes Pixels einzelnd aus dem BufferedImage lesen und dessen Position jeweils in eine Polarkoordinate umrechnen. Dann wird die Skalierung auf die Winkel jeder Polarkoordinate angewendet. Beim Zurückumrechnen der Polarkoordinaten jedes Pixels in je eine kartesiche Position muss dann ein schlauer Überlagerungsalgorithmus für Pixel auf derselben Koordinate angewandt werden. Zum Schluss muss dann der Farbwert jedes überlagerten Pixels in das neue Bild an die errechnete kartesische Position geschrieben werden.

Das klingt für mich nach etwas das ich nicht "zu Fuß auf der oberen Abstraktionsebene" machen sollte, auch wenn es vermutlich funktionieren würde. Gibt es dafür keine existierende Funktion?
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Es gibt doch nur kartesische Skalierfunktionen, oder?
Ja, deswegen müsste man auch das Koordinatensystem umrechnen.

Wenn ich das also richtig verstehe, müsste ich den Farbwert jedes Pixels einzelnd aus dem BufferedImage lesen und dessen Position jeweils in eine Polarkoordinate umrechnen. Dann wird die Skalierung auf die Winkel jeder Polarkoordinate angewendet. Beim Zurückumrechnen der Polarkoordinaten jedes Pixels in je eine kartesiche Position muss dann ein schlauer Überlagerungsalgorithmus für Pixel auf derselben Koordinate angewandt werden.
Das scheint mir zu kompliziert. Ich würde einfach ein Polarkoordinatenbild erstellen und dort jedes Pixel mit einem Farbwert aus dem Urbild setzen. Dann ergeben sich Überlagerungen automatisch. Anschließend skalieren und dann zurück in das kartesische Bild transformieren.

Man müsste noch nicht einmal das Bild neu schreiben, weil es ja nur um Koordinatentransformation geht.

Gibt es dafür keine existierende Funktion?
Nicht, dass ich wüßte. Evtl. bietet OpenCV sowas an?
 

SuperPCFan

Mitglied
Ich würde einfach ein Polarkoordinatenbild erstellen
Der BufferedImage Konstruktor hat doch keine Option für Polarkoordinaten, oder? Meinst du damit eine ArrayList mit einem Element je Pixel? Und jedes Listenelement enthält Farbwert, Radius und Winkel?

...Dann ergeben sich Überlagerungen automatisch. Anschließend skalieren...
Überlagerungen können sich doch erst nach/bei der Skalierung ergeben?!
...weil es ja nur um Koordinatentransformation geht
Ich habe am BufferedImage keine Funktion für Koordinatentransformation gesehen. Außerdem müssten nach der Skalierung leere Pixel doch mit dem Alphawert für "Transparenz" gefüllt werden. Ein "transparentes" neues Bild zu befüllen scheint mir da sinnvoller, oder was übersehe ich?
 

mihe7

Top Contributor
Der BufferedImage Konstruktor hat doch keine Option für Polarkoordinaten, oder? Meinst du damit eine ArrayList mit einem Element je Pixel? Und jedes Listenelement enthält Farbwert, Radius und Winkel?
Nein, nein und nein :)

Das BufferedImage ist rechteckig. Mal ein ganz einfaches Beispiel: 360 breit (das wäre sehr grob, 1 Pixel pro Grad) und Radius hoch.

Überlagerungen können sich doch erst nach/bei der Skalierung ergeben?!
Nein. Im Beispiel hättest Du für den Mittelpunkt (y=0 im Polarkoordinatenbild) z. B. 360 Pixel mit dem gleichen Farbwert. Wenn Du dann das Bild skalierst, entstehen natürlich weitere Überlagerungen.

Ich habe am BufferedImage keine Funktion für Koordinatentransformation gesehen.
Selbst ist der Mann.

Außerdem müssten nach der Skalierung leere Pixel doch mit dem Alphawert für "Transparenz" gefüllt werden.
Ja - in erster Linie im kartesischen Bild, wobei es einfacher sein kann, das bereits im Polarkoordinatenbild zu erledigen.
 

SuperPCFan

Mitglied
Selbst ist der Mann.
Schon, aber irgendwie stehe ich immer noch auf dem Schlauch.

BufferedImage ist zwangsläufig kartesisch.
Eine ArrayList mit den Polarkoordinaten meinst du nicht.

In welcher Klasse, in welchem Objekt oder in welcher Form soll ich das
Polarkoordinatenbild
denn abbilden?
Ich muss die Gesamtheit der Koordinaten doch erstmal "speichern", um sie skalieren zu können.
 

Barista

Top Contributor
Ich hoffe ich habe das verständlich ausgedrückt.
Nein.

Du musst(kannst) eine Abbildungsfunktion vom Punkt des Originalbildes zum Punkt des skalierten Bildes definieren.

Weil ein Pixel eine bestimmte Fläche hat, musst Du für den Farb-Wert (RGB) des Ziel-Pixels den gewichteten Durchschnitt der beteiligten Quell-Pixel mit Pythagoras ermitteln.

Überstehende Quell-Pixel musst Du abschneiden (if).

Ein kreisförmiges Bild kannst Du in einer rechteckigen Welt wahrscheinlich mit Hilfe des Durchsichtig-Setzens der Pixel ausserhalb des Kreises erreichen.
 

mihe7

Top Contributor
Ich hatte meinen Vorschlag mal umgesetzt, der funktioniert leider auch nicht ganz so (einfach), wie ich mir das vorgestellt hatte.

Die Grundidee war, eine Linie fester Länge (Radius) wie einen Sekundenzeiger um den Mittelpunkt zu rotieren und die Punkte, die auf dieser Linie liegen, nebeneinander zu einem rechteckigen Bild zusammenzusetzen.

Das funktioniert relativ einfach per Umrechnung in Polarkoordinaten. Nehmen wir als Beispiel mal ein 11x11 Bild, dessen Inhalt sich auf eine Kreisfläche mit Mittelpunkt (5,5) und Radius 5 beschränkt. Der Umfang des Kreises beträgt aufgerundet 32 bzw. 35, wenn man als Durchmesser dank Pixel 11 statt 10 verwendet.

Wenn wir also z. B. ein Bild 32x5 erstellen, entspricht jede Koordinate in diesem Bild einer Polarkoordinate. In x-Richtung stehen die Winkel von 0 bis 2*PI, in y-Richtung die Abstände zum Mittelpunkt.

Für ein px ist der Winkel also w=2*PI*px/32. Die kartesische Koordinate ergibt sich also für ein py

cx = py*cos(w) + 5
cy = py*sin(w) + 5

Um den Farbwert für (px, py) zu bestimmen, liest man diesen einfach aus dem Originalbild an Position (cx, cy) aus.

Nächster Schritt war das Skalieren des Bildes. Skaliert man z. B. auf 24x5, quetscht man auf einen Dreiviertelkreis. Den rechts freiwerdenden Streifen von 8x5 kann man z. B. mit Transparenz oder Hintergrundfarbe füllen.

Beim Zurückschreiben habe ich der Einfachheit halber den gleichen Ansatz gewählt, nur dass der Farbwert von (cx, cy) anhand von (px, py) bestimmt wird.

Ergebnis: sieht seltsam aus - so, als ob man nach oben und unten biegen würde. Warum leuchtet mir allerdings noch nicht ganz ein.
 

Neue Themen


Oben