Сортуйте пікселі


35

Ваше завдання - створити програму, яка, задавши вхідне зображення, створить вихідне зображення однакового розміру, де всі пікселі упорядковані за шістнадцятковим значенням.

Ваша програма може:

  • Сортуйте пікселі зліва направо, а потім вниз або спочатку сортуйте стовпці, а потім праворуч. У будь-якому випадку верхній лівий піксель найменший, а нижній правий - найбільший.
  • Використовуйте прозорість, але це не потрібно.
  • Сортувати за RGB, але ви можете використовувати CMY або будь-який інший формат із щонайменше 3 значеннями. Ви можете вибрати, за якими значеннями слід сортувати. (HSV може дати кілька приємних зображень)
  • Використовуйте будь-який відомий формат зображення, який може відкрити більшість комп'ютерів.

Правила:

  • Вихід повинен бути записаний на диск або бути переданим у файл.
  • Введення задається у вигляді аргументу командного рядка у вигляді відносного шляху до зображення, або передається з командного рядка.
  • Це код гольфу, тому найкоротший код у байтах виграє!

Відповіді:


20

Pyth - 10 байт

Читає зображення, згортає растрові карти, сортує, а потім розбиває растрові карти, а потім пише.

.wclK'zSsK

Не працює в Інтернеті з зрозумілих причин. Приймає введення як відносний шлях до файлу зображення та виводить у нього o.png.

Вихід з американської готики:


3
Я сподіваюся, що я не єдиний, хто справляє враження, що картина рухається ...
Квентін

Це схоже на дерево.
Джо З.

19

JavaScript (ES6), 383 377 354 байт

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

sample output

Демонстраційна демонстрація:

Як цей код працює - це використовувати getImageDataдля отримання масиву форми

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

І mapце до масиву форми

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

Так що значення R відображаються в масиви набору RGBA, а значення B, G і A перетворюються на масиви мінімального значення нульового значення. Коли ми сортуємо цей масив, усі [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],
 [0,0,0,0],..., [R,G,B,A],[R,G,B,A],[R,G,B,A],...]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               extract & flatten these sorted pixels

Ми пропускаємо верхню четверту частину масиву (щоб втратити порожні створені нами значення), вирівнюємо її [].concat.applyі знову закінчуємо масивом першої форми, але на цей раз він відсортований.

Трохи де-гольф із пробілом та коментарями:

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

Зауважте, що більшість браузерів не може запустити цей код для великих зображень, оскільки він передає величезну кількість аргументів [].concat. Коли середовище браузера не дає достатньої пам’яті для всіх аргументів, альтернативним підходом є повторне відображення значень RGBA з верхнього четвертого масиву назад на масив, на загальний бал 361 байт :

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

Ми просто замінити [].concat(...{stuff}).slice(12*w*h)з {stuff}.map((v,i,A)=>A[3*w*h+(i>>2)][i%4]).)


Чи можете ви включити приклад результату?
Paŭlo Ebermann

@ PaŭloEbermann Готово.
апспіллери

@insertusernamehere О, давно, я перевіряв лише невеликі зображення. Мій concat.applyдзвінок надає занадто багато аргументів, concatі двигун JS відкидає його. D:Спасибі! Я виправлю це і відзначу два бали. (І я радий, що можу допомогти!)
apsillers

@insertusernamehere Дякую за загальну інформацію про обмеження розміру; Зараз я також опублікував трохи більш довгу версію, яка працює на великих зображеннях.
апсилери

@apsillers Приємна робота. На жаль, не можна повторно подати пропозицію. :)
insertusernamehere

14

Mathematica 86 83 72 байти

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

З 14 байтами збережено завдяки @Martin Buttner.


Приклад

Сам образ вводиться. Альтернативно, може бути використана змінна, що містить зображення.

gothic


Завдання вказує, що пікселі будуть відсортовані за шістнадцятковим значенням, але якщо я прочитав це правильно, ви використовуєте сортування Mathematica за замовчуванням для списків {R, G, B} або {R, G, B, alpha}. Мені не ясно, що це рівнозначно.
Майкл Стерн

@MichaelStern Я не знаю Mathematica, але якщо вона сортує кортежі елементарно, як і більшість мов, вони є рівнозначними: Числа, як шістнадцяткові, сортуються за кожною цифрою, дві з яких представлені кожним елементом в кортежі.
Мальтісен

