Rainbowlify an image

23

Wyzwanie polega na stopniowym zmienianiu odcieni na obrazie w celu uzyskania ładnych zdjęć:

wielka gwiaździsta noc ( oryginał )

Wyzwanie

Napisz program lub funkcję, która przyjmuje dwie nieujemne liczby całkowite i obraz w dowolnym wybranym przez siebie formacie pliku obrazu (możesz wybrać ścieżkę do obrazu lub surowych danych obrazu).

Pierwszą liczbę całkowitą nazywamy cyklami, a drugą liczbą całkowitą - przesunięcie .

Zdefiniujemy również krok zmiennoprzecinkowy jako cykle 360 razy podzielone przez obszar obrazu lub step = 360 * cycles / (image width * image height).

Dla każdego piksela P na obrazie, przesuwając jeden rząd na raz, od lewej do prawej, od góry do dołu (tj. W kolejności odczytu, jeśli piksele były literami), wykonaj następujące czynności:

  1. Zwiększyć odcień z P przez offsetowych stopni (zapętlenie około od 360 do 0, jeśli to konieczne).

  2. Następnie zwiększ przesunięcie krok po kroku .

Zapisz, wyświetl lub wyślij nieprzetworzony obraz wynikowy w dowolnym popularnym formacie pliku obrazu.

Ta procedura stopniowo zwiększa odcień wszystkich pikseli na obrazie, czyniąc cykle pełnymi pętlami wokół tęczy odcienia , zaczynając od początkowego przesunięcia odcienia przez przesunięcie .

Kiedy cykle wynoszą 1, a przesunięcie wynosi 0, jak na powyższym obrazie Gwieździstej nocy, górne i dolne rzędy pikseli praktycznie nie mają przesunięcia odcienia, ale pomiędzy nimi jest pełny cykl kolorów.

Detale

  • Cykle mogą być dowolnymi liczbami całkowitymi nieujemnymi, ale można założyć, że przesunięcie wynosi od 0 do 359 włącznie.

  • Gdy liczba cykli wynosi 0, każdy piksel na obrazie zostanie przesunięty o dokładnie przesunięcie, ponieważ krok musi również wynosić 0. (W takim przypadku, jeśli przesunięcie wynosi 0, obraz w ogóle się nie zmienia).

  • Możesz założyć, że cykle i przesunięcia są wprowadzane jako 1.0liczby zmiennoprzecinkowe, jeśli jest to pożądane (tzn. Zamiast 1). (Zdaję sobie sprawę, że wcale nie muszą to być liczby całkowite, to po prostu upraszcza wyzwanie).

  • „Barwa” oznacza wersję przestrzeni kolorów RGB, powszechną w modelach kolorów HSL / HSV .

Przykłady

Oryginalny:

rzeka

Cykle = 1, przesunięcie = 0:

wyjście rzeki 1

Cykle = 1, przesunięcie = 180:

wyjście rzeki 2

Oryginalny:

kule

Cykle = 2, przesunięcie = 60:

wyjście kulek

Oryginalny:

zachód słońca
(Dzięki ArtOfCode .)

Cykle = 1, przesunięcie = 120:

wyjście zachód

Oryginalny:

klamka
(Dzięki Klamka .)

Cykle = 1, przesunięcie = 0:

wyjście klamki 1

Cykle = 4, przesunięcie = 0:

wyjście klamki 2

Cykle = 200, przesunięcie = 0:

wyjście klamki 3

Cykle = 30000, przesunięcie = 0:

wyjście klamki 4

(Te obrazy mogą nie być idealnie w pikselach z powodu kompresji ich przez Imgur.)

Punktacja

Najkrótszy kod w bajtach wygrywa. Tiebreaker jest wyżej głosowaną odpowiedzią.

Odpowiedzi, które opublikują własne fajnie wyglądające obrazy testowe, dostaną ode mnie więcej punktów brownie.

Hobby Calvina
źródło
6
Wygląda na to, że Klamka pali jakąś garnek.
Denker
Zakładam tablicę liczb całkowitych, ponieważ wartość zwracana byłaby zawarta w „lub wyjściowym surowym”?
Marv
2
@Marv Nie. Mam na myśli nieprzetworzone bajty obrazu (w wybranym wspólnym formacie, powiedzmy, że ppm ) mogą być przesyłane bezpośrednio na standardowe wyjście.
Calvin's Hobbies
2
Czy wyniki muszą być identyczne z twoimi przykładami? Dostaję nieco inne obrazy.
DJMcMayhem
1
@DrGreenEggsandHamDJ Jeśli nie możesz wizualnie powiedzieć różnicy, to prawdopodobnie jest w porządku. Perfekcja pikseli nie jest wymagana (i tak obraz może i tak kompresować moje obrazy).
Calvin's Hobbies

Odpowiedzi:

8

Pyth, 86 bajtów, pełny program

=N.tE7=Z*6*.n0cEl.n'zMmhtS[0255ss*VG.>+Lc-1.tH1 3[.tH1Kc.tH0@3 2_K)d)3.wmmgk~-NZd'z

Pyth nie ma wbudowanych konwersji przestrzeni kolorów - to prawdziwa okazja.

Pobiera dane wejściowe w następującym formacie na stdin:

input_filename.png
offset
cycles

Obraz wyjściowy jest zapisywany o.png.


Działa to poprzez obrócenie kostki koloru wokół jej przekątnej, a następnie zaciśnięcie dowolnych wartości poza zakresem.

