Trier les pixels

35

Votre tâche consiste à créer un programme qui, à partir d’une image d’entrée, crée une image de sortie de la même taille, dans laquelle tous les pixels sont classés par valeur hexadécimale.

Votre programme peut:

  • Triez les pixels de gauche à droite et ensuite vers le bas ou commencez par les colonnes puis par la droite. Dans tous les cas, le pixel en haut à gauche est le plus petit et le coin en bas à droite est le plus grand.
  • Utilisez la transparence, mais ce n'est pas obligatoire.
  • Triez par RVB, mais vous pouvez utiliser CMJ ou tout autre format avec au moins 3 valeurs. Vous pouvez choisir les valeurs à trier. (HSV peut donner de belles images)
  • Utilisez n’importe quel format d’image connu que la plupart des ordinateurs peuvent ouvrir.

Règles:

  • La sortie doit être écrite sur le disque ou raccordée à un fichier.
  • L'entrée est donnée sous forme d'argument de ligne de commande, sous la forme d'un chemin relatif à l'image ou acheminé depuis la ligne de commande.
  • C'est le code de golf, donc le code le plus court en octets gagne!
vrwim
la source
2
En relation.
Martin Ender

Réponses:

20

Pyth - 10 octets

Lit les images, réduit les images, trie, puis sépare à nouveau les images, puis écrit.

.wclK'zSsK

Ne fonctionne pas en ligne pour des raisons évidentes. Prend l'entrée en tant que chemin relatif au fichier image et en génère le résultat o.png.

Sortie du gothique américain:

Maltysen
la source
3
J'espère que je ne suis pas le seul à avoir l'impression que la photo bouge ...
Quentin
Cela ressemble à du bois.
Joe Z.
19

JavaScript (ES6), 383 377 354 octets

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)}}

exemple de sortie

Démo exécutable:

Comment fonctionne ce code est d'utiliser getImageDatapour obtenir un tableau de la forme

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

Et mapcela à un tableau de la forme

[[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],
 ...]

Ainsi, les valeurs R sont mappées sur les tableaux de l'ensemble RGBA et les valeurs B, G et A se transforment en tableaux de valeurs minimales nuls. Lorsque nous trions ce tableau, tous les [0,0,0,0]tableaux sont classés en bas et les tableaux de valeurs réelles, normalement en haut:

[[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

Nous parcourons le quart supérieur du tableau (pour perdre les valeurs vides que nous avons créées), l'aplatissons avec [].concat.apply et un tableau de la première forme, mais cette fois, il est trié.

Légèrement défiguré avec des espaces et des commentaires:

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)
  }
}

Notez que la plupart des navigateurs peuvent ne pas exécuter ce code pour les images volumineuses, car il transmet un grand nombre d'arguments [].concat. Lorsque l'environnement du navigateur n'autorise pas suffisamment de mémoire pour tous les arguments, une autre approche consiste à réaffecter les valeurs RGBA des quatrièmes premiers tableaux au tableau, pour un score total de 361 octets :

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)}}

Nous remplaçons simplement le [].concat(...{stuff}).slice(12*w*h)avec {stuff}.map((v,i,A)=>A[3*w*h+(i>>2)][i%4]).)

apsillers
la source
Pourriez-vous inclure un exemple de sortie?
Paŭlo Ebermann
@ PaŭloEbermann Fait.
apsillers
@ insertusernamehere Oh, dang, je n'ai testé que sur de petites images. Mon concat.applyappel fournit trop d'arguments à concatet le moteur JS le rejette. D:Merci! Je vais arranger ça et noter les deux partitions. (Et je suis heureux de pouvoir aider!)
apsillers
@insertusernamehere Merci pour le heads-up sur la limitation de taille; J'ai également publié une version légèrement plus longue qui fonctionne sur des images plus grandes.
apsillers
@apsillers Beau travail. Je ne peux plus voter, malheureusement. :)
insertusernamehere
14

Mathematica 86 83 72 octets

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

Avec 14 octets sauvegardés grâce à @Martin Buttner.


Exemple

L'image elle-même est entrée. Alternativement, une variable contenant l'image pourrait être utilisée.

gothique

DavidC
la source
Le défi spécifie que les pixels doivent être triés par valeur hexadécimale, mais si je lis ceci correctement, vous utiliserez le tri par défaut de Mathematica pour les listes {R, G, B} ou {R, G, B, alpha}. Ce n'est pas clair pour moi que ce sont équivalents.
Michael Stern
@MichaelStern Je ne connais pas Mathematica, mais si elle trie les tuples élément par élément comme dans la plupart des langues, elles sont équivalentes: les nombres comme hex sont triés par chaque chiffre, deux d'entre eux étant représentés par chaque élément du tuple.
Maltysen
@MichaelStern, Maltysen est correct. Le tri RGB et le tri Hex sont équivalents: le tri par R, puis par G, puis la valeur B fonctionne exactement comme le tri de valeur de position dans Hex.
DavidC
OK, +1 de moi.
Michael Stern
ImageDataet ArrayReshapepourrait utiliser la notation infixe. Flattenest assez long pour sauvegarder quelques octets en l’affectant à f. Et avez-vous réellement besoin "Byte"? Par défaut, les valeurs de canal ne [0,1]seraient -elles pas simplement dimensionnées de manière à ce que le tri et la reconstruction des images fonctionnent toujours correctement?
Martin Ender
5

