ピクセルを並べ替える


35

あなたの仕事は、入力画像が与えられると、同じサイズの出力画像を作成するプログラムを作成することです。この場合、すべてのピクセルは16進値で並べられます。

あなたのプログラムは:

  • ピクセルを左から右にソートしてから下にソートするか、最初に列でソートしてから右にソートします。いずれの場合も、左上のピクセルが最小で、右下のピクセルが最大です。
  • 透明度を使用しますが、これは必須ではありません。
  • RGBで並べ替えますが、CMYまたは少なくとも3つの値を持つ他の形式を使用できます。ソートする値を選択できます。(HSVはいくつかの素晴らしい画像を与えるかもしれません)
  • ほとんどのコンピューターで開くことができる既知の画像形式を使用します。

ルール:

  • 出力はディスクに書き込むか、ファイルにパイプできる必要があります。
  • 入力は、イメージへの相対パスの形式でコマンドライン引数として与えられるか、コマンドラインからパイプで渡されます。
  • これはコードゴルフなので、バイト単位の最短コードが勝ちです!

回答:


20

Pyth-10バイト

画像を読み取り、ビットマップを折りたたみ、ソートし、ビットマップを再び分割してから書き込みます。

.wclK'zSsK

明らかな理由でオンラインでは機能しません。入力を画像ファイルへの相対パスとして取得し、出力しo.pngます。

アメリカンゴシックからの出力:


3
写真が動いているという印象を持つのは私だけではないことを願っています
クエンティン

木のように見えます。
ジョーZ.

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

サンプル出力

実行可能なデモ:

このコードの仕組みは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

(作成した空の値を失うために)配列の上位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値を上位4番目の配列から再マッピングして配列に戻し、合計スコア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ŭloEbermann完了。
アプシラーズ

@insertusernamehereああ、ちょっと、小さな画像でしかテストしていません。私のconcat.apply呼び出しはあまりにも多くの引数を提供してconcatおり、JSエンジンはそれを拒否しています。D:ありがとう!これを修正し、2つのスコアに注目します。(そして、私は助けることができてうれしいです!)
apsillers

@insertusernamehereサイズ制限についてのヘッドアップをありがとう。また、大きな画像で動作する少し長いバージョンも公開しました。
-apsillers

@apsillersいいですね。残念ながら再度投票することはできません。:)
ユーザー名をここに挿入します

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を知らないが、ほとんどの言語のように要素ごとにタプルをソートする場合、それらは同等である:hexのような数字は各数字でソートされ、そのうちの2つはタプルの各要素で表される。
マルティセン

@ MichaelStern、Maltysenは正しい。RGBソートと16進数ソートは同等です。R、G、Bの順にソートすると、Hexの場所の値ソートと同じように機能します。
DavidC

OK、私から+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 x 1900ピクセルの画像も処理します。
insertusernamehere

2
今日、それappendChildがその議論を返すことを学びました。非常に便利!あなたは私のエントリを377から354に切り詰める気になりましたが、私はあなたのものを打つことはできません:)。(appendChild-chainingとwithtechnique を使用すると、347まで下げることができますが、それでも13個離れています!)すばらしい仕事です!
-apsillers

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

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追加される-elementに描画しbodyます。

ソースは同じドメイン上にある必要があります。そうしないと、スクリプトがセキュリティ上の問題で停止します。


制限事項

OS X(10.10)上のFirefox 42で、2.5 GHz i7と16 GB RAMを搭載したマシンでテストしました。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バイトを保存しました。おかげar34zfor (a in b)for(;;)
  • 変数に保存して3バイトを保存しdocumentました。
  • これらのいくつかを落とすことによって4バイトを節約しました()
  • タグ付きテンプレート文字列を使用して、オブジェクトの作成を省略し、冗長な別のペアを削除して、10バイトを節約しました。apsillersに感謝します()()
  • ソート後にカラー配列を平坦化するコードの大規模なリファクタリングにより14バイトを節約しましたapsillersYpnypnにお互いをアンダーカットしてくれてありがとう。
  • 各ピクセルの色を取得する-loopをリファクタリングして1バイトを節約しましたfor

1
for-loopsを使用for(k in t)すると、さらにいくつかのバイトを節約できます:)
-ar34z

1
よくやった!いくつかの改善:()inを失いnew Image()ます。使用タグ付きテンプレートの文字列を、あなたの文字列引数のために(createElement`canvas`getContext`2d`)、シングル矢印機能パラメータの括弧を使用しない(ただやるf=u=>{...};括弧のみマルチパラメータまたはゼロパラメータ矢印のfuncsのためのものです)。またfor、角括弧のある1つまたは2つの単一ステートメントループが必要な場合もあります。
apsillers

ああ、実際には、引数がゼロの矢印関数には、2文字の空の括弧の代わりに1文字の仮引数を使用します。(i.onload=$=>...代わりにi.onload=()=>...
アプシラー

私が考える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));uinのすべての配列に対してt、viaへuの引数のリストとして指定します(無制限の数の引数を受け入れて、すべての引数を順番にプッシュするため)。f.pushapplypush
アプシラーズ

4

Bash + GNU utils、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に送られます。


上記がよく知られている画像形式と見なされない場合、必要な変換を追加できます。

Bash + GNU utils + 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
ザック・ゲイツ

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

ピクセルカラーの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バイトを追加します。


なぜintが必要なのかよくわかりません。フロートを使用すると、実際に結果が正しくなるようです。int on SYS/DEFSP.GRPを使用してこのコードを実行するFF000000と、a 00101010が左上に配置され、a が右下に配置されます。これは、明らかに反対の質問です。フロートを使用する00000000FFF8F8F8、左上と右下に配置されます。これは正しいです。(もちろん、これは16進数の色を符号なし/より高いチャネルとして扱います。これはおそらく正しいでしょう。)
snail_

質問は並べ替える特定の順序を指定していないため(そして値が署名されているため、0xFF000000より小さい0x00101010)、とにかく、ここで整数を使用した理由が実際にはわかりません... float配列を使用したときに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

仕組み:簡単です。つまり、画像を読み、すべての座標を調べてピクセルを取得し、ピクセルを並べ替え、座標を再度調べますが、今回は並べ替えられたリストに表示される順序でピクセルを設定し、ファイルに書き込みますディスク。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.