@MichaelStern, Мальтісен правильний. Сортування RGB та Hex сортування еквівалентні: сортування за R, потім G, а потім B значення працює так само, як сортування значення місця у Hex.
DavidC

Гаразд, +1 від мене.
Майкл Стерн

ImageDataі ArrayReshapeможе використовувати інфіксацію. Flattenдостатньо довго, щоб зберегти пару байтів, призначивши його f. А вам насправді потрібно "Byte"? Чи не буде за замовчуванням просто масштабувати значення каналу [0,1]таким чином, щоб сортування та реконструкція зображення все-таки спрацювали б чудово?
Мартін Ендер

5

Javascript ES6, 334 байти

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

Безголівки:

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
}

@insertusernamehere Він працює на останньому Firefox. Як і у вашій відповіді, він передбачає, що є тіло для додавання полотна, а вихідне зображення - з того самого домену.
Дендробіум

+1 Дуже гладке рішення. Він також обробляє зображення розміром до 1600 х 1900 пікселів.
вставитикористувач туди

2
Сьогодні я дізнався, що appendChildповертає свої аргументи. Дуже корисний! Ти надихнув мене знебарвити свій запис з 377 до 354, але я не можу зовсім перемогти тебе :). (Коли я використовую вашу техніку appendChildланцюга і withтехніку, я можу знизити її до 347, але все одно за 13!) Відмінна робота!
апспіллери

5

C (використовуючи SDL1.2), 333 322 315 байт

C, швидше за все, не "найгостріший ніж у полиці" для такої роботи, я хотів би спробувати все-таки. Поради щодо вдосконалення моєї відповіді вітаються. Програма отримує назву вхідного образу зображення як аргумент 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));}

компілювати та запускати: gcc -I/usr/include/SDL snippet.c -lSDL -lSDL_image && ./a.out

введіть тут опис зображення

Зазвичай я не гольфу в С, але я вчора тільки відповів на це виклик і просто хотів продовжувати грати з цією новою іграшкою :)

дякую @ pseudonym117 за те, що він допомагає мені зберегти 5 байт


Можна зберегти 1 байт, змінивши whileв кінці for(;;SDL_Flip(s));, і я вважаю, що ви можете опустити intметод Cі зберегти ще 4.
псевдонім117

4

JavaScript (ES6), 452 480 484 487 511 байт

Ого, це стало довше, ніж очікувалося:

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

Функція приймає URL як свій вхід f('test.jpg');і малює результат у canvas-елементі, який додається до body.

Зверніть увагу, що джерело має бути в одному домені, або сценарій зупиниться з проблемою безпеки.


Обмеження

Я протестував його в Firefox 42 на OS X (10.10) на машині з i7 та 16 ГБ оперативної пам’яті. Максимальний розмір зображення, який я міг обробити без Firefox з проханням продовжити виконання сценарію, був 1600 x 1932 px .


Безумовно

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

Вихідні дані

Для кращого порівняння я також взяв " американську готику " як приклад джерело:

введіть тут опис зображення


Правки

  • Збережено 24 байти за допомогою, for (a in b)а не for(;;). Завдяки ar34z
  • Збережено 3 байти , зберігаючи documentзмінну.
  • Збережено 4 байти , скинувши деякі з них ().
  • Збережено 10 байт за допомогою тегів рядків тегів , опускаючи ()створення об’єкта та видаляючи ще одну пару зайвих (). Завдяки апсилерам .
  • Збережено 14 байт за допомогою масового рефакторингу коду, який вирівнює кольоровий масив після сортування. Велике спасибі апсилерам та Ypnypn за те, що вони підрізали один одного.
  • Збережено 1 байт , рефакторинг на for-loop, який отримує кольори кожного пікселя.

1
Ви можете мінімізувати for(k in t)
фор

1
Хороша робота! Деякі вдосконалення: втратити ()в new Image(); використовуйте позначені рядки шаблону для ваших аргументів рядка ( createElement`canvas`, getContext`2d`), не використовуйте круглі дужки для параметрів функцій однієї стрілки (просто робіть f=u=>{...}; парени призначені лише для функцій стрілок з кількома параметрами або нульовими параметрами). Також у вас можуть бути одна або дві forпетлі з одним твердженням, які мають дужки, які не потрібні.
апсилери