Javascript ES6, 334 octets

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
}
Dendrobium
la source
@insertusernamehere Cela fonctionne sur le dernier Firefox. À l'instar de votre réponse, elle suppose qu'il existe un corps auquel ajouter le canevas et que l'image source provient du même domaine.
Dendrobium
+1 Solution très élégante. Il traite également les images jusqu'à 1600 x 1900px.
insertusernamehere
2
Aujourd'hui j'ai appris que appendChildretourne son argument. Très utile! Vous m'avez inspiré de réduire mon entrée de 377 à 354, mais je ne peux pas battre le vôtre :). (Quand j'utilise votre appendChildchaîne etwith technique technique, je peux le réduire à 347, mais il en reste 13!) Excellent travail!
apsillers
5

C (utilisant SDL1.2), 333 322 315 octets

C n’est probablement pas le «couteau le plus tranchant de l’étagère» pour ce genre de travail, j’ai voulu essayer quand même. Les astuces pour améliorer ma réponse sont les bienvenues. Le programme obtient le nom du fichier image d'entrée en tant qu'argument 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));}

compiler et exécuter: gcc -I/usr/include/SDL snippet.c -lSDL -lSDL_image && ./a.out

entrez la description de l'image ici

Je ne joue généralement pas au C, mais je viens de répondre. relever ce défi joue hier et je voulais juste continuer à jouer avec ce nouveau jouet :)

merci à @ pseudonym117 de m'avoir aidé à économiser 5 octets

dieter
la source
Vous pouvez économiser 1 octet en changeant votre mot whileà la fin for(;;SDL_Flip(s));, et je crois que vous pouvez omettre intla méthode Cet en économiser 4 de plus.
pseudonym117
4

JavaScript (ES6), 452 480 484 487 511 octets

Wow, cela a pris plus de temps que prévu:

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 fonction prend une URL en entrée f('test.jpg');et dessine le résultat dans un canvasélément qui est ajouté à l'élément.body .

Notez que la source doit être sur le même domaine ou le script s’arrêtera avec un problème de sécurité.


Limites

Je l'ai testé sous Firefox 42 sous OS X (10.10) sur un ordinateur doté de 2,5 GHz i7 et de 16 Go de RAM. La taille d'image maximale que je pouvais traiter sans que Firefox ne demande à continuer l'exécution du script était de 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)
    }
}

Sortie

Pour une meilleure comparaison, j'ai également pris le " gothique américain " comme exemple:

entrez la description de l'image ici


Édite

  • Sauvegardé 24 octets en utilisant for (a in b)au lieu de for(;;). Merci à ar34z
  • Sauvegardé 3 octets en stockant documentdans une variable.
  • Sauvegardé 4 octets en supprimant certains d'entre eux ().
  • Sauvegardé 10 octets en utilisant des chaînes de modèles étiquetées , en omettant la ()création d'objet lors de la suppression d'un autre couple redondant (). Merci à apsillers .
  • 14 octets enregistrés grâce à une refactorisation massive du code qui aplatit le tableau de couleurs après le tri. Merci beaucoup à apsillers et à Ypnypn pour .
  • Sauvegardé 1 octet en refacturant la for-loop qui récupère les couleurs de chaque pixel.
insertusernamehere
la source
1
Vous pouvez minimiser l'utilisation des boucles for, for(k in t)ce qui économisera quelques octets supplémentaires :)
ar34z
1
Bon travail! Quelques améliorations: perdre l' ()en new Image(); utiliser des chaînes de modèles étiquetés pour vos arguments de chaîne ( createElement`canvas`, getContext`2d`), n'utilisez pas de parenthèses pour les paramètres de fonction flèche unique (il suffit de le faire f=u=>{...}; les parenthèses ne concernent que les fonctions de flèche à paramètres multiples ou à paramètres zéro). Vous pouvez également avoir une ou deux forboucles à une seule instruction avec des crochets, ce qui n'est pas nécessaire.
apsillers
Oh, en fait, pour les fonctions de flèche à zéro argument, utilisez un argument factice à un caractère au lieu de parenthèses vides à deux caractères. ( i.onload=$=>...au lieu de i.onload=()=>...)
apsillers
Je pense for(l in u)f.push(u[l]);peut devenirfor(z of u)f.push(z);
Ypnypn
@Ypnypn Il peut même être plus court que ça :). - for(u of t)for(z of u)f.push(z)est assez court, mais on peut le raccourcir davantage t.map(u=>u.map(z=>f.push(z))). Dans beaucoup de cas, utiliser .mapou .someavec une fonction flèche sera plus court que d'utiliser une forboucle. Si vous voulez devenir vraiment fou, vous pouvez économiser encore plus ici avec t.map(u=>f.push.apply(f,u));ce qui suit: "Pour chaque tableau udans t, fournissez uune liste d'arguments à f.pushvia apply(car pushpeut accepter un nombre illimité d'arguments et les met dans l'ordre).
apsillers
4

