Ordina i pixel


35

Il tuo compito è creare un programma che, in base a un'immagine di input, crei un'immagine di output della stessa dimensione, in cui tutti i pixel sono ordinati per valore esadecimale.

Il tuo programma può:

  • Ordina i pixel da sinistra a destra e poi verso il basso o prima verso il basso in colonne e poi a destra. In ogni caso, il pixel in alto a sinistra è il più piccolo e quello in basso a destra è il più grande.
  • Usa la trasparenza, ma questo non è richiesto.
  • Ordina per RGB, ma puoi utilizzare CMY o qualsiasi altro formato con almeno 3 valori. Puoi scegliere su quali valori ordinare. (HSV potrebbe dare delle belle immagini)
  • Utilizzare qualsiasi formato di immagine noto che può aprire la maggior parte dei computer.

Regole:

  • L'output deve essere scritto su disco o può essere trasferito in un file.
  • L'input viene fornito come argomento della riga di comando, sotto forma di un percorso relativo all'immagine, oppure reindirizzato dalla riga di comando.
  • Questo è il codice golf, quindi vince il codice più breve in byte!

Risposte:


20

Pyth - 10 byte

Legge l'immagine, comprime la bitmap, ordina, quindi suddivide nuovamente la bitmap, quindi scrive.

.wclK'zSsK

Non funziona online per ovvi motivi. Accetta l'input come percorso relativo al file di immagine e l'output in o.png.

Uscita dal gotico americano:


3
Spero di non essere l'unico ad avere l'impressione che l'immagine si stia muovendo ...
Quentin,

Sembra legno.
Joe Z.,

19

JavaScript (ES6), 383 377 354 byte

f=s=>{d=document,i=new Image,i.src=s,i.onload=$=>{c=d.createElement`canvas`,x=c.getContext`2d`,c.width=w=i.width,c.height=h=i.height,x.drawImage(i,0,0),D=x.getImageData(0,0,w,h),t=D.data,t.set([].concat(...[...t].map((v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)).sort((a,b)=>a.some((v,i)=>k=v-b[i])&&k)).slice(12*w*h)),x.putImageData(D,0,0),d.body.appendChild(c)}}

uscita campione

Demo eseguibile:

Come funziona questo codice è usare getImageDataper ottenere un array del modulo

[R,G,B,A,
 R,G,B,A,
 R,G,B,A,
 ...]

E mapquesto a una matrice del modulo