О, насправді, для функцій стрілки з нульовим аргументом використовуйте однофакторний манекен-аргумент замість порожніх паролів з двома знаками. ( i.onload=$=>...замість i.onload=()=>...)
apsillers

Я думаю, що for(l in u)f.push(u[l]);може статиfor(z of u)f.push(z);
Ypnypn

@Ypnypn Це може бути навіть менше , ніж :). - for(u of t)for(z of u)f.push(z)досить недовго, але його можна скоротити далі t.map(u=>u.map(z=>f.push(z))). У багатьох випадках використання .mapабо .someфункція зі стрілкою буде коротшою, ніж використання forциклу. Якщо ви хочете піти на насправді з розуму, ви можете заощадити ще більше тут з t.map(u=>f.push.apply(f,u));якої говорить : «Для кожного масиву uв t, поставки uу вигляді списку аргументів з f.pushдопомогою apply(так як pushможе приймати необмежену кількість аргументів і штовхає їх все в порядку).
апсилери

4

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

Це передбачає, що формат вводу / виводу є у форматі .txt пікселів переліку пікселів ImageMagick. Вхід передається як ім'я файлу, а вихід переходить до STDOUT.


Якщо вищезгадане не вважається відомим форматом зображення, тоді ми можемо додати необхідні перетворення:

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

Вхід і вихід визначаються як імена файлів. ImageMagick визначає, які формати файлів використовувати для переданих розширень файлів, тому ми можемо використовувати будь-які поширені:

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

Отриманий o.png виглядає так:

введіть тут опис зображення


3

Python 2, 128 байт

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без розширення, результатом буде файл, названий bбез розширення.

Американська готика Американська готика (сортування)


Я не перевіряв, але ви повинні мати можливість щось робити a.putdata(sorted(b[f/c,f%d]for f in range(d*c)))натомість (я просто прокинувся, тому, можливо, я змішав змінні).
Кейд

Як ви писали це, він не працював (індекс поза діапазоном), але я не намагався перемикати будь-які змінні (у мене зараз мало часу). @Shebang
Zach Gates

3

Java, 316 байт

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

Розміщує шістнадцяткові значення кольорів пікселів у масиві. Масив сортується, а кольори переставляються до пікселів на зображенні. Назва отриманого зображення a.png.

введення жовтих тюльпанів вихід жовтих тюльпанів
Американська готика введіть тут опис зображення


3

SmileBASIC, 39 35 байт

Припустимо, що зображення завантажено на графічну сторінку 512 * 512:

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

Пояснили:

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

Це так просто! На жаль, нам доводиться використовувати цілі числа, що додає 4 байти до розміру програми завдяки суфіксам типу.


Я не дуже впевнений, чому потрібні інти. Схоже, що використання плавців фактично отримує результати правильні. Запуск цього коду за допомогою ints on SYS/DEFSP.GRPставить a FF000000вгорі зліва та a 00101010в нижньому правому куті, що є явною протилежністю питання. Використання поплавців ставить 00000000у верхньому лівому і FFF8F8F8правому нижньому куточках, що правильно. (Зрозуміло, це трактує шістнадцяткові кольори як непідписаний / вищий канал більше, що, мабуть, правильно.)
snail_

Я думаю, що це справедливо, оскільки питання не визначає конкретний порядок сортування за (і оскільки значення підписані, 0xFF000000менші за 0x00101010), але все одно, я не впевнений, чому я тут використовував цілі числа ... Я думаю, що в той час, коли я не розумів, як GLOAD використовував непідписані значення, коли ви використовували плаваючий масив, і просто припускав, що він не працює.
12Me21

2

Java, 424 417 404 байт

Ну, це не мова, в яку ви хочете пограти в гольф ...

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 байт

Перший пост, перший гольф. Очевидно, не найкраще для гольфу

Не дуже поважаючи трубопроводи. Приймає шлях зображення як вхідний і виводить його з буквою "o", що додається до імені.

Краще працює з растровими карти, шанси на результати з іншими

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 байт

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

Для цього використовується GDбібліотека. Використання f <filename>. Вхідний файл повинен бути у pngформаті. Вихідний файл названий o.

Як це працює: прямо, тобто прочитайте картинку, пройдіть усі координати і отримайте пікселі, відсортуйте пікселі, знову пройдіть по координатах, але цього разу встановіть пікселі у тому порядку, який вони відображаються у відсортованому списку, запишіть файл у диск.

введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.