Bash + utilitaires GNU, 80

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

Cela suppose que le format d'entrée / sortie est au format .txt d'énumération de pixels ImageMagick. L'entrée est passée en tant que nom de fichier et la sortie passe à STDOUT.


Si ce qui précède n'est pas considéré comme un format d'image bien connu, nous pouvons ajouter les conversions nécessaires:

Bash + utilitaires 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

L'entrée et la sortie sont spécifiées en tant que noms de fichiers. ImageMagick détermine les formats de fichiers à utiliser en fonction des extensions de fichiers transmises. Nous pouvons donc utiliser les formats les plus courants:

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

Le o.png résultant ressemble à ceci:

entrez la description de l'image ici

Trauma numérique
la source
3

Python 2, 128 octets

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')

À condition que l'image soit un fichier nommé asans extension, la sortie sera un fichier nommé bsans extension.

gothique americain Gothique américain (triés)

Zach Gates
la source
Je n'ai pas vérifié, mais vous devriez pouvoir faire quelque chose comme ça a.putdata(sorted(b[f/c,f%d]for f in range(d*c)))(je viens de me réveiller, alors j'ai peut-être mélangé les variables).
Kade
Comme vous l'avez écrit, cela n'a pas fonctionné (index hors limites), mais je n'ai pas essayé de changer de variable (je n'ai pas beaucoup de temps pour le moment). @Shebang
Zach Gates
3

Java, 316 octets

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"));}}

Place les valeurs hexadécimales des couleurs de pixel dans un tableau. Le tableau est trié et les couleurs sont remappées sur les pixels de l'image. Le nom de l'image résultante est a.png.

entrée tulipes jaunes sortie tulipes jaunes
Entrée gothique américaine entrez la description de l'image ici

TNT
la source
3

SmileBASIC, 39 35 octets

En supposant que l'image soit chargée sur la page graphique 512 * 512:

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

A expliqué:

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

C'est si simple! Malheureusement, nous devons utiliser des entiers, ce qui ajoute 4 octets à la taille du programme en raison des suffixes de type.

12Me21
la source
Je ne sais pas vraiment pourquoi les ints sont nécessaires. Il semble que l'utilisation de floats donne les résultats corrects. Exécuter ce code en utilisant ints on SYS/DEFSP.GRPmet un FF000000en haut à gauche et un 00101010en bas à droite, ce qui est le contraire apparent de la question. Utiliser des flotteurs met 00000000en haut à gauche et FFF8F8F8en bas à droite, ce qui est correct. (Bien sûr, cela traite les couleurs hexadécimales comme des canaux non signés / supérieurs, ce qui est probablement correct.)
snail_
Je pense que cela est valable, car la question ne spécifie pas un ordre spécifique de tri (et puisque les valeurs sont signées, 0xFF000000est plus petit que 0x00101010) mais de toute façon, je ne suis pas sûr de savoir pourquoi j'ai utilisé des entiers ici ... À l'époque, je ne comprenais pas comment GLOAD utilisait des valeurs non signées lorsque vous utilisiez un tableau flottant, et supposais simplement que cela ne fonctionnait pas.
12Me21 le
2

Java, 424 417 404 octets

Eh bien, ce n'est pas une langue dans laquelle vous voulez jouer au 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"));}}
Peter Lenkefi
la source
2

C #, 497 octets

Premier post, premier golf. Ce n'est clairement pas le meilleur pour le golf

Pas vraiment respecter la tuyauterie. Prend un chemin d’image en tant qu’entrée et le sort avec la lettre "o" précédée du nom.

Fonctionne mieux avec les bitmaps, les résultats de cotes avec les autres

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]);}}}
Cylianna
la source
1

Haskell, 195 octets

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

Cela utilise la GDbibliothèque. Utilisation f <filename>. Le fichier d'entrée doit être au pngformat. Le fichier de sortie est nomméo .

Comment ça marche: simple, c'est-à-dire lire l'image, parcourir toutes les coordonnées et obtenir les pixels, trier les pixels, repasser sur les coordonnées, mais cette fois, réglez les pixels dans l'ordre dans lequel ils apparaissent dans la liste triée, écrivez le fichier disque.

entrez la description de l'image ici

nimi
la source