Jeśli ajest to kąt obrotu i r, g, bkolor wejściowy, nowy kolor obliczamy na r', g', b'podstawie:

o = cos(a), i = sin(a) / sqrt(3)
n = (1 - o) / 3
m = [n + o, n - i, n + i]
clamp(c) = max(0, min(255, c))
r' = clamp(r*m[0] + g*m[1] + b*m[2])
g' = clamp(r*m[2] + g*m[0] + b*m[1])
b' = clamp(r*m[1] + g*m[2] + b*m[0])
orlp
źródło
6

Python, 379 bajtów

from PIL.Image import*
from colorsys import*
def f(H,c,I):
 i=open(I);x,y=i.size;S=1.*c/(x*y);r,g,b=i.split();R=[];G=[];B=[]
 for x,y,z in zip(r.getdata(),g.getdata(),b.getdata()):
  e=255.;h,s,v=rgb_to_hsv(x/e,y/e,z/e);t=hsv_to_rgb(h+H,s,v);H=H+S%1.;x,y,z=[int(x*e)for x in t];R.append(x);G.append(y);B.append(z)
 p=Image.putdata;p(r,R);p(g,G);p(b,B);return merge('RGB',(r,g,b))

To prowadzi do .jpg wejścia jako. To nie będzie działać z png, chociaż można zmienić r,g,b=i.split();, aby r,g,b=i.split()[:3];załadować obraz PNG.

Oto kilka zdjęć:

Oryginalny:

wprowadź opis zdjęcia tutaj

Przesunięcie: 0, Cykle: 4

wprowadź opis zdjęcia tutaj

Oryginalny:

wprowadź opis zdjęcia tutaj

Przesunięcie 0, 1 cykl:

wprowadź opis zdjęcia tutaj

Oryginalny:

wprowadź opis zdjęcia tutaj

Przesunięcie 0, 2,5 cykli:

wprowadź opis zdjęcia tutaj

DJMcMayhem
źródło
6

Java (pełny program), 491 488 bajtów (Dzięki @Geobits)

import java.awt.*;import java.io.*;import static javax.imageio.ImageIO.*;class Q{public static void main(String[]v)throws Exception{File f=new File(v[2]);java.awt.image.BufferedImage b=read(f);for(int i=0,j,h=b.getHeight(),w=b.getWidth();i<h;i++)for(j=0;j<w;){Color c=new Color(b.getRGB(j,i));float[]a=new float[3];c.RGBtoHSB(c.getRed(),c.getGreen(),c.getBlue(),a);b.setRGB(j++,i,c.HSBtoRGB((a[0]+Float.valueOf(v[1])/360+(i*w+j)*Float.valueOf(v[0])/w/h)%1,a[1],a[2]));}write(b,"png",f);}}

Bez golfa

import java.awt.*;
import java.io.*;

import static javax.imageio.ImageIO.*;

class A79200 {
    public static void main(String[] v) throws Exception {
        File file = new File(v[2]);
        java.awt.image.BufferedImage image = read(file);
        for (int i = 0, j, height = image.getHeight(), width = image.getWidth(); i < height; i++)
            for (j = 0; j < width; ) {
                Color color = new Color(image.getRGB(j, i));
                float[] arr = new float[3];
                color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), arr);
                image.setRGB(j++, i, color.HSBtoRGB((arr[0] + Float.valueOf(v[1]) / 360 + (i * width + j) * Float.valueOf(v[0]) / width / height) % 1, arr[1], arr[2]));
            }
        write(image, "png", file);
    }
}

Wyjaśnienie

  • Zastosowanie: dość proste. Kompiluj z java -c Q.java. Uruchom z java Q <cycles> <offset> <imagepath>. Zastąpi istniejący obraz, więc bądź ostrożny.

  • Na początku zamierzałem stworzyć rozwiązanie oparte tylko na metodzie, ale nie do końca wiedziałem, jak sobie z nimi poradzić, więc pomyślałem, że przejdę do pełnej wersji , prawdopodobnie i tak nie wygra: ^)

Wyniki:

Image 1: 1 cycle, 0 offset

1

Image 1: 1 cycle, 180 offset

2)

Image 2: 2 cycles, 60 offset

3)

Image 3: 1 cycle, 120 offset

4

Image 4: 1 cycle, 0 offset

5

Image 4: 4 cycles, 0 offset

6

Image 4: 200 cycles, 0 offset

7

Bonus: The Starry Night, 1 cycle, 0 offset

wprowadź opis zdjęcia tutaj

Marv
źródło
1
W celu późniejszego wykorzystania można importować tylko odpowiedzi odpowiadające metodom, tak jak zwykle. Po prostu umieść je poza ciałem metody i policz bajty. Możesz również w pełni zakwalifikować klasy zamiast importować je, jeśli będziesz potrzebować tylko raz, aby w niektórych przypadkach zaoszczędzić kilka bajtów.
Geobity
Czy istnieje powód, dla którego importujesz java.io.Filezamiast java.io.*?
Geobity
Dzięki, dobrze wiedzieć. Po drugie, nie, nie ma żadnego powodu. Słuszna uwaga.
Marv
Dlaczego import ** static**, nie tylko import?
Solomon Ucko
1
Tak, że mogę zadzwonić ImageIO::readi ImageIO::writebez konieczności ImageIO.dodawania: To dodaje 9 bajtów ( static .*), ale oszczędza 16 ( ImageIO.dwa razy).
Marv