픽셀을 정렬


35

당신의 임무는 입력 이미지가 주어지면 모든 픽셀이 16 진수 값으로 정렬되는 동일한 크기의 출력 이미지를 생성하는 프로그램을 만드는 것입니다.

당신의 프로그램은 :

  • 왼쪽에서 오른쪽으로 픽셀을 정렬 한 다음 아래로 또는 먼저 열에서 정렬 한 다음 오른쪽으로 정렬하십시오. 어쨌든 왼쪽 상단 픽셀이 가장 작고 오른쪽 하단이 가장 큽니다.
  • 투명도를 사용하지만 필수는 아닙니다.
  • RGB로 정렬하지만 CMY 또는 3 개 이상의 값을 가진 다른 형식을 사용할 수 있습니다. 정렬 할 값을 선택할 수 있습니다. (HSV는 멋진 이미지를 줄 수 있습니다)
  • 대부분의 컴퓨터에서 열 수있는 잘 알려진 이미지 형식을 사용하십시오.

규칙 :

  • 출력은 디스크에 쓰거나 파일로 파이프 할 수 있어야합니다.
  • 입력은 이미지에 대한 상대 경로의 형태로 명령 줄 인수로 제공되거나 명령 줄에서 파이프됩니다.
  • 이것은 코드 골프이므로 바이트 단위의 가장 짧은 코드가 이깁니다!

답변:


20

Pyth-10 바이트

이미지를 읽고, 비트 맵을 축소하고, 정렬 한 다음 비트 맵을 다시 분할 한 다음 씁니다.

.wclK'zSsK

명백한 이유로 온라인으로 작동하지 않습니다. 입력을 이미지 파일의 상대 경로로 가져와로 출력합니다 o.png.

미국 고딕의 결과물 :


3
사진이 움직이는 느낌을 가진 유일한 사람이
Quentin

나무처럼 보입니다.
Joe Z.

19

자바 스크립트 (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)}}

샘플 출력

실행 가능한 데모 :

이 코드의 작동 방식은 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,0],..., [R,G,B,A],[R,G,B,A],[R,G,B,A],...]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               extract & flatten these sorted pixels

우리는 배열의 4 분의 1을 훑어 냈습니다 (빈 값을 잃어 버렸습니다) [].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 님.
apillers

@insertusername 여기, 작은 이미지에서만 테스트했습니다. 내 concat.apply전화가 너무 많은 인수를 제공 concat하고 있으며 JS 엔진이이를 거부합니다. D:감사! 나는 그것을 고치고 두 점수를 주목할 것이다. (그리고 도움을 드릴 수있어 기쁩니다!)
apsillers

@insertusername 여기 크기 제한에 대한 헤드 업에 감사드립니다. 또한 더 큰 이미지에서 작동하는 약간 더 긴 버전도 게시했습니다.
apillers

@apsillers 좋은 일. 불행히도 다시 공감할 수 없습니다. :)
insertusernamehere

14

Mathematica 86 83 72 바이트

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

@Martin Buttner 덕분에 14 바이트가 절약되었습니다.


이미지 자체가 입력됩니다. 대안 적으로, 이미지를 포함하는 변수가 사용될 수있다.

고딕


도전 과제는 픽셀을 16 진수 값으로 정렬하도록 지정하지만이 글을 올바르게 읽으면 {R, G, B} 또는 {R, G, B, alpha} 목록에 Mathematica의 기본 정렬을 사용합니다. 이것들이 동등하다는 것은 분명하지 않습니다.
마이클 스턴

@MichaelStern 나는 Mathematica를 모른다. 그러나 대부분의 언어처럼 튜플을 요소별로 정렬하면 그것들은 동등하다.
Maltysen

@MichaelStern, Maltysen이 정확합니다. RGB 정렬과 16 진수 정렬은 동일합니다. R, G, B 값으로 정렬 한 다음 B 값은 16 진수의 자리 값 정렬과 동일하게 작동합니다.
DavidC

좋아, +1
Michael Stern

ImageDataArrayReshape중위 표기법을 사용할 수 있습니다. Flatten에 할당하여 몇 바이트를 저장할만큼 깁니다 f. 그리고 실제로 필요 "Byte"합니까? 기본적으로 [0,1]정렬 및 이미지 재구성이 여전히 잘 작동 하도록 채널 값의 크기를 조정하지 않습니까?
Martin Ender

5

자바 스크립트 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
}

@insertusername 여기 최신 Firefox에서 작동합니다. 답과 마찬가지로 캔버스를 추가 할 본문이 있고 소스 이미지가 동일한 도메인에서 온 것으로 가정합니다.
Dendrobium

+1 매우 매끄러운 솔루션. 또한 최대 1600 x 1900px의 이미지를 처리합니다.
insertusernamehere 여기에

2
오늘 나는 그것이 appendChild그 주장 을 돌려주는 것을 배웠다 . 매우 유용한! 당신은 저에게 377에서 354까지의 나의 입장을 깨우도록 영감을 주었지만, 나는 당신의 것을 이길 수 없습니다 :). (귀하의 appendChild체인과 with기술을 사용하면 347로 줄일 수 있지만 여전히 13 거리에 ​​있습니다!) 훌륭합니다!
apillers

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

여기에 이미지 설명을 입력하십시오

나는 보통 C에서 골프를 타지 않지만 어제이 도전에 답 하고 새로운 장난감으로 계속 놀고 싶었습니다. :)