[[R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
 [R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
 [R,G,B,A],[0,0,0,0],[0,0,0,0],[0,0,0,0],
 ...]

In modo che i valori R siano associati alle matrici dell'insieme RGBA e i valori B, G e A si trasformino in matrici zero di valore minimo. Quando ordiniamo questo array, tutti gli [0,0,0,0]array si ordinano in fondo e gli array di valore reale si ordinano normalmente in alto:

[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],
 [0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],
 [0,0,0,0],..., [R,G,B,A],[R,G,B,A],[R,G,B,A],...]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               extract & flatten these sorted pixels

Raschiamo il quarto superiore dell'array (per perdere i valori vuoti che abbiamo creato), lo appiattiamo [].concat.applye finiamo con un array del primo modulo, ma questa volta viene ordinato.

Leggermente decodificato con spazi bianchi e commenti:

f=s=>{ 
  // first, load image, then do everything else onload
  i=new Image,
  i.src = s,
  i.onload=$=>{
    // set up the canvas
    d=document,
    c=d.createElement`canvas`,
    w=c.width=i.width,
    h=c.height=i.height,
    x=c.getContext`2d`,

    // draw image to canvas and capture pixel data
    x.drawImage(i,0,0),
    D=x.getImageData(0,0,w,h),
    t=D.data,

    // set pixel data to...
    t.set(
      // the flattened array...
      [].concat(...
        // that is a mapping of the pixel data...
        [...t].map(
          // that clumps RGBA families into subarrays
          // by replacing every fourth value with [R,G,B,A]
          // and all other values to [0,0,0,0]...
          (v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)
        )
        // and is then sorted...
        .sort(
          // by reducing each array to a positive, negative, or zero
          // by comparing R,G,B,& A until the first nonzero difference
          (a,b)=>a.some((v,i)=>k=v-b[i])&&k
        )
      )
      // then eliminate the low-sorted empty [0,0,0,0] values we created,
      // leaving only the top fourth, with real values
      // (note that 3*4*w*h is the same as 3*t.length)
      .slice(3*4*w*h)
    ),

    // now that `t` is set, store `D` in canvas
    x.putImageData(D,0,0),

    // show canvas
    d.body.appendChild(c)
  }
}

Si noti che la maggior parte dei browser potrebbe non eseguire questo codice per immagini di grandi dimensioni, poiché passa un numero enorme di argomenti [].concat. Quando l'ambiente del browser non consente memoria sufficiente per tutti gli argomenti, un approccio alternativo consiste nel mappare nuovamente i valori RGBA dai primi quattro array superiori sull'array, per un punteggio totale di 361 byte :

f=s=>{d=document,i=new Image,i.src=s,i.onload=$=>{c=d.createElement`canvas`,x=c.getContext`2d`,c.width=w=i.width,c.height=h=i.height,x.drawImage(i,0,0),D=x.getImageData(0,0,w,h),t=D.data,t.set([...t].map((v,i,T)=>i%4?[,,,0]:T.slice(i,i+4)).sort((a,b)=>a.some((v,i)=>k=v-b[i])&&k).map((v,i,A)=>A[3*w*h+(i>>2)][i%4])),x.putImageData(D,0,0),d.body.appendChild(c)}}

Sostituiamo semplicemente il [].concat(...{stuff}).slice(12*w*h)con {stuff}.map((v,i,A)=>A[3*w*h+(i>>2)][i%4]).)


Potresti includere un esempio di output?
Paŭlo Ebermann,

@ PaŭloEbermann Fatto.
apsillers,

@inserireusernamehere Oh, dang, ho provato solo su piccole immagini. La mia concat.applychiamata fornisce troppi argomenti concate il motore JS lo sta rifiutando. D:Grazie! Lo aggiusterò e prenderò nota dei due punteggi. (E sono felice di poterti aiutare!)
apsillers,

@inserireusernamehere Grazie per l'head-up sulla limitazione delle dimensioni; Ora ho anche pubblicato una versione leggermente più lunga che funziona su immagini più grandi.
apsillers,

@apsillers Bel lavoro. Purtroppo non posso votare di nuovo. :)
inserireusernamehere

14

