Schreiben Sie ein Programm, das ein farbechtes RGB-Bild I , die maximale Anzahl der zu zeichnenden Linien L und die minimale m- und maximale M- Länge jeder Linie aufnimmt . Geben Sie ein Bild O aus , das so gut wie möglich wie I aussieht und mit L oder weniger geraden Linien gezeichnet wird, die alle eine euklidische Länge zwischen m und M haben .
Jede Linie muss einfarbig sein, beide Endpunkte in den Grenzen von O haben und mit dem Linienalgorithmus von Bresenham gezeichnet werden (was die meisten Grafikbibliotheken bereits für Sie tun werden). Einzelne Zeilen können nur 1 Pixel dick sein.
Alle Zeilen, auch die mit der Länge 0, sollten mindestens ein Pixel einnehmen. Linien können übereinander gezeichnet werden.
Bevor Sie Linien zeichnen, können Sie den Hintergrund von O mit einer beliebigen Farbe initialisieren (die von I abhängen kann ).
Einzelheiten
- O sollte die gleichen Abmessungen haben wie ich .
- L wird immer eine nichtnegative ganze Zahl sein. Es kann größer als die Fläche sein , ich .
- m und M sind nichtnegative Gleitkommazahlen mit M > = m . Der Abstand zwischen zwei Pixeln ist der euklidische Abstand zwischen ihren Mittelpunkten. Wenn dieser Abstand kleiner als m oder größer als M ist , ist eine Linie zwischen diesen Pixeln nicht zulässig.
- Die Leitungen sollten nicht vorgespannt sein.
- Deckkraft und Alpha sollten nicht verwendet werden.
- Es sollte nicht länger als eine Stunde dauern, bis Ihr Programm auf einem anständigen modernen Computer mit Bildern mit weniger als einer Million Pixel und L weniger als 10.000 ausgeführt wird.
Bilder testen
Sie sollten uns natürlich Ihre genauesten oder interessantesten Ausgabebilder zeigen (was ich erwarte, wenn L zwischen 5% und 25% der Pixelanzahl in I liegt und m und M ungefähr ein Zehntel der Diagonalengröße betragen).
Hier sind einige Testbilder (für Originale klicken). Sie können auch Ihre eigenen posten.
Einfachere Bilder:
Dies ist ein Beliebtheitswettbewerb. Die Einsendung mit den höchsten Stimmen gewinnt.
Anmerkungen
- Es kann hilfreich sein, L aus einem Prozentsatz der gesamten Pixel in I sowie einem absoluten Wert ableiten zu lassen . zB
>>> imageliner I=img.png L=50% m=10 M=20
wäre das gleiche, als>>> imageliner I=img.png L=32 m=10 M=20
wäreimg.png
es ein 8 mal 8 Pixel großes Bild. Ähnliches könnte für m und M getan werden . Dies ist nicht erforderlich. - Da Linien nicht über Grenzen hinausgehen können, ist die Diagonallänge von I die längste mögliche Linie . Ein höheres M sollte jedoch nichts kaputt machen.
- Wenn m 0 ist und L größer oder gleich der Anzahl von Pixeln in I ist , könnte O natürlich mit I identisch sein, indem die Länge 0 "Zeilen" an jeder Pixelstelle vorliegt. Dieses Verhalten ist nicht erforderlich.
- Wahrscheinlich ist die Reproduktion der Form von I wichtiger als die Reproduktion der Farbe. Möglicherweise möchten Sie sich mit der Kantenerkennung befassen .
quelle
Antworten:
C ++ - etwas zufällige Zeilen und noch einige mehr
Zuerst ein paar zufällige Zeilen
Der erste Schritt des Algorithmus erzeugt zufällig Linien, nimmt für das Zielbild einen Durchschnitt der Pixel entlang dieser Linie und berechnet dann, ob das aufsummierte Quadrat der RGB-Abstände aller Pixel geringer wäre, wenn wir die neue Linie zeichnen würden (und nur malen, wenn es ist). Die Farbe der neuen Linien wird als kanalweiser Durchschnitt der RGB-Werte mit einer zufälligen Addition von -15 / + 15 gewählt.
Dinge, die mir aufgefallen sind und die Umsetzung beeinflusst haben:
Ich experimentierte mit einigen Zahlen und wählte
L=0.3*pixel_count(I)
und verließm=10
undM=50
. Es wird gute Ergebnisse liefern, angefangen bei ungefähr0.25
bis0.26
zur Anzahl der Zeilen, aber ich habe 0,3 gewählt, um mehr Platz für genaue Details zu haben.Für das vollständige Golden Gate-Bild wurden 235929 Linien gezeichnet (wofür es hier satte 13 Sekunden gedauert hat). Beachten Sie, dass alle Bilder hier in verkleinerter Größe angezeigt werden und Sie sie in einem neuen Tab öffnen / herunterladen müssen, um die volle Auflösung anzuzeigen.
Löschen Sie die Unwürdigen
Der nächste Schritt ist ziemlich teuer (für die 235k-Leitungen hat es ungefähr eine Stunde gedauert, aber das sollte durchaus innerhalb der Zeitanforderungen von "einer Stunde für 10k-Leitungen mit 1 Megapixel" liegen), ist aber auch ein bisschen überraschend. Ich gehe alle zuvor gemalten Linien durch und entferne diejenigen, die das Bild nicht verbessern. Dies lässt mich in diesem Lauf mit nur 97347 Zeilen, die das folgende Bild erzeugen:
Sie müssen sie wahrscheinlich in einem geeigneten Bildbetrachter herunterladen und vergleichen, um die meisten Unterschiede zu erkennen.
und von vorne anfangen
Jetzt habe ich viele Linien, die ich wieder malen kann, um insgesamt 235929 wieder zu haben. Nicht viel zu sagen, deshalb hier das Bild:
kurze Analyse
Der gesamte Vorgang scheint wie ein Unschärfefilter zu funktionieren, der auf lokalen Kontrast und Objektgrößen reagiert. Es ist aber auch interessant zu sehen, wo die Linien gezeichnet werden, so dass das Programm diese auch aufzeichnet (für jede Linie wird die Pixelfarbe einen Schritt weißer gemacht, am Ende wird der Kontrast maximiert). Hier sind die entsprechenden zu den drei oben farbigen.
Animationen
Und da wir alle Animationen lieben, finden Sie hier einige animierte Gifs des gesamten Prozesses für das kleinere Golden Gate-Bild. Beachten Sie, dass es aufgrund des GIF-Formats zu deutlichen Dithering-Effekten kommt (und da Entwickler von True-Color-Animationsdateiformaten und Browserhersteller im Streit um ihr Ego sind, gibt es kein Standardformat für True-Color-Animationen. Andernfalls hätte ich möglicherweise ein .mng oder ähnliches hinzugefügt ).
Etwas mehr
Wie gewünscht, hier einige Ergebnisse der anderen Bilder (möglicherweise müssen Sie sie erneut in einem neuen Tab öffnen, damit sie nicht verkleinert werden.)
Zukünftige Gedanken
Das Herumspielen mit dem Code kann einige interessante Variationen ergeben.
Der Code
Dies sind nur die beiden wichtigsten nützlichen Funktionen. Der gesamte Code passt hier nicht hinein und kann unter http://ideone.com/Z2P6Ls gefunden werden
Die
bmp
Klassenraw
undraw_line
Funktionen greifen auf Pixel bzw. Zeilen in einem Objekt zu, das im bmp-Format geschrieben werden kann (es war nur ein Hack, der herumlag, und ich dachte, das macht dies etwas unabhängig von jeder Bibliothek).Das Eingabedateiformat ist PPM
quelle
Java - zufällige Zeilen
Eine sehr einfache Lösung, die zufällige Linien zeichnet und für sie die durchschnittliche Farbe des Quellbilds berechnet. Die Hintergrundfarbe wird auf die durchschnittliche Quellfarbe eingestellt.
L = 5000, m = 10, M = 50
L = 10000, m = 10, M = 50
BEARBEITEN
Ich habe einen genetischen Algorithmus hinzugefügt, der eine Population von Linien verarbeitet. Bei jeder Generation behalten wir nur die 50% besten Zeilen bei, lassen die anderen fallen und generieren zufällig neue. Die Kriterien für das Beibehalten der Linien sind:
Zu meiner großen Enttäuschung scheint der Algorithmus die Bildqualität nicht wirklich zu verbessern :-( nur die Linien werden paralleler.
Erste Generation (5000 Zeilen)
Zehnte Generation (5000 Zeilen)
Mit Parametern spielen
quelle
C - gerade Linien
Ein grundlegender Ansatz in C, der ppm-Dateien verarbeitet. Der Algorithmus versucht, vertikale Linien mit optimaler Linienlänge zu platzieren, um alle Pixel zu füllen. Die Hintergrundfarbe und die Linienfarben werden als Durchschnittswert des Originalbilds berechnet (der Median jedes Farbkanals):
L = 5000, m = 10, M = 50
L = 5000, m = 10, M = 50
L = 100000, m = 10, M = 50
quelle
Python 3-basiert auf "etwas zufälligen Linien und etwas mehr" plus Sobel-Kantenerkennung.
Der Code kann theoretisch für immer laufen (also kann ich ihn zum Spaß über Nacht laufen lassen), aber er zeichnet seinen Fortschritt auf, sodass alle Bilder von der 1-10-Minuten-Marke aufgenommen werden.
Es liest zuerst das Bild und ermittelt dann mithilfe der Sobel-Kantenerkennung den Winkel aller Kanten, um sicherzustellen, dass die Linien nicht in eine andere Farbe übergehen. Sobald eine Zeile der zufälligen Länge innerhalb (lengthmin, lengthmax) festgelegt ist, wird geprüft, ob sie zum Gesamtbild beiträgt. Während kleinere Linien besser sind, stelle ich die Linienlänge von 10-50 ein.
quelle