5 바이트 절약에 도움을 주신 @ pseudonym117에게 감사합니다


while의 끝을 로 변경하여 1 바이트를 절약 for(;;SDL_Flip(s));할 수 int있으며 메소드에서 생략 C하고 4를 더 절약 할 수 있다고 생각합니다 .
pseudonym117

4

자바 스크립트 (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에 추가 된 -element에 결과를 그립니다 body.

소스가 동일한 도메인에 있어야합니다. 그렇지 않으면 스크립트에 보안 문제가 발생합니다.


한계

2.5GHz i7 및 16GB RAM이있는 시스템의 OS X (10.10)의 Firefox 42에서 테스트했습니다. Firefox가 스크립트 실행을 계속하도록 요구하지 않고 처리 할 수있는 최대 이미지 크기는 1600 x 1932 픽셀 입니다.


언 골프

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

산출

더 나은 비교를 위해 나는 또한 " American Gothic "을 예제 소스로 사용했습니다.

여기에 이미지 설명을 입력하십시오


편집

  • 대신에 24 바이트절약했습니다 . ar34z 덕분에for (a in b)for(;;)
  • 변수 에 저장 하여 3 바이트절약했습니다document .
  • 이들 중 일부를 삭제하여 4 바이트절약했습니다() .
  • 태그가있는 템플릿 문자열 을 사용하여 10 바이트절약 하고 객체 생성시 생략하고 다른 중복 항목을 제거했습니다 . apsillers 에게 감사합니다 .()()
  • 정렬 후 색상 배열을 평평하게하는 코드를 리팩토링하여 14 바이트절약했습니다 . 서로 언더컷 을 한 apsillersYpnypn 에게 많은 감사를드립니다 .
  • 저장된 1 바이트 리팩토링하여 for각 화소의 색을 얻을 -loop.

1
당신은 사용에 대한-루프를 최소화 할 수있는 for(k in t)몇 가지 더 바이트 : 절약 할 수있는
ar34z

1
잘 하셨어요! 일부 개선 사항은 다음을 잃게 ()new Image(); 사용 태그 템플릿 문자열을 당신의 문자열 인수 ( createElement`canvas`, getContext`2d`) 하나의 화살표 기능 매개 변수에 대한 괄호를 사용하지 않는 (단지 할 f=u=>{...}; 괄호는 다중 매개 변수 또는 제로 매개 변수 화살표 funcs위한 것입니다). 또한 for대괄호 가있는 하나 또는 두 개의 단일 문 루프가있을 수 있으며 필요하지 않습니다.
apillers

실제로, 인수가없는 화살표 펑크의 경우, 두 문자로 된 빈 괄호 대신 단일 문자 더미 인수를 사용하십시오. ( 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));있는 모든 배열은 "밝히는 ut공급 u에 인수 목록 등 f.push을 통해 apply(이후 push인수의 무제한의 수를 수용하고 그것을 위해 그들 모두를 밀어 수 있습니다.)
apillers

4

배쉬 + GNU 유틸리티, 80

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

이것은 입 / 출력 형식이 ImageMagick 픽셀 열거 .txt 형식이라고 가정합니다. 입력은 파일 이름으로 전달되고 출력은 STDOUT으로 이동합니다.


위의 내용이 잘 알려진 이미지 형식으로 간주되지 않으면 필요한 변환을 추가 할 수 있습니다.

배쉬 + 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

파이썬 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)))대신 줄을 따라 무언가를 할 수 있어야합니다 (방금 일어 났으 므로 변수를 혼합했을 수 있습니다).
Kade

당신이 그것을 썼을 때, 그것은 작동하지 않았지만 (색인이 범위를 벗어났습니다), 나는 변수를 바꾸려고 시도하지 않았습니다 (현재 많은 시간이 없습니다). @ Shebang
Zach Gates

3

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

픽셀 색상의 16 진수 값을 배열에 배치합니다. 배열이 정렬되고 색상이 이미지의 픽셀로 다시 매핑됩니다. 결과 이미지의 이름은입니다 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 바이트를 추가하는 정수를 사용해야합니다.


왜 정수가 필요한지 잘 모르겠습니다. float를 사용하면 실제로 결과가 올바른 것 같습니다. 에서의 int를 사용하여이 코드를 실행 SYS/DEFSP.GRP두고 FF000000상단에있는 것은 왼쪽과 00101010질문의 명백한 반대 오른쪽 아래있다. 플로트를 사용하면 00000000왼쪽 상단과 FFF8F8F8오른쪽 하단에 배치됩니다. (물론 이것은 16 진수 색상을 부호없는 / 높은 채널로 취급합니다. 아마 맞을 것입니다.)
달팽이 _

나는 질문이 정렬 할 특정 순서를 지정하지 않기 때문에 (그리고 값이 부호 0xFF000000가 붙어서보다 작기 때문에 0x00101010) 유효 하지만 어쨌든 정수를 사용한 이유는 실제로 확실하지 않습니다 ... float 배열을 사용할 때 GLOAD가 부호없는 값을 어떻게 사용했는지 이해하지 못하고 작동하지 않는다고 가정했습니다.
12Me21

2

자바, 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

하스켈, 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입니다.

작동 방식 : 간단하게, 즉 그림을 읽고, 모든 좌표를 걷거나 픽셀을 가져오고, 픽셀을 정렬하고, 좌표를 다시 걷지 만, 이번에는 정렬 된 목록에 나타나는 순서대로 픽셀을 설정하고 파일을 디스크.

여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.