Mathematica 86 83 72 byte

 f=Flatten;Image[f[Sort[f[s=ImageData@#1,1]]]~ArrayReshape~Dimensions@s]&

Con 14 byte salvati grazie a @Martin Buttner.


Esempio

L'immagine stessa è stata inserita. In alternativa, è possibile utilizzare una variabile contenente l'immagine.

Gotico


La sfida specifica che i pixel devono essere ordinati in base al valore esadecimale, ma se leggo correttamente, usi l'ordinamento predefinito di Mathematica per gli elenchi {R, G, B} o {R, G, B, alpha}. Non mi è chiaro che siano equivalenti.
Michael Stern,

@MichaelStern Non conosco Mathematica, ma se ordina le tuple elementalmente come la maggior parte delle lingue, sono equivalenti: numeri come esadecimali sono ordinati per ogni cifra, due dei quali sono rappresentati da ciascun elemento nella tupla.
Maltysen,

@MichaelStern, Maltysen ha ragione. L'ordinamento RGB e l'ordinamento esadecimale sono equivalenti: l'ordinamento per R, quindi G, quindi il valore B funziona esattamente come l'ordinamento per valore di luogo in esadecimale.
DavidC,

OK, +1 da parte mia.
Michael Stern,

ImageDatae ArrayReshapepotrebbe usare la notazione infix. Flattenè abbastanza lungo da salvare un paio di byte assegnandolo a f. E hai davvero bisogno "Byte"? L'impostazione predefinita non ridimensionerebbe i valori del canale in modo [0,1]tale che l'ordinamento e la ricostruzione delle immagini funzionassero ancora bene?
Martin Ender,

5

Javascript ES6, 334 byte

f=s=>{with((d=document).body.appendChild(c=d.createElement`canvas`).getContext`2d`)(i=new Image).src=s,drawImage(i,0,0,w=c.width=i.width,h=c.height=i.height),t=(g=getImageData(0,0,w,h)).data,t.set([...t].map(i=>(0+i.toString(16)).slice(-2)).join``.match(/.{8}/g).sort().join``.match(/../g).map(i=>parseInt(i,16))),putImageData(g,0,0)}

Ungolfed:

f=s=>{                                   // create function that accepts image name
 with((d=document).body.appendChild(     // use "with" to exclude having to prepend "<context2d>." to drawImage, getImageData and putImageData
   c=d.createElement`canvas`).getContext`2d`) // create canvas to get pixels from and draw output to
  (i=new Image).src=s,                   // create image, define source filename
  drawImage(i,0,0,w=c.width=i.width,     // draw image to canvas
                  h=c.height=i.height),
  t=(g=getImageData(0,0,w,h)).data,      // get image data from canvas in form of Uint8Array
  t.set([...t]                           // convert image data from Uint8Array to standard array
   .map(i=>(0+i.toString(16)).slice(-2)) // convert R,G,B,A bytes to base16 strings with leading zeros
   .join``.match(/.{8}/g)                // convert array of [R,G,B,A,R,G,B,A,...] to [RGBA,RGBA,...]
   .sort()                               // sort pixel values
   .join``.match(/../g)                  // convert array of [RGBA,RGBA,...] to [R,G,B,A,R,G,B,A,...]
   .map(i=>parseInt(i,16))),             // convert hex strings back to integers, reassign to image data
  putImageData(g,0,0)                    // dump image data onto canvas
}

@inserireusernamehere Funziona con l'ultimo Firefox. Come la tua risposta, presuppone che ci sia un corpo a cui aggiungere la tela e che l'immagine di origine provenga dallo stesso dominio.
Dendrobium,

+1 Soluzione molto elegante. Elabora anche immagini fino a 1600 x 1900px.
insertusernamehere

2
Oggi ho imparato che appendChildrestituisce il suo argomento. Molto utile! Mi hai ispirato a sminuire la mia voce dal 377 al 354, ma non riesco proprio a battere il tuo :). (Quando uso il tuo appendChildportachiavi e withtecnica riesco a portarlo a 347, ma comunque a 13!) Ottimo lavoro!
apsillers,

5

C (usando SDL1.2), 333 322 315 byte

Probabilmente C non è il "coltello più affilato nello scaffale" per questo tipo di lavoro, volevo comunque provarlo. I suggerimenti per migliorare la mia risposta sono i benvenuti. Il programma ottiene il nome del file immagine di input come argomento cli.

#include <SDL.h>
#include <SDL_image.h>
#define X SDL_Surface*
#define Y const void*
C(Y a,Y b){return*(Uint32*)a-*(Uint32*)b;}main(int o,char**a){X i=IMG_Load(a[1]);X s=SDL_SetVideoMode(i->w,i->h,32,0);i=SDL_ConvertSurface(i,s->format,0);qsort(i->pixels,i->w*i->h,4,C);SDL_BlitSurface(i,0,s,0);for(;;SDL_Flip(s));}

compilare ed eseguire: gcc -I/usr/include/SDL snippet.c -lSDL -lSDL_image && ./a.out

inserisci qui la descrizione dell'immagine

Di solito non gioco a golf in C, ma ieri ho appena risposto a questa sfida e volevo solo continuare a giocare con quel nuovo giocattolo :)

grazie a @ pseudonym117 per avermi aiutato a salvare 5 byte


Puoi salvare 1 byte modificando il tuo whilealla fine in for(;;SDL_Flip(s));e credo che tu possa omettere intil metodo Ce salvarne altri 4.
pseudonimo117,

4

JavaScript (ES6), 452 480 484 487 511 byte

Wow, questo è diventato più lungo del previsto:

f=u=>{i=new Image;i.src=u;i.onload=_=>{c=(d=document).createElement`canvas`;c.width=w=i.width;c.height=h=i.height;x=c.getContext`2d`;x.drawImage(i,0,0,w,h);p=x.getImageData(0,0,w,h).data;t=[];f=[];for(j=0;j<p.length;++j)t.push([p[j],p[++j],p[++j],p[++j]]);t.sort((a,b)=>a[0]>b[0]||a[0]==b[0]&&a[1]>b[1]||a[0]==b[0]&&a[1]==b[1]&&a[2]>b[2]).map(u=>f.push.apply(f,u));x.putImageData(new ImageData(new Uint8ClampedArray(f),w,h),0,0);d.body.appendChild(c)}}

La funzione accetta un URL come input f('test.jpg');e disegna il risultato in un canvaselemento che viene aggiunto a body.

Si noti che l'origine deve trovarsi sullo stesso dominio o lo script si arresterà con un problema di sicurezza.


limitazioni

L'ho provato in Firefox 42 su OS X (10.10) su una macchina con 2,5 GHz i7 e 16 GB di RAM. La dimensione massima dell'immagine che avrei potuto elaborare senza che Firefox mi chiedesse di continuare l'esecuzione dello script era 1600 x 1932 px .


Ungolfed

f = u => {
    i = new Image;
    i.src = u;
    i.onload = _ => {
        c = (d = document).createElement`canvas`;
        c.width = w = i.width;
        c.height = h = i.height;

        x = c.getContext`2d`;
        x.drawImage(i, 0, 0, w, h);

        p = x.getImageData(0, 0, w, h).data;

        t = [];
        f = [];

        for (j = 0; j < p.length;++j)
            t.push([p[j], p[++j], p[++j], p[++j]]);

        t.sort( (a,b) => a[0] > b[0] || a[0] == b[0] && a[1] > b[1] || a[0] == b[0] && a[1] == b[1] && a[2] > b[2] )
         .map(u => f.push.apply(f,u));

        x.putImageData( new ImageData( new Uint8ClampedArray(f), w, h), 0, 0);
        d.body.appendChild(c)
    }
}

Produzione

Per un migliore confronto ho anche preso " American Gothic " come fonte di esempio:

inserisci qui la descrizione dell'immagine


Le modifiche

  • 24 byte salvati utilizzando for (a in b)invece di for(;;). Grazie ad Ar34z
  • Salvato 3 byte memorizzando documentin una variabile.
  • Hai salvato 4 byte eliminandone alcuni ().
  • Hai salvato 10 byte usando le stringhe di template con tag , omettendo la ()creazione dell'oggetto on e rimuovendo un'altra coppia di ridondanti (). Grazie agli apsillers .
  • Salvato 14 byte con un massiccio refactoring del codice che appiattisce l'array di colori dopo l'ordinamento. Grazie mille a apsillers e Ypnypn per essersi scambiati l' un l'altro.
  • Salvato 1 byte rifattorizzando il for-loop che ottiene i colori di ciascun pixel.

1
È possibile ridurre al minimo i cicli for for(k in t)che utilizzano il che farà risparmiare qualche altro byte :)
ar34z,

1
Bel lavoro! Alcuni miglioramenti: perdere l' ()in new Image(); usa le stringhe di modello con tag per i tuoi argomenti di stringa ( createElement`canvas`, getContext`2d`), non usare le parentesi per i parametri delle funzioni a freccia singola (basta fare f=u=>{...}; le parentesi sono solo per funzioni freccia multi-parametro o zero-parametro). Inoltre, potresti avere uno o due forloop a istruzione singola con parentesi, che non sono necessari.
apsillers,

Oh, in realtà, per le funzioni con la freccia zero-argomento, usa un argomento fittizio a carattere singolo invece di parentesi vuote a due caratteri. ( i.onload=$=>...invece di i.onload=()=>...)
apsillers

Penso che for(l in u)f.push(u[l]);possa diventarefor(z of u)f.push(z);
Ypnypn,

@Ypnypn Può essere anche più breve di così :). - for(u of t)for(z of u)f.push(z)è piuttosto corto, ma può essere ulteriormente ridotto t.map(u=>u.map(z=>f.push(z))). In molti casi, l'utilizzo .mapo .somecon una funzione freccia sarà più breve rispetto all'utilizzo di un forloop. Se vuoi diventare davvero pazzo, puoi risparmiare ancora di più qui con il t.map(u=>f.push.apply(f,u));quale dice "Per ogni array uin t, fornisci uun elenco di argomenti da f.pushvia apply(poiché pushpuò accettare un numero illimitato di argomenti e li mette tutti in ordine).
apsillers,

4

Utilità Bash + GNU, 80

s()(sed 1d $1|cut -d\  -f$2)
sed 1q $1
s $1 2-|sort -t_ -k1.16|paste <(s $1 1) -

Ciò presuppone che il formato di input / output sia in formato .txt di enumerazione pixel ImageMagick. L'input viene passato come nome file e l'output passa a STDOUT.


Se quanto sopra non è considerato un formato di immagine noto, allora possiamo aggiungere le conversioni necessarie:

Utilità Bash + GNU + ImageMagick, 108

s()(sed 1d t|cut -d\  -f$1)
convert $1 txt:t
(sed 1q t
s 2-|sort -t_ -k1.16|paste <(s 1) -)|convert txt:- $2

Input e output sono specificati come nomi di file. ImageMagick determina quali formati di file utilizzare dalle estensioni di file passate, quindi possiamo usarne uno qualsiasi:

$ ./sortpixels.sh 398px-Grant_Wood_-_American_Gothic_-_Google_Art_Project.jpg o.png
$ 

L'o.png risultante è simile a:

inserisci qui la descrizione dell'immagine


3

Python 2, 128 byte

from PIL import*
a=Image.open('a')
b=a.load()
c,d=a.size
a.putdata(sorted(b[e,f]for f in range(d)for e in range(c)))
a.save('b')

A condizione che l'immagine sia un file denominato asenza estensione, l'output sarà un file denominato bsenza estensione.

gotico americano American Gothic (ordinato)


Non ho controllato, ma dovresti invece essere in grado di fare qualcosa del genere a.putdata(sorted(b[f/c,f%d]for f in range(d*c)))(mi sono appena svegliato, quindi potrei aver confuso le variabili).
Kade,

Come l'hai scritto, non ha funzionato (indice fuori intervallo), ma non ho provato a cambiare nessuna variabile (al momento non ho molto tempo). @Shebang
Zach Gates,

3

Java, 316 byte

import javax.imageio.*;class C{public static void main(String[]a)throws Exception{java.awt.image.BufferedImage i=ImageIO.read(new java.io.File(a[0]));int w=i.getWidth(),h=i.getHeight(),v[]=i.getRGB(0,0,w,h,null,0,w);java.util.Arrays.sort(v);i.setRGB(0,0,w,h,v,0,w);ImageIO.write(i,"png",new java.io.File("a.png"));}}

Posiziona i valori esadecimali dei colori dei pixel in un array. L'array viene ordinato e i colori vengono rimappati ai pixel nell'immagine. Il nome dell'immagine risultante è a.png.

input dei tulipani gialli uscita di tulipani gialli
Ingresso gotico americano inserisci qui la descrizione dell'immagine


3

SmileBASIC, 39 35 byte

Supponendo che l'immagine sia caricata sulla pagina grafica 512 * 512:

DIM A[0]GSAVE A,0SORT A
GLOAD A,0,1

Ha spiegato:

DIM IMG[0] 'create array
GSAVE IMG,0 'save graphics to array
SORT IMG 'sort
GLOAD IMG,0,1 'load graphics from array

È così semplice! Sfortunatamente dobbiamo usare numeri interi, che aggiungono 4 byte alla dimensione del programma a causa dei suffissi di tipo.


Non sono davvero sicuro del motivo per cui sono richiesti ints. Sembra che l'utilizzo dei float ottenga effettivamente i risultati corretti. L'esecuzione di questo codice usando ints on SYS/DEFSP.GRPmette a FF000000in alto a sinistra e a 00101010in basso a destra, che è l'apparente opposto della domanda. L'uso di float mette 00000000in alto a sinistra e FFF8F8F8in basso a destra, il che è corretto. (Naturalmente, questo tratta i colori esadecimali come canali non firmati / più alti, il che è probabilmente corretto.)
snail_

Penso che sia valido, dal momento che la domanda non specifica un ordine specifico per cui ordinare (e poiché i valori sono firmati, 0xFF000000è più piccolo di 0x00101010) ma comunque, in realtà non sono sicuro del perché ho usato numeri interi qui ... Penso a il tempo in cui non capivo come GLOAD usasse valori senza segno quando usavi un array float, e pensavo solo che non funzionasse.
12Me21

2

Java, 424 417 404 byte

Bene, questa non è una lingua in cui vuoi giocare a golf ...

import java.awt.image.*;import java.io.*;import javax.imageio.*;class F{public static void main(String[]x)throws Exception{BufferedImage i,o;i=ImageIO.read(new File(x[0]));o=new BufferedImage(i.getWidth(),i.getHeight(),BufferedImage.TYPE_INT_RGB);o.setData(i.getRaster());int[]p=((DataBufferInt)o.getRaster().getDataBuffer()).getData();java.util.Arrays.sort(p);ImageIO.write(o,"png",new File("o.png"));}}

2

C #, 497 byte

Primo post, primo golf. Chiaramente non è il migliore per giocare a golf

Non rispettando davvero le tubazioni. Prende un percorso immagine come input e lo emette con la lettera "o" anteposta al nome.

Funziona meglio con bitmap, risultati di probabilità con gli altri

using System.Linq;using System.Drawing;using System.Runtime.InteropServices;class Program{static void Main(string[]args){using(var im=(Bitmap)Image.FromFile(args[0])){int h=im.Height;int w=im.Width;var b=im.LockBits(new Rectangle(0,0,w,h),System.Drawing.Imaging.ImageLockMode.ReadWrite,System.Drawing.Imaging.PixelFormat.Format32bppRgb);var p=new int[h*w];Marshal.Copy(b.Scan0,p,0,h*w);var q=p.ToList();q.Sort();p=q.ToArray();Marshal.Copy(p,0,b.Scan0,h*w);im.UnlockBits(b);im.Save("o"+args[0]);}}}

1

Haskell, 195 byte

import Data.List
import Graphics.GD
f p=do 
 a<-loadPngFile p;(x,y)<-imageSize a;let l=[(i,j)|j<-[0..y],i<-[0..x]]
 mapM(flip getPixel a)l>>=mapM(\(d,c)->setPixel d c a).zip l.sort;savePngFile"o"a

Questo utilizza la GDlibreria. Utilizzo f <filename>. Il file di input deve essere nel pngformato. Il file di output è denominato o.

Come funziona: semplice, cioè leggi l'immagine, cammina su tutte le coordinate e ottieni i pixel, ordina i pixel, cammina di nuovo sulle coordinate, ma questa volta imposta i pixel nell'ordine in cui appaiono nell'elenco ordinato, scrivi il file su disco.

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.