Tüm renklerle görüntüler


433

Allrgb.com'daki resimlere benzer şekilde, her pikselin benzersiz bir renk olduğu resimleri yapın (iki kez renk kullanılmaz ve renk yoktur).

Çıktının ekran görüntüsü veya dosyasıyla birlikte bu tür bir görüntüyü üreten bir program verin (PNG olarak yükleyin).

  • Görüntüyü tamamen algoritmik olarak oluşturun.
  • Görüntünün 256 × 128 olması (veya ekran görüntüsü alınabilen ve 256 × 128'de kaydedilmiş olan ızgara)
  • Tüm 15 bit renkleri kullan *
  • Harici girişe izin verilmez (web sorguları, URL'ler veya veritabanları da yoktur)
  • Gömülü görüntüye izin verilmez (görüntü olarak kaynak kodu, örneğin Piet )
  • Dithering izin verilir
  • Bu kısa bir kod yarışması değil, oy vermenize rağmen.
  • Gerçekten bir meydan okumaya hazırsanız, 512 × 512, 2048 × 1024 veya 4096 × 4096 (3 bitlik artışlarla) yapın.

Puanlama oylama gereğidir. En zarif kod ve / veya ilginç algoritma ile yapılan en güzel resimler için oy verin.

İlk önce güzel bir görüntü oluşturduğunuz ve ardından tüm pikselleri mevcut renklerden birine sığdıran iki aşamalı algoritmalara izin verilir, ancak şıklık puanları kazanmazsınız.

* 15 bit renkler, tümü eşit adımlarda ve eşit aralıklarda 32 kırmızı, 32 yeşil ve 32 mavinin karıştırılmasıyla yapılabilecek 32768 renktir. Örnek: 24 bit görüntülerde (kanal başına 8 bit), kanal başına aralık 0..255 (veya 0..224) 'dir, bu nedenle onu eşit aralıklı 32 gölgeye bölün.

Çok net olmak gerekirse, görüntü piksellerinin dizisi bir permütasyon olmalıdır, çünkü tüm olası görüntüler sadece farklı piksel konumlarında aynı renklere sahiptir. Burada hiç de güzel olmayan önemsiz bir permütasyon vereceğim:

Java 7

import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;

public class FifteenBitColors {
    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(256, 128, BufferedImage.TYPE_INT_RGB);

        // Generate algorithmically.
        for (int i = 0; i < 32768; i++) {
            int x = i & 255;
            int y = i / 256;
            int r = i << 3 & 0xF8;
            int g = i >> 2 & 0xF8;
            int b = i >> 7 & 0xF8;
            img.setRGB(x, y, (r << 8 | g) << 8 | b);
        }

        // Save.
        try (OutputStream out = new BufferedOutputStream(new FileOutputStream("RGB15.png"))) {
            ImageIO.write(img, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

görüntü tanımını buraya girin

kazanan

7 gün bittiğinden, kazanan ilan ediyorum

Ancak, hiçbir şekilde bunun bittiğini düşünmeyin. Ben ve tüm okuyucular her zaman daha harika tasarımlara açığız. Oluşturmayı bırakma.

Kazanan: 231 oy ile fejesjoco


8
"Dithering'e izin verilir" derken, ne demek istiyorsun? Bu, "her piksel benzersiz bir renktir" kuralına bir istisna mıdır? Değilse, hangisinin yasak olduğunu neye izin veriyorsunuz?
Peter Taylor

1
Bu, renkleri bir desene yerleştirebileceğiniz anlamına gelir, bu nedenle gözle bakıldığında farklı bir renge karışırlar. Örneğin, allRGB sayfasındaki "açıkça tüm RGB" görüntüsünü ve oradaki diğerlerini görün.
Mark Jeronimus

8
Aslında önemsiz permütasyon örneğini göze oldukça hoş buluyorum.
Jason C,

2
@ Zom-B Adam, bu yazıyı çok seviyorum. Teşekkürler!
Jason C,

7
Güzel sonuçlar / cevaplar!
EthanB,

Yanıtlar:


534

C #

Ortasına rastgele bir piksel koydum ve daha sonra onlara çok benzeyen bir mahalleye rastgele pikseller koymaya başladım. İki mod desteklenir: minimum seçimde, bir seferde yalnızca bir komşu piksel dikkate alınır; ortalama seçimde, tümlerin (1..8) ortalaması alınır. Minimum seçim biraz gürültülü, ortalama seçim elbette daha bulanık, ancak her ikisi de aslında resimlere benziyor. Bazı düzenlemelerden sonra, güncel, biraz optimize edilmiş versiyon (paralel işleme bile kullanıyor!):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.IO;

class Program
{
    // algorithm settings, feel free to mess with it
    const bool AVERAGE = false;
    const int NUMCOLORS = 32;
    const int WIDTH = 256;
    const int HEIGHT = 128;
    const int STARTX = 128;
    const int STARTY = 64;

    // represent a coordinate
    struct XY
    {
        public int x, y;
        public XY(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public override int GetHashCode()
        {
            return x ^ y;
        }
        public override bool Equals(object obj)
        {
            var that = (XY)obj;
            return this.x == that.x && this.y == that.y;
        }
    }

    // gets the difference between two colors
    static int coldiff(Color c1, Color c2)
    {
        var r = c1.R - c2.R;
        var g = c1.G - c2.G;
        var b = c1.B - c2.B;
        return r * r + g * g + b * b;
    }

    // gets the neighbors (3..8) of the given coordinate
    static List<XY> getneighbors(XY xy)
    {
        var ret = new List<XY>(8);
        for (var dy = -1; dy <= 1; dy++)
        {
            if (xy.y + dy == -1 || xy.y + dy == HEIGHT)
                continue;
            for (var dx = -1; dx <= 1; dx++)
            {
                if (xy.x + dx == -1 || xy.x + dx == WIDTH)
                    continue;
                ret.Add(new XY(xy.x + dx, xy.y + dy));
            }
        }
        return ret;
    }

    // calculates how well a color fits at the given coordinates
    static int calcdiff(Color[,] pixels, XY xy, Color c)
    {
        // get the diffs for each neighbor separately
        var diffs = new List<int>(8);
        foreach (var nxy in getneighbors(xy))
        {
            var nc = pixels[nxy.y, nxy.x];
            if (!nc.IsEmpty)
                diffs.Add(coldiff(nc, c));
        }

        // average or minimum selection
        if (AVERAGE)
            return (int)diffs.Average();
        else
            return diffs.Min();
    }

    static void Main(string[] args)
    {
        // create every color once and randomize the order
        var colors = new List<Color>();
        for (var r = 0; r < NUMCOLORS; r++)
            for (var g = 0; g < NUMCOLORS; g++)
                for (var b = 0; b < NUMCOLORS; b++)
                    colors.Add(Color.FromArgb(r * 255 / (NUMCOLORS - 1), g * 255 / (NUMCOLORS - 1), b * 255 / (NUMCOLORS - 1)));
        var rnd = new Random();
        colors.Sort(new Comparison<Color>((c1, c2) => rnd.Next(3) - 1));

        // temporary place where we work (faster than all that many GetPixel calls)
        var pixels = new Color[HEIGHT, WIDTH];
        Trace.Assert(pixels.Length == colors.Count);

        // constantly changing list of available coordinates (empty pixels which have non-empty neighbors)
        var available = new HashSet<XY>();

        // calculate the checkpoints in advance
        var checkpoints = Enumerable.Range(1, 10).ToDictionary(i => i * colors.Count / 10 - 1, i => i - 1);

        // loop through all colors that we want to place
        for (var i = 0; i < colors.Count; i++)
        {
            if (i % 256 == 0)
                Console.WriteLine("{0:P}, queue size {1}", (double)i / WIDTH / HEIGHT, available.Count);

            XY bestxy;
            if (available.Count == 0)
            {
                // use the starting point
                bestxy = new XY(STARTX, STARTY);
            }
            else
            {
                // find the best place from the list of available coordinates
                // uses parallel processing, this is the most expensive step
                bestxy = available.AsParallel().OrderBy(xy => calcdiff(pixels, xy, colors[i])).First();
            }

            // put the pixel where it belongs
            Trace.Assert(pixels[bestxy.y, bestxy.x].IsEmpty);
            pixels[bestxy.y, bestxy.x] = colors[i];

            // adjust the available list
            available.Remove(bestxy);
            foreach (var nxy in getneighbors(bestxy))
                if (pixels[nxy.y, nxy.x].IsEmpty)
                    available.Add(nxy);

            // save a checkpoint
            int chkidx;
            if (checkpoints.TryGetValue(i, out chkidx))
            {
                var img = new Bitmap(WIDTH, HEIGHT, PixelFormat.Format24bppRgb);
                for (var y = 0; y < HEIGHT; y++)
                {
                    for (var x = 0; x < WIDTH; x++)
                    {
                        img.SetPixel(x, y, pixels[y, x]);
                    }
                }
                img.Save("result" + chkidx + ".png");
            }
        }

        Trace.Assert(available.Count == 0);
    }
}

256x128 piksel, ortadan itibaren minimum seçim:

256x128 piksel, sol üst köşeden başlayarak, minimum seçim:

256x128 piksel, ortada başlayan, ortalama seçim:

Aşağıda, minimum ve ortalama seçimin nasıl çalıştığını gösteren iki 10 karelik animgif (yalnızca 256 renkle görüntüleyebilmek için gif biçimindeki övgüler):

Mimimum seçim modu, tüm pikselleri olduğu gibi doldurarak, kabarcık gibi küçük bir dalga cephesi ile büyür. Bununla birlikte, ortalama modda, iki farklı renkli dal yan yana büyümeye başladığında küçük siyah bir boşluk olacaktır çünkü hiçbir şey iki farklı renge yeterince yakın olmayacaktır. Bu boşluklar nedeniyle, dalga cephesi daha büyük bir sipariş olacak, bu nedenle algoritma çok daha yavaş olacaktır. Ama güzel çünkü büyüyen bir mercan gibi görünüyor. Ortalama modu düşürürsem, biraz daha hızlı olabilirdi çünkü her yeni renk mevcut her pikselle yaklaşık 2-3 kez karşılaştırılıyor. Bunu optimize etmenin başka yollarını göremiyorum, bence bu yeterince iyi.

Ve büyük cazibe, işte 512x512 piksel oluşturma, orta başlangıç, minimum seçim:

Sadece bununla oynamayı bırakamıyorum! Yukarıdaki kodda renkler rastgele sıralanır. Hiç sıralamazsak ya da hue ( (c1, c2) => c1.GetHue().CompareTo(c2.GetHue())) ile sıralarsak , sırasıyla bunları alırız (hem orta başlangıç ​​hem de minimum seçim):

Mercan formunun sonuna kadar tutulduğu bir başka kombinasyon: ortalama seçim ile renk sırası, 30 karelik bir animgif ile:

GÜNCELLEME: HAZIR !!!

Merhaba res istedin, res res istedim, sabırsızdın, zar zor uyudum. Şimdi nihayet hazır olduğunu, üretim kalitesini açıklamaktan heyecan duyuyorum. Ve ben büyük bir patlama, harika bir 1080p YouTube videosu ile çıkıyorum! Video için buraya tıklayın , geek tarzı teşvik etmek viral yapalım. Ayrıca blogumda http://joco.name/ adresinde bir şeyler gönderiyorum , tüm ilginç detaylar, optimizasyonlar, videoyu nasıl yaptığımla ilgili teknik bir yazı olacak. Sonunda kaynağı paylaşıyorum. GPL altındaki kod . Büyük oldu bu yüzden uygun bir barındırma bunun için en iyi yer, artık cevabımın yukarıdaki bölümünü düzenlemeyeceğim. Serbest bırakma modunda derlediğinizden emin olun! Program birçok CPU çekirdeğine iyi ölçekler. 4Kx4K bir render yaklaşık 2-3 GB RAM gerektirir.

Artık 5-10 saatte büyük görüntüler oluşturabiliyorum. Zaten bazı 4Kx4K render var, daha sonra gönderirim. Program çok gelişti, sayısız optimizasyon yapıldı. Ayrıca kullanıcı dostu yaptım, böylece herkes kolayca kullanabilir, hoş bir komut satırı vardır. Program aynı zamanda deterministik olarak rasgeledir, yani rasgele bir tohum kullanabilirsiniz ve her seferinde aynı görüntüyü oluşturur.

İşte bazı büyük işler.

Favori 512:


(kaynak: joco.name )

Benim görünen 2048 adlı videosu :


(kaynak: joco.name )


(kaynak: joco.name )


(kaynak: joco.name )


(kaynak: joco.name )

İlk 4096 render (TODO: yüklenmekte ve web sitem büyük trafiği idare edemiyor, bu yüzden geçici olarak yerleştiriliyorlar):


(kaynak: joco.name )


(kaynak: joco.name )


(kaynak: joco.name )


(kaynak: joco.name )


25
Şimdi bu harika!
Jaa-c,

5
Çok güzel :-D Şimdi biraz daha büyüğünü yapın!
squeamish ossifrage

20
Sen gerçek bir sanatçısın! :)
AL

10
Bir baskı için ne kadar?
primo

16
Büyük renderler ve 1080p video üzerinde çalışıyorum. Saatler veya günler alacak. Umarım birileri büyük bir renderden bir baskı yaratabilir. Veya bir tişört bile: bir tarafta kod, diğer tarafta görüntü. Biri bunu ayarlayabilir mi?
fejesjoco

248

İşleme

Güncelleme! 4096x4096 görüntüler!

İkinci yazımı iki programı bir araya getirerek birleştirdim.

Seçilen görüntülerin tam bir koleksiyonu burada, Dropbox'ta bulunabilir . (Not: DropBox, 4096x4096 görüntüler için önizleme oluşturamaz; yalnızca onları tıklayın ve "İndir" i tıklayın).

Sadece birine bakarsanız, buna bakın (eğilebilir)! İşte küçültülmüş (ve daha fazlası aşağıda), orijinal 2048x1024:

görüntü tanımını buraya girin

Bu program, renkli küpte rastgele seçilen noktalardan gelen yollarda yürümek, ardından görüntüyü rastgele seçilen yollara çekmek suretiyle çalışır. Çok fazla olasılık var. Yapılandırılabilir seçenekler:

  • Maksimum renk küp yolu uzunluğu.
  • Renkli küpten geçmenin maksimum adımı (daha büyük değerler daha büyük farklılıklara neden olur, ancak işler sıkılaştığında sondaki küçük yol sayısını en aza indirir).
  • Resmin döşenmesi.
  • Şu anda iki görüntü yolu modu vardır:
    • Mod 1 (bu orijinal gönderinin modu): Görüntüde kullanılmayan piksellerin bir bloğunu bulur ve bu bloğa işler. Bloklar rastgele yerleştirilebilir veya soldan sağa sıralanabilir.
    • Mod 2 (ikinci gönderimin bu ile birleştirdiğim modu): Görüntüde rastgele bir başlangıç ​​noktası seçer ve kullanılmayan piksellerden geçen bir yol boyunca yürür; kullanılan piksellerin etrafında yürüyebilir. Bu mod için seçenekler:
      • Yürüyerek (ortogonal, diyagonal veya her ikisi de) yol tarifini ayarlayın.
      • Her adımdan sonra yönün değiştirilip değiştirilmeyeceği (şu anda saat yönünde ancak kod esnektir) ya da yalnızca işgal edilen bir pikselle karşılaşıldığında yön değiştirilip değiştirilmeyeceği ..
      • Karışık yön sırasını değiştirme seçeneği değişir (saat yönünde değil).

4096x4096'ya kadar tüm boyutlarda çalışır.

Tam İşleme taslağını burada bulabilirsiniz: Tracer.zip

Yerden kazanmak için tüm dosyaları aynı kod bloğuna yapıştırdım (hepsinde bir dosyada bile geçerli bir taslak). Hazır ayarlardan birini kullanmak istiyorsanız, gPresetatamadaki dizini değiştirin . Bunu Processing'te rçalıştırırsanız, yeni bir görüntü oluşturmak için çalışırken basabilirsiniz .

  • Güncelleme 1: İlk kullanılmayan renk / pikseli izlemek ve bilinen kullanılan pikselleri aramamak için optimize edilmiş kod; 2048x1024 üretim süresini 10-30 dakikadan 15 saniyeye düşürdü ve 4096x4096'yı 1-3 saatten 1 dakikaya düşürdü. Bırakılan kutu kaynağı ve altındaki kaynak güncellendi.
  • Güncelleme 2: 4096x4096 görüntülerin oluşturulmasını engelleyen hata giderildi.
final int BITS = 5; // Set to 5, 6, 7, or 8!

// Preset (String name, int colorBits, int maxCubePath, int maxCubeStep, int imageMode, int imageOpts)
final Preset[] PRESETS = new Preset[] {
  // 0
  new Preset("flowers",      BITS, 8*32*32, 2, ImageRect.MODE2, ImageRect.ALL_CW | ImageRect.CHANGE_DIRS),
  new Preset("diamonds",     BITS, 2*32*32, 2, ImageRect.MODE2, ImageRect.ORTHO_CW | ImageRect.CHANGE_DIRS),
  new Preset("diamondtile",  BITS, 2*32*32, 2, ImageRect.MODE2, ImageRect.ORTHO_CW | ImageRect.CHANGE_DIRS | ImageRect.WRAP),
  new Preset("shards",       BITS, 2*32*32, 2, ImageRect.MODE2, ImageRect.ALL_CW | ImageRect.CHANGE_DIRS | ImageRect.SHUFFLE_DIRS),
  new Preset("bigdiamonds",  BITS,  100000, 6, ImageRect.MODE2, ImageRect.ORTHO_CW | ImageRect.CHANGE_DIRS),
  // 5
  new Preset("bigtile",      BITS,  100000, 6, ImageRect.MODE2, ImageRect.ORTHO_CW | ImageRect.CHANGE_DIRS | ImageRect.WRAP),
  new Preset("boxes",        BITS,   32*32, 2, ImageRect.MODE2, ImageRect.ORTHO_CW),
  new Preset("giftwrap",     BITS,   32*32, 2, ImageRect.MODE2, ImageRect.ORTHO_CW | ImageRect.WRAP),
  new Preset("diagover",     BITS,   32*32, 2, ImageRect.MODE2, ImageRect.DIAG_CW),
  new Preset("boxfade",      BITS,   32*32, 2, ImageRect.MODE2, ImageRect.DIAG_CW | ImageRect.CHANGE_DIRS),
  // 10
  new Preset("randlimit",    BITS,     512, 2, ImageRect.MODE1, ImageRect.RANDOM_BLOCKS),
  new Preset("ordlimit",     BITS,      64, 2, ImageRect.MODE1, 0),
  new Preset("randtile",     BITS,    2048, 3, ImageRect.MODE1, ImageRect.RANDOM_BLOCKS | ImageRect.WRAP),
  new Preset("randnolimit",  BITS, 1000000, 1, ImageRect.MODE1, ImageRect.RANDOM_BLOCKS),
  new Preset("ordnolimit",   BITS, 1000000, 1, ImageRect.MODE1, 0)
};


PGraphics gFrameBuffer;
Preset gPreset = PRESETS[2];

void generate () {
  ColorCube cube = gPreset.createCube();
  ImageRect image = gPreset.createImage();
  gFrameBuffer = createGraphics(gPreset.getWidth(), gPreset.getHeight(), JAVA2D);
  gFrameBuffer.noSmooth();
  gFrameBuffer.beginDraw();
  while (!cube.isExhausted())
    image.drawPath(cube.nextPath(), gFrameBuffer);
  gFrameBuffer.endDraw();
  if (gPreset.getName() != null)
    gFrameBuffer.save(gPreset.getName() + "_" + gPreset.getCubeSize() + ".png");
  //image.verifyExhausted();
  //cube.verifyExhausted();
}

void setup () {
  size(gPreset.getDisplayWidth(), gPreset.getDisplayHeight());
  noSmooth();
  generate();
}

void keyPressed () {
  if (key == 'r' || key == 'R')
    generate();
}

boolean autogen = false;
int autop = 0;
int autob = 5;

void draw () {
  if (autogen) {
    gPreset = new Preset(PRESETS[autop], autob);
    generate();
    if ((++ autop) >= PRESETS.length) {
      autop = 0;
      if ((++ autob) > 8)
        autogen = false;
    }
  }
  if (gPreset.isWrapped()) {
    int hw = width/2;
    int hh = height/2;
    image(gFrameBuffer, 0, 0, hw, hh);
    image(gFrameBuffer, hw, 0, hw, hh);
    image(gFrameBuffer, 0, hh, hw, hh);
    image(gFrameBuffer, hw, hh, hw, hh);
  } else {
    image(gFrameBuffer, 0, 0, width, height);
  }
}

static class ColorStep {
  final int r, g, b;
  ColorStep (int rr, int gg, int bb) { r=rr; g=gg; b=bb; }
}

class ColorCube {

  final boolean[] used;
  final int size; 
  final int maxPathLength;
  final ArrayList<ColorStep> allowedSteps = new ArrayList<ColorStep>();

  int remaining;
  int pathr = -1, pathg, pathb;
  int firstUnused = 0;

  ColorCube (int size, int maxPathLength, int maxStep) {
    this.used = new boolean[size*size*size];
    this.remaining = size * size * size;
    this.size = size;
    this.maxPathLength = maxPathLength;
    for (int r = -maxStep; r <= maxStep; ++ r)
      for (int g = -maxStep; g <= maxStep; ++ g)
        for (int b = -maxStep; b <= maxStep; ++ b)
          if (r != 0 && g != 0 && b != 0)
            allowedSteps.add(new ColorStep(r, g, b));
  }

  boolean isExhausted () {
    println(remaining);
    return remaining <= 0;
  }

  boolean isUsed (int r, int g, int b) {
    if (r < 0 || r >= size || g < 0 || g >= size || b < 0 || b >= size)
      return true;
    else
      return used[(r*size+g)*size+b];
  }

  void setUsed (int r, int g, int b) {
    used[(r*size+g)*size+b] = true;
  }

  int nextColor () {

    if (pathr == -1) { // Need to start a new path.

      // Limit to 50 attempts at random picks; things get tight near end.
      for (int n = 0; n < 50 && pathr == -1; ++ n) {
        int r = (int)random(size);
        int g = (int)random(size);
        int b = (int)random(size);
        if (!isUsed(r, g, b)) {
          pathr = r;
          pathg = g;
          pathb = b;
        }
      }
      // If we didn't find one randomly, just search for one.
      if (pathr == -1) {
        final int sizesq = size*size;
        final int sizemask = size - 1;
        for (int rgb = firstUnused; rgb < size*size*size; ++ rgb) {
          pathr = (rgb/sizesq)&sizemask;//(rgb >> 10) & 31;
          pathg = (rgb/size)&sizemask;//(rgb >> 5) & 31;
          pathb = rgb&sizemask;//rgb & 31;
          if (!used[rgb]) {
            firstUnused = rgb;
            break;
          }
        }
      }

      assert(pathr != -1);

    } else { // Continue moving on existing path.

      // Find valid next path steps.
      ArrayList<ColorStep> possibleSteps = new ArrayList<ColorStep>();
      for (ColorStep step:allowedSteps)
        if (!isUsed(pathr+step.r, pathg+step.g, pathb+step.b))
          possibleSteps.add(step);

      // If there are none end this path.
      if (possibleSteps.isEmpty()) {
        pathr = -1;
        return -1;
      }

      // Otherwise pick a random step and move there.
      ColorStep s = possibleSteps.get((int)random(possibleSteps.size()));
      pathr += s.r;
      pathg += s.g;
      pathb += s.b;

    }

    setUsed(pathr, pathg, pathb);  
    return 0x00FFFFFF & color(pathr * (256/size), pathg * (256/size), pathb * (256/size));

  } 

  ArrayList<Integer> nextPath () {

    ArrayList<Integer> path = new ArrayList<Integer>(); 
    int rgb;

    while ((rgb = nextColor()) != -1) {
      path.add(0xFF000000 | rgb);
      if (path.size() >= maxPathLength) {
        pathr = -1;
        break;
      }
    }

    remaining -= path.size();

    //assert(!path.isEmpty());
    if (path.isEmpty()) {
      println("ERROR: empty path.");
      verifyExhausted();
    }
    return path;

  }

  void verifyExhausted () {
    final int sizesq = size*size;
    final int sizemask = size - 1;
    for (int rgb = 0; rgb < size*size*size; ++ rgb) {
      if (!used[rgb]) {
        int r = (rgb/sizesq)&sizemask;
        int g = (rgb/size)&sizemask;
        int b = rgb&sizemask;
        println("UNUSED COLOR: " + r + " " + g + " " + b);
      }
    }
    if (remaining != 0)
      println("REMAINING COLOR COUNT IS OFF: " + remaining);
  }

}


static class ImageStep {
  final int x;
  final int y;
  ImageStep (int xx, int yy) { x=xx; y=yy; }
}

static int nmod (int a, int b) {
  return (a % b + b) % b;
}

class ImageRect {

  // for mode 1:
  //   one of ORTHO_CW, DIAG_CW, ALL_CW
  //   or'd with flags CHANGE_DIRS
  static final int ORTHO_CW = 0;
  static final int DIAG_CW = 1;
  static final int ALL_CW = 2;
  static final int DIR_MASK = 0x03;
  static final int CHANGE_DIRS = (1<<5);
  static final int SHUFFLE_DIRS = (1<<6);

  // for mode 2:
  static final int RANDOM_BLOCKS = (1<<0);

  // for both modes:
  static final int WRAP = (1<<16);

  static final int MODE1 = 0;
  static final int MODE2 = 1;

  final boolean[] used;
  final int width;
  final int height;
  final boolean changeDir;
  final int drawMode;
  final boolean randomBlocks;
  final boolean wrap;
  final ArrayList<ImageStep> allowedSteps = new ArrayList<ImageStep>();

  // X/Y are tracked instead of index to preserve original unoptimized mode 1 behavior
  // which does column-major searches instead of row-major.
  int firstUnusedX = 0;
  int firstUnusedY = 0;

  ImageRect (int width, int height, int drawMode, int drawOpts) {
    boolean myRandomBlocks = false, myChangeDir = false;
    this.used = new boolean[width*height];
    this.width = width;
    this.height = height;
    this.drawMode = drawMode;
    this.wrap = (drawOpts & WRAP) != 0;
    if (drawMode == MODE1) {
      myRandomBlocks = (drawOpts & RANDOM_BLOCKS) != 0;
    } else if (drawMode == MODE2) {
      myChangeDir = (drawOpts & CHANGE_DIRS) != 0;
      switch (drawOpts & DIR_MASK) {
      case ORTHO_CW:
        allowedSteps.add(new ImageStep(1, 0));
        allowedSteps.add(new ImageStep(0, -1));
        allowedSteps.add(new ImageStep(-1, 0));
        allowedSteps.add(new ImageStep(0, 1));
        break;
      case DIAG_CW:
        allowedSteps.add(new ImageStep(1, -1));
        allowedSteps.add(new ImageStep(-1, -1));
        allowedSteps.add(new ImageStep(-1, 1));
        allowedSteps.add(new ImageStep(1, 1));
        break;
      case ALL_CW:
        allowedSteps.add(new ImageStep(1, 0));
        allowedSteps.add(new ImageStep(1, -1));
        allowedSteps.add(new ImageStep(0, -1));
        allowedSteps.add(new ImageStep(-1, -1));
        allowedSteps.add(new ImageStep(-1, 0));
        allowedSteps.add(new ImageStep(-1, 1));
        allowedSteps.add(new ImageStep(0, 1));
        allowedSteps.add(new ImageStep(1, 1));
        break;
      }
      if ((drawOpts & SHUFFLE_DIRS) != 0)
        java.util.Collections.shuffle(allowedSteps);
    }
    this.randomBlocks = myRandomBlocks;
    this.changeDir = myChangeDir;
  }

  boolean isUsed (int x, int y) {
    if (wrap) {
      x = nmod(x, width);
      y = nmod(y, height);
    }
    if (x < 0 || x >= width || y < 0 || y >= height)
      return true;
    else
      return used[y*width+x];
  }

  boolean isUsed (int x, int y, ImageStep d) {
    return isUsed(x + d.x, y + d.y);
  }

  void setUsed (int x, int y) {
    if (wrap) {
      x = nmod(x, width);
      y = nmod(y, height);
    }
    used[y*width+x] = true;
  }

  boolean isBlockFree (int x, int y, int w, int h) {
    for (int yy = y; yy < y + h; ++ yy)
      for (int xx = x; xx < x + w; ++ xx)
        if (isUsed(xx, yy))
          return false;
    return true;
  }

  void drawPath (ArrayList<Integer> path, PGraphics buffer) {
    if (drawMode == MODE1)
      drawPath1(path, buffer);
    else if (drawMode == MODE2)
      drawPath2(path, buffer);
  }

  void drawPath1 (ArrayList<Integer> path, PGraphics buffer) {

    int w = (int)(sqrt(path.size()) + 0.5);
    if (w < 1) w = 1; else if (w > width) w = width;
    int h = (path.size() + w - 1) / w; 
    int x = -1, y = -1;

    int woff = wrap ? 0 : (1 - w);
    int hoff = wrap ? 0 : (1 - h);

    // Try up to 50 times to find a random location for block.
    if (randomBlocks) {
      for (int n = 0; n < 50 && x == -1; ++ n) {
        int xx = (int)random(width + woff);
        int yy = (int)random(height + hoff);
        if (isBlockFree(xx, yy, w, h)) {
          x = xx;
          y = yy;
        }
      }
    }

    // If random choice failed just search for one.
    int starty = firstUnusedY;
    for (int xx = firstUnusedX; xx < width + woff && x == -1; ++ xx) {
      for (int yy = starty; yy < height + hoff && x == -1; ++ yy) {
        if (isBlockFree(xx, yy, w, h)) {
          firstUnusedX = x = xx;
          firstUnusedY = y = yy;
        }  
      }
      starty = 0;
    }

    if (x != -1) {
      for (int xx = x, pathn = 0; xx < x + w && pathn < path.size(); ++ xx)
        for (int yy = y; yy < y + h && pathn < path.size(); ++ yy, ++ pathn) {
          buffer.set(nmod(xx, width), nmod(yy, height), path.get(pathn));
          setUsed(xx, yy);
        }
    } else {
      for (int yy = 0, pathn = 0; yy < height && pathn < path.size(); ++ yy)
        for (int xx = 0; xx < width && pathn < path.size(); ++ xx)
          if (!isUsed(xx, yy)) {
            buffer.set(nmod(xx, width), nmod(yy, height), path.get(pathn));
            setUsed(xx, yy);
            ++ pathn;
          }
    }

  }

  void drawPath2 (ArrayList<Integer> path, PGraphics buffer) {

    int pathn = 0;

    while (pathn < path.size()) {

      int x = -1, y = -1;

      // pick a random location in the image (try up to 100 times before falling back on search)

      for (int n = 0; n < 100 && x == -1; ++ n) {
        int xx = (int)random(width);
        int yy = (int)random(height);
        if (!isUsed(xx, yy)) {
          x = xx;
          y = yy;
        }
      }  

      // original:
      //for (int yy = 0; yy < height && x == -1; ++ yy)
      //  for (int xx = 0; xx < width && x == -1; ++ xx)
      //    if (!isUsed(xx, yy)) {
      //      x = xx;
      //      y = yy;
      //    }
      // optimized:
      if (x == -1) {
        for (int n = firstUnusedY * width + firstUnusedX; n < used.length; ++ n) {
          if (!used[n]) {
            firstUnusedX = x = (n % width);
            firstUnusedY = y = (n / width);
            break;
          }     
        }
      }

      // start drawing

      int dir = 0;

      while (pathn < path.size()) {

        buffer.set(nmod(x, width), nmod(y, height), path.get(pathn ++));
        setUsed(x, y);

        int diro;
        for (diro = 0; diro < allowedSteps.size(); ++ diro) {
          int diri = (dir + diro) % allowedSteps.size();
          ImageStep step = allowedSteps.get(diri);
          if (!isUsed(x, y, step)) {
            dir = diri;
            x += step.x;
            y += step.y;
            break;
          }
        }

        if (diro == allowedSteps.size())
          break;

        if (changeDir) 
          ++ dir;

      }    

    }

  }

  void verifyExhausted () {
    for (int n = 0; n < used.length; ++ n)
      if (!used[n])
        println("UNUSED IMAGE PIXEL: " + (n%width) + " " + (n/width));
  }

}


class Preset {

  final String name;
  final int cubeSize;
  final int maxCubePath;
  final int maxCubeStep;
  final int imageWidth;
  final int imageHeight;
  final int imageMode;
  final int imageOpts;
  final int displayScale;

  Preset (Preset p, int colorBits) {
    this(p.name, colorBits, p.maxCubePath, p.maxCubeStep, p.imageMode, p.imageOpts);
  }

  Preset (String name, int colorBits, int maxCubePath, int maxCubeStep, int imageMode, int imageOpts) {
    final int csize[] = new int[]{ 32, 64, 128, 256 };
    final int iwidth[] = new int[]{ 256, 512, 2048, 4096 };
    final int iheight[] = new int[]{ 128, 512, 1024, 4096 };
    final int dscale[] = new int[]{ 2, 1, 1, 1 };
    this.name = name; 
    this.cubeSize = csize[colorBits - 5];
    this.maxCubePath = maxCubePath;
    this.maxCubeStep = maxCubeStep;
    this.imageWidth = iwidth[colorBits - 5];
    this.imageHeight = iheight[colorBits - 5];
    this.imageMode = imageMode;
    this.imageOpts = imageOpts;
    this.displayScale = dscale[colorBits - 5];
  }

  ColorCube createCube () {
    return new ColorCube(cubeSize, maxCubePath, maxCubeStep);
  }

  ImageRect createImage () {
    return new ImageRect(imageWidth, imageHeight, imageMode, imageOpts);
  }

  int getWidth () {
    return imageWidth;
  }

  int getHeight () {
    return imageHeight;
  }

  int getDisplayWidth () {
    return imageWidth * displayScale * (isWrapped() ? 2 : 1);
  }

  int getDisplayHeight () {
    return imageHeight * displayScale * (isWrapped() ? 2 : 1);
  }

  String getName () {
    return name;
  }

  int getCubeSize () {
    return cubeSize;
  }

  boolean isWrapped () {
    return (imageOpts & ImageRect.WRAP) != 0;
  }

}

İşte beğendiğim 256x128 görüntülerden oluşan tam bir set:

Mod 1:

Orijinal setten favorim (max_path_length = 512, path_step = 2, rastgele, görüntülenen 2x, bağlantı 256x128 ):

görüntü tanımını buraya girin

Diğerleri (sol iki sıralı, sağ iki rasgele, üst iki yol uzunluğu sınırlı, alt iki sınırsız):

ordlimit randlimit ordnolimit randnolimit

Bu bir kiremitli olabilir:

randtile

Mod 2:

elmaslar Çiçekler boxfade diagover bigdiamonds boxes2 kırıkları

Bunlar döşenebilir:

bigtile diamondtile hediye paketi

512x512 seçimler:

Tileable elmaslar, 2. moddaki favorim; yolların mevcut nesnelerin etrafında nasıl yürüdüğünü görebilirsiniz.

görüntü tanımını buraya girin

Daha büyük yol adımı ve maksimum yol uzunluğu, eğilebilir:

görüntü tanımını buraya girin

Rastgele mod 1, tileable:

görüntü tanımını buraya girin

Daha fazla seçenek:

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin

512x512 işlemlerinin tümü dropbox klasöründe (* _64.png) bulunabilir.

2048x1024 ve 4096x4096:

Bunlar gömülemeyecek kadar büyük ve bulduğum tüm görüntü konakları onları 1600x1200'e düşürüyor. Şu anda 4096x4096 görüntü kümesi oluşturuyorum, bu yüzden yakında hazır olacak. Tüm linkleri buraya eklemek yerine, sadece dropbox klasöründeki (* _128.png ve * _256.png) kontrol ediniz, not: 4096x4096 olanları dropbox önizleyici için çok büyüktür, sadece "indir" e tıklayın). İşte benim favorilerimden bazıları:

2048x1024 büyük eğilebilir elmas (bu yazı başlangıcında bağladığımla aynı)

2048x1024 elmas (bunu seviyorum!), Küçültülmüş :

görüntü tanımını buraya girin

4096x4096 büyük eğilebilir elmaslar (Sonunda! Dropbox bağlantısında ' indir'i tıklayın; önizleyicileri için çok büyük), aşağı doğru ölçeklendirildi:

4096x4096 büyük tileable elmas

4096x4096 rastgele mod 1 : görüntü tanımını buraya girin

4096x4096 başka bir havalı

Güncelleme: 2048x1024 ön ayarlı resim seti tamamlandı ve dropbox'ta. 4096x4096 seti bir saat içinde yapılmalıdır.

Tonlarca iyi olanlar var, hangilerinin gönderileceğini seçmekte çok zorlanıyorum, bu yüzden lütfen klasör bağlantısını kontrol edin!


6
Bazı minerallerin yakından izlenimlerini hatırlatıyor.
Morwenn

3
Yarışmanın bir parçası değil, ama bunun çok havalı olduğunu düşündüm ; Photoshop'ta rastgele mod 1 resimlerden birine büyük bir gauss bulanıklığı ve otomatik kontrast geliştirdim ve güzel bir masaüstü arkaplan-y türünde bir şey yaptım.
Jason C,

2
vay, bunlar harika resimler!
sevenseacat

2
Bana Gustav Klimt dokularını hatırlatıyor.
Kim,

2
Dropbox'ta görüntüleri bağlayabileceğini biliyor muydun? Sadece indirme URL'yi kopyalayın kaldırmak dl=1ve token_hash=<something>bir kısmını ve bu gibi resmin bağlantısını yapmak: [![Alt text of my small preview image](https://i.stack.imgur.com/smallpreview.png)](https://dl.dropbox.com/linktoyourfullsiz‌​eimage.png). Başka bir ipucu: resimlerinizi sıkıştırabilirsiniz ( TruePNG ( İndirme ) ile iyi sonuçlar alıyorum ). Dosya boyutunun% 28.1'ini bu görüntüye kaydedebildim .
user2428118

219

Python w / PIL

Bu , özellikle z → z 5 - 1 için olan bir Newton Fraktalını temel alır . Beş kök ve dolayısıyla beş yakınsama noktası olduğundan, kullanılabilir renk alanı Hue'ye göre beş bölgeye ayrılır. Tek tek noktalar önce yakınsama noktalarına ulaşmak için gerekli olan yineleme sayısına göre ve ardından bu noktaya olan mesafeye göre sıralanır, daha önceki değerlere daha parlak bir renk atanır.

Güncelleme: 4096x4096 büyük render, allrgb.com'da barındırılıyor .

Orijinal (33,7 MB)

Çok merkezin yakın bir görüntüsü (gerçek boyut):

Bu değerleri kullanan farklı bir bakış açısı:

xstart = 0
ystart = 0

xd = 1 / dim[0]
yd = 1 / dim[1]

Orijinal (32,2 MB)

Ve bunları kullanarak başka:

xstart = 0.5
ystart = 0.5

xd = 0.001 / dim[0]
yd = 0.001 / dim[1]

Orijinal (27,2 MB)


Animasyon

İsteğe göre bir yakınlaştırma animasyonu derledim.

Odak Noktası: ( 0.50051 , -0.50051 )
Yakınlaştırma faktörü: 2 1/5

Odak noktası biraz tuhaf bir değer çünkü siyah noktaya yakınlaştırmak istemedim. Yakınlaştırma faktörü, her 5 kareyi ikiye katlayacak şekilde seçilir.

32x32 teaser:

Burada 256x256 sürümü görülebilir:
http://www.pictureshack.org/images/66172_frac.gif (5.4MB)

Sonsuz bir animasyonu mümkün kılacak matematiksel olarak "kendilerine" yakınlaşan noktalar olabilir. Herhangi birini tanımlayabilirsem, onları buraya eklerim.


Kaynak

from __future__ import division
from PIL import Image, ImageDraw
from cmath import phase
from sys import maxint

dim  = (4096, 4096)
bits = 8

def RGBtoHSV(R, G, B):
  R /= 255
  G /= 255
  B /= 255

  cmin = min(R, G, B)
  cmax = max(R, G, B)
  dmax = cmax - cmin

  V = cmax

  if dmax == 0:
    H = 0
    S = 0

  else:
    S = dmax/cmax

    dR = ((cmax - R)/6 + dmax/2)/dmax
    dG = ((cmax - G)/6 + dmax/2)/dmax
    dB = ((cmax - B)/6 + dmax/2)/dmax

    if   R == cmax: H = (dB - dG)%1
    elif G == cmax: H = (1/3 + dR - dB)%1
    elif B == cmax: H = (2/3 + dG - dR)%1

  return (H, S, V)

cmax = (1<<bits)-1
cfac = 255/cmax

img  = Image.new('RGB', dim)
draw = ImageDraw.Draw(img)

xstart = -2
ystart = -2

xd = 4 / dim[0]
yd = 4 / dim[1]

tol = 1e-12

a = [[], [], [], [], []]

for x in range(dim[0]):
  print x, "\r",
  for y in range(dim[1]):
    z = d = complex(xstart + x*xd, ystart + y*yd)
    c = 0
    l = 1
    while abs(l-z) > tol and abs(z) > tol:
      l = z
      z -= (z**5-1)/(5*z**4)
      c += 1
    if z == 0: c = maxint
    p = int(phase(z))

    a[p] += (c,abs(d-z), x, y),

for i in range(5):
  a[i].sort(reverse = False)

pnum = [len(a[i]) for i in range(5)]
ptot = dim[0]*dim[1]

bounds = []
lbound = 0
for i in range(4):
  nbound = lbound + pnum[i]/ptot
  bounds += nbound,
  lbound = nbound

t = [[], [], [], [], []]
for i in range(ptot-1, -1, -1):
  r = (i>>bits*2)*cfac
  g = (cmax&i>>bits)*cfac
  b = (cmax&i)*cfac
  (h, s, v) = RGBtoHSV(r, g, b)
  h = (h+0.1)%1
  if   h < bounds[0] and len(t[0]) < pnum[0]: p=0
  elif h < bounds[1] and len(t[1]) < pnum[1]: p=1
  elif h < bounds[2] and len(t[2]) < pnum[2]: p=2
  elif h < bounds[3] and len(t[3]) < pnum[3]: p=3
  else: p=4
  t[p] += (int(r), int(g), int(b)),

for i in range(5):
  t[i].sort(key = lambda c: c[0]*2126 + c[1]*7152 + c[2]*722, reverse = True)

r = [0, 0, 0, 0, 0]
for p in range(5):
  for c,d,x,y in a[p]:
    draw.point((x,y), t[p][r[p]])
    r[p] += 1

img.save("out.png")

6
Sonunda bir fraktal :) Bunları seviyorum. Ayrıca, 144 derecedeki yeşil benim en sevdiğim renk (120 derecelik saf yeşilin aksine sadece sıkıcı).
Mark Jeronimus

2
Bilmiyorum, aslında AllRGB versiyonlarını daha çok seviyorum; tam parlaklık alanını kullanma ihtiyacı, gradyanları güzel bir şekilde vurgulamaktadır.
Ilmari Karonen

2
+1 Sonunda bazı iyi fraktallar! Sonuncusu benim kişisel favorim. Bir video yakınlaştırma yapmalısınız! (@Quincunx: Seninkileri de gördüm; 1. günden itibaren oyumu aldım!)
Jason C

1
@JasonC Bir animasyon ekledim;)
primo

2
@primo Geç kaldığımı biliyorum, ama sadece bu görüntülerin muhteşem olduğunu söylemek istedim.
Ashwin Gupta

130

Bu fikri kullanıcı fejesjoco algoritmasından aldım ve biraz çalmak istedim, bu yüzden kendi algoritmamı sıfırdan yazmaya başladım.

Bunu gönderiyorum çünkü sizin için en iyisinden daha iyisini * yapabilirsem, bu sorunun henüz bitmediğini sanmıyorum. Karşılaştırma yapmak gerekirse, tüm RGB'lerde burada ulaşılan seviyenin çok üstünde olduğunu düşündüğüm çarpıcı tasarımlar var ve nasıl yaptıkları hakkında hiçbir fikrim yok.

*) yine de oylarla karar verilecek

Bu algoritma:

  1. Renkleri siyaha mümkün olduğunca yakın olacak şekilde (birkaç) tohum ile başlayın.
  2. Ziyaret edilmeyen ve ziyaret edilen bir noktaya 8 bağlı tüm piksellerin bir listesini tutun.
  3. Bu listeden rastgele bir ** nokta seçin
  4. Hesaplanan tüm piksellerin ortalama rengini hesaplayın [Bir Gaussian çekirdek kullanarak 9x9 karede düzenle] [ 8 ] buna bağlı (bu kadar pürüzsüz görünmesinin nedeni budur) Hiçbiri bulunmazsa, siyah alın.
  5. Bu rengin etrafındaki 3x3x3'lük bir küpte kullanılmayan bir renk arayın.
    • Çok renkli renkler bulunduğunda, en koyu olanı alın.
    • Multple eşit koyu renkler bulunduğunda, bunlardan rastgele birini alın.
    • Hiçbir şey bulunmadığında, arama aralığını 5x5x5, 7x7x7, vb. Şeklinde güncelleyin.
  6. Arsa piksel, güncelleme listesi ve 3 tekrarlayın

Ayrıca, seçilen pikselin kaç ziyaret edilen komşusunu saydığına dayanarak aday puanları seçme olasılığını da denedim, ancak algoritmayı daha da güzelleştirmeden yavaşlattı. Mevcut algoritma olasılıkları kullanmaz ve listeden rastgele bir nokta seçer. Bu sayede birçok komşunun puanları hızla doluyor, bu da bulanık bir kenarı olan büyüyen bir top haline geliyor. Bu aynı zamanda, yarıkların daha sonraki süreçte doldurulması durumunda komşu renklerin bulunmamasını önler.

Görüntü toroidaldir.

Java

İndir: com.digitalmodularkütüphane

package demos;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Arrays;

import com.digitalmodular.utilities.RandomFunctions;
import com.digitalmodular.utilities.gui.ImageFunctions;
import com.digitalmodular.utilities.swing.window.PixelImage;
import com.digitalmodular.utilities.swing.window.PixelWindow;

/**
 * @author jeronimus
 */
// Date 2014-02-28
public class AllColorDiffusion extends PixelWindow implements Runnable {
    private static final int    CHANNEL_BITS    = 7;

    public static void main(String[] args) {
        int bits = CHANNEL_BITS * 3;
        int heightBits = bits / 2;
        int widthBits = bits - heightBits;

        new AllColorDiffusion(CHANNEL_BITS, 1 << widthBits, 1 << heightBits);
    }

    private final int           width;
    private final int           height;
    private final int           channelBits;
    private final int           channelSize;

    private PixelImage          img;
    private javax.swing.Timer   timer;

    private boolean[]           colorCube;
    private long[]              foundColors;
    private boolean[]           queued;
    private int[]               queue;
    private int                 queuePointer    = 0;
    private int                 remaining;

    public AllColorDiffusion(int channelBits, int width, int height) {
        super(1024, 1024 * height / width);

        RandomFunctions.RND.setSeed(0);

        this.width = width;
        this.height = height;
        this.channelBits = channelBits;
        channelSize = 1 << channelBits;
    }

    @Override
    public void initialized() {
        img = new PixelImage(width, height);

        colorCube = new boolean[channelSize * channelSize * channelSize];
        foundColors = new long[channelSize * channelSize * channelSize];
        queued = new boolean[width * height];
        queue = new int[width * height];
        for (int i = 0; i < queue.length; i++)
            queue[i] = i;

        new Thread(this).start();
    }

    @Override
    public void resized() {}

    @Override
    public void run() {
        timer = new javax.swing.Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                draw();
            }
        });

        while (true) {
            img.clear(0);
            init();
            render();
        }

        // System.exit(0);
    }

    private void init() {
        RandomFunctions.RND.setSeed(0);

        Arrays.fill(colorCube, false);
        Arrays.fill(queued, false);
        remaining = width * height;

        // Initial seeds (need to be the darkest colors, because of the darkest
        // neighbor color search algorithm.)
        setPixel(width / 2 + height / 2 * width, 0);
        remaining--;
    }

    private void render() {
        timer.start();

        for (; remaining > 0; remaining--) {
            int point = findPoint();
            int color = findColor(point);
            setPixel(point, color);
        }

        timer.stop();
        draw();

        try {
            ImageFunctions.savePNG(System.currentTimeMillis() + ".png", img.image);
        }
        catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    void draw() {
        g.drawImage(img.image, 0, 0, getWidth(), getHeight(), 0, 0, width, height, null);
        repaintNow();
    }

    private int findPoint() {
        while (true) {
            // Time to reshuffle?
            if (queuePointer == 0) {
                for (int i = queue.length - 1; i > 0; i--) {
                    int j = RandomFunctions.RND.nextInt(i);
                    int temp = queue[i];
                    queue[i] = queue[j];
                    queue[j] = temp;
                    queuePointer = queue.length;
                }
            }

            if (queued[queue[--queuePointer]])
                return queue[queuePointer];
        }
    }

    private int findColor(int point) {
        int x = point & width - 1;
        int y = point / width;

        // Calculate the reference color as the average of all 8-connected
        // colors.
        int r = 0;
        int g = 0;
        int b = 0;
        int n = 0;
        for (int j = -1; j <= 1; j++) {
            for (int i = -1; i <= 1; i++) {
                point = (x + i & width - 1) + width * (y + j & height - 1);
                if (img.pixels[point] != 0) {
                    int pixel = img.pixels[point];

                    r += pixel >> 24 - channelBits & channelSize - 1;
                    g += pixel >> 16 - channelBits & channelSize - 1;
                    b += pixel >> 8 - channelBits & channelSize - 1;
                    n++;
                }
            }
        }
        r /= n;
        g /= n;
        b /= n;

        // Find a color that is preferably darker but not too far from the
        // original. This algorithm might fail to take some darker colors at the
        // start, and when the image is almost done the size will become really
        // huge because only bright reference pixels are being searched for.
        // This happens with a probability of 50% with 6 channelBits, and more
        // with higher channelBits values.
        //
        // Try incrementally larger distances from reference color.
        for (int size = 2; size <= channelSize; size *= 2) {
            n = 0;

            // Find all colors in a neighborhood from the reference color (-1 if
            // already taken).
            for (int ri = r - size; ri <= r + size; ri++) {
                if (ri < 0 || ri >= channelSize)
                    continue;
                int plane = ri * channelSize * channelSize;
                int dr = Math.abs(ri - r);
                for (int gi = g - size; gi <= g + size; gi++) {
                    if (gi < 0 || gi >= channelSize)
                        continue;
                    int slice = plane + gi * channelSize;
                    int drg = Math.max(dr, Math.abs(gi - g));
                    int mrg = Math.min(ri, gi);
                    for (int bi = b - size; bi <= b + size; bi++) {
                        if (bi < 0 || bi >= channelSize)
                            continue;
                        if (Math.max(drg, Math.abs(bi - b)) > size)
                            continue;
                        if (!colorCube[slice + bi])
                            foundColors[n++] = Math.min(mrg, bi) << channelBits * 3 | slice + bi;
                    }
                }
            }

            if (n > 0) {
                // Sort by distance from origin.
                Arrays.sort(foundColors, 0, n);

                // Find a random color amongst all colors equally distant from
                // the origin.
                int lowest = (int)(foundColors[0] >> channelBits * 3);
                for (int i = 1; i < n; i++) {
                    if (foundColors[i] >> channelBits * 3 > lowest) {
                        n = i;
                        break;
                    }
                }

                int nextInt = RandomFunctions.RND.nextInt(n);
                return (int)(foundColors[nextInt] & (1 << channelBits * 3) - 1);
            }
        }

        return -1;
    }

    private void setPixel(int point, int color) {
        int b = color & channelSize - 1;
        int g = color >> channelBits & channelSize - 1;
        int r = color >> channelBits * 2 & channelSize - 1;
        img.pixels[point] = 0xFF000000 | ((r << 8 | g) << 8 | b) << 8 - channelBits;

        colorCube[color] = true;

        int x = point & width - 1;
        int y = point / width;
        queued[point] = false;
        for (int j = -1; j <= 1; j++) {
            for (int i = -1; i <= 1; i++) {
                point = (x + i & width - 1) + width * (y + j & height - 1);
                if (img.pixels[point] == 0) {
                    queued[point] = true;
                }
            }
        }
    }
}
  • 512 x 512
  • orijinal 1 tohum
  • 1 saniye

görüntü tanımını buraya girin

  • 2048 × 1024
  • 1920 × 1080 masaüstüne hafifçe döşenmiştir
  • 30 saniye
  • photoshop'ta olumsuz

görüntü tanımını buraya girin

  • 2048 × 1024
  • 8 tohumlar
  • 27 saniye

görüntü tanımını buraya girin

  • 512 x 512
  • 40 rastgele tohum
  • 6 saniye

görüntü tanımını buraya girin

  • 4096 x 4096
  • 1 tohum
  • Çizgiler belirgin şekilde keskinleşir (sanki sashimi'ye bir balık kesebilirmiş gibi görünürler)
  • 20 dakika sonra bitmiş gibiydi, ama ... bir sebepten dolayı bitiremediler, bu yüzden şimdi gece boyunca 7 örnek çalıştırıyorum.

[Aşağıya bakınız]

[Düzenle]
** Piksel seçme yöntemimin tamamen rastgele olmadığını keşfettim. Arama alanının rastgele bir permütasyonuna sahip olmanın rastgele ve gerçek rastgele olduğundan daha hızlı olacağını düşündüm (çünkü bir nokta şans eseri iki kez seçilmez. Ancak, bir şekilde, onu gerçek rastgele ile değiştirerek, sürekli olarak resmimde daha fazla gürültü lekesi olur.

[sürüm 2 kodu kaldırıldı çünkü 30.000 karakter sınırını aştım]

görüntü tanımını buraya girin

  • İlk arama küpünü 5x5x5'e yükseltti

görüntü tanımını buraya girin

  • Daha da büyük, 9x9x9

görüntü tanımını buraya girin

  • Kaza 1. Permütasyonu devre dışı bırakarak arama alanı her zaman doğrusal olacaktır.

görüntü tanımını buraya girin

  • Kaza 2. Beşinci sıra kullanarak yeni bir arama tekniği denedim. Hala bunu analiz etmek zorundayım ama paylaşmaya değer olduğunu düşündüm.

görüntü tanımını buraya girin

  • Daima merkezden X kullanılmayan pikselleri içinde seçme
  • X 256 ile 0 - 8192 aralığında

Resim yüklenemiyor: "Hata! Kötü Bir Şey Oldu! Siz değil, biziz. Bu bizim hatamız." Resim sadece imgur için çok büyük. Başka bir yerde denemek ...

görüntü tanımını buraya girin

digitalmodularPiksellerin kullanıldığı sırayı belirlemek için kütüphanede bulduğum bir zamanlayıcı paketi ile deneme (difüzyon yerine).

package demos;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Arrays;

import com.digitalmodular.utilities.RandomFunctions;
import com.digitalmodular.utilities.gui.ImageFunctions;
import com.digitalmodular.utilities.gui.schedulers.ScheduledPoint;
import com.digitalmodular.utilities.gui.schedulers.Scheduler;
import com.digitalmodular.utilities.gui.schedulers.XorScheduler;
import com.digitalmodular.utilities.swing.window.PixelImage;
import com.digitalmodular.utilities.swing.window.PixelWindow;

/**
 * @author jeronimus
 */
// Date 2014-02-28
public class AllColorDiffusion3 extends PixelWindow implements Runnable {
    private static final int    CHANNEL_BITS    = 7;

    public static void main(String[] args) {

        int bits = CHANNEL_BITS * 3;
        int heightBits = bits / 2;
        int widthBits = bits - heightBits;

        new AllColorDiffusion3(CHANNEL_BITS, 1 << widthBits, 1 << heightBits);
    }

    private final int           width;
    private final int           height;
    private final int           channelBits;
    private final int           channelSize;

    private PixelImage          img;
    private javax.swing.Timer   timer;
    private Scheduler           scheduler   = new XorScheduler();

    private boolean[]           colorCube;
    private long[]              foundColors;

    public AllColorDiffusion3(int channelBits, int width, int height) {
        super(1024, 1024 * height / width);

        this.width = width;
        this.height = height;
        this.channelBits = channelBits;
        channelSize = 1 << channelBits;
    }

    @Override
    public void initialized() {
        img = new PixelImage(width, height);

        colorCube = new boolean[channelSize * channelSize * channelSize];
        foundColors = new long[channelSize * channelSize * channelSize];

        new Thread(this).start();
    }

    @Override
    public void resized() {}

    @Override
    public void run() {
        timer = new javax.swing.Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                draw();
            }
        });

        // for (double d = 0.2; d < 200; d *= 1.2)
        {
            img.clear(0);
            init(0);
            render();
        }

        // System.exit(0);
    }

    private void init(double param) {
        // RandomFunctions.RND.setSeed(0);

        Arrays.fill(colorCube, false);

        // scheduler = new SpiralScheduler(param);
        scheduler.init(width, height);
    }

    private void render() {
        timer.start();

        while (scheduler.getProgress() != 1) {
            int point = findPoint();
            int color = findColor(point);
            setPixel(point, color);
        }

        timer.stop();
        draw();

        try {
            ImageFunctions.savePNG(System.currentTimeMillis() + ".png", img.image);
        }
        catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    void draw() {
        g.drawImage(img.image, 0, 0, getWidth(), getHeight(), 0, 0, width, height, null);
        repaintNow();
        setTitle(Double.toString(scheduler.getProgress()));
    }

    private int findPoint() {
        ScheduledPoint p = scheduler.poll();

        // try {
        // Thread.sleep(1);
        // }
        // catch (InterruptedException e) {
        // }

        return p.x + width * p.y;
    }

    private int findColor(int point) {
        // int z = 0;
        // for (int i = 0; i < colorCube.length; i++)
        // if (!colorCube[i])
        // System.out.println(i);

        int x = point & width - 1;
        int y = point / width;

        // Calculate the reference color as the average of all 8-connected
        // colors.
        int r = 0;
        int g = 0;
        int b = 0;
        int n = 0;
        for (int j = -3; j <= 3; j++) {
            for (int i = -3; i <= 3; i++) {
                point = (x + i & width - 1) + width * (y + j & height - 1);
                int f = (int)Math.round(10000 * Math.exp((i * i + j * j) * -0.4));
                if (img.pixels[point] != 0) {
                    int pixel = img.pixels[point];

                    r += (pixel >> 24 - channelBits & channelSize - 1) * f;
                    g += (pixel >> 16 - channelBits & channelSize - 1) * f;
                    b += (pixel >> 8 - channelBits & channelSize - 1) * f;
                    n += f;
                }
                // System.out.print(f + "\t");
            }
            // System.out.println();
        }
        if (n > 0) {
            r /= n;
            g /= n;
            b /= n;
        }

        // Find a color that is preferably darker but not too far from the
        // original. This algorithm might fail to take some darker colors at the
        // start, and when the image is almost done the size will become really
        // huge because only bright reference pixels are being searched for.
        // This happens with a probability of 50% with 6 channelBits, and more
        // with higher channelBits values.
        //
        // Try incrementally larger distances from reference color.
        for (int size = 2; size <= channelSize; size *= 2) {
            n = 0;

            // Find all colors in a neighborhood from the reference color (-1 if
            // already taken).
            for (int ri = r - size; ri <= r + size; ri++) {
                if (ri < 0 || ri >= channelSize)
                    continue;
                int plane = ri * channelSize * channelSize;
                int dr = Math.abs(ri - r);
                for (int gi = g - size; gi <= g + size; gi++) {
                    if (gi < 0 || gi >= channelSize)
                        continue;
                    int slice = plane + gi * channelSize;
                    int drg = Math.max(dr, Math.abs(gi - g));
                    // int mrg = Math.min(ri, gi);
                    long srg = ri * 299L + gi * 436L;
                    for (int bi = b - size; bi <= b + size; bi++) {
                        if (bi < 0 || bi >= channelSize)
                            continue;
                        if (Math.max(drg, Math.abs(bi - b)) > size)
                            continue;
                        if (!colorCube[slice + bi])
                            // foundColors[n++] = Math.min(mrg, bi) <<
                            // channelBits * 3 | slice + bi;
                            foundColors[n++] = srg + bi * 114L << channelBits * 3 | slice + bi;
                    }
                }
            }

            if (n > 0) {
                // Sort by distance from origin.
                Arrays.sort(foundColors, 0, n);

                // Find a random color amongst all colors equally distant from
                // the origin.
                int lowest = (int)(foundColors[0] >> channelBits * 3);
                for (int i = 1; i < n; i++) {
                    if (foundColors[i] >> channelBits * 3 > lowest) {
                        n = i;
                        break;
                    }
                }

                int nextInt = RandomFunctions.RND.nextInt(n);
                return (int)(foundColors[nextInt] & (1 << channelBits * 3) - 1);
            }
        }

        return -1;
    }

    private void setPixel(int point, int color) {
        int b = color & channelSize - 1;
        int g = color >> channelBits & channelSize - 1;
        int r = color >> channelBits * 2 & channelSize - 1;
        img.pixels[point] = 0xFF000000 | ((r << 8 | g) << 8 | b) << 8 - channelBits;

        colorCube[color] = true;
    }
}
  • Açısal (8)

görüntü tanımını buraya girin

  • Açısal (64)

görüntü tanımını buraya girin

  • CRT

görüntü tanımını buraya girin

  • titreme

görüntü tanımını buraya girin

  • Çiçek (5, X), burada X, X = X × 1.2 adımlarında 0.5 ila 20 arasındadır

görüntü tanımını buraya girin

  • şık

görüntü tanımını buraya girin

  • Pisagor

görüntü tanımını buraya girin

  • Radyal

görüntü tanımını buraya girin

  • rasgele

görüntü tanımını buraya girin

  • scanline

görüntü tanımını buraya girin

  • Spiral (X), burada X, X = X × 1.2 kademelerinde 0.1 ila 200 arasındadır.
  • Radyalden Köşeye (5) arasındaki araları görebilirsiniz.

görüntü tanımını buraya girin

  • Bölünmüş

görüntü tanımını buraya girin

  • SquareSpiral

görüntü tanımını buraya girin

  • XOR

görüntü tanımını buraya girin

Yeni göz yemi

  • Renk seçiminin etkisi max(r, g, b)

görüntü tanımını buraya girin

  • Renk seçiminin etkisi min(r, g, b)
  • Bunun, yukarıdakilerle tamamen aynı özelliklere / detaylara sahip olduğuna dikkat edin! (aynı rastgele tohum)

görüntü tanımını buraya girin

  • Renk seçiminin etkisi max(r, min(g, b))

görüntü tanımını buraya girin

  • Renk seçiminin gri değere etkisi 299*r + 436*g + 114*b

görüntü tanımını buraya girin

  • Renk seçiminin etkisi 1*r + 10*g + 100*b

görüntü tanımını buraya girin

  • Renk seçiminin etkisi 100*r + 10*g + 1*b

görüntü tanımını buraya girin

  • 299*r + 436*g + 114*b32-bit bir tamsayıda taşması durumunda mutlu kazalar

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin

  • Varyant 3, gri değer ve Radyal zamanlayıcı

görüntü tanımını buraya girin

  • Bunu nasıl yarattığımı unuttum

görüntü tanımını buraya girin

  • CRT Zamanlayıcısı ayrıca mutlu bir tamsayı taşması hatası yaşamıştır (ZIP'i güncelledi), ortada 512 × 512 görüntü ile yarı yolda başlaması sağlandı. Görünmesi gereken şey bu:

görüntü tanımını buraya girin görüntü tanımını buraya girin

  • InverseSpiralScheduler(64) (yeni)

görüntü tanımını buraya girin

  • Başka bir XOR

görüntü tanımını buraya girin

  • 4096'nın ilk başarılı düzeltmesi yapıldı. Bu sürüm 3 SpiralScheduler(1)ya da başka bir şey olduğunu düşünüyorum

görüntü tanımını buraya girin (50MB !!)

  • Sürüm 1 4096, ancak yanlışlıkla renk kriterlerini bıraktım max()

görüntü tanımını buraya girin (50MB !!)

  • 4096, şimdi min()
  • Bunun, yukarıdakilerle tamamen aynı özelliklere / detaylara sahip olduğuna dikkat edin! (aynı rastgele tohum)
  • Zaman: kaydetmeyi unuttum ancak zaman damgası dosya önceki görüntüden 3 dakika sonra

görüntü tanımını buraya girin (50MB !!)


Güzel. Son imajınız, etrafta savurduğum ikinci bir fikre benziyor, ancak benimkilerin o kadar iyi görünmeyeceği hissine sahibim. Btw , allrgb.com/diffusive de benzer serin bir tane var .
Jason C

Sadece bir teaser olarak düşünülmüştü, ancak görünüşe göre olan, işaretlenme korkusuyla değiştirdim :)
Mark Jeronimus

2
Kazalar bile güzel görünüyor :). Renkli küp çok iyi bir fikir gibi görünüyor ve render hızlarınız benimkine kıyasla inanılmaz. Allrgb'deki bazı tasarımların iyi bir açıklaması vardır, örneğin allrgb.com/dla. Keşke daha fazla deney yapmak için daha fazla zamanım olsaydı, çok fazla olasılık var ...
fejesjoco

Neredeyse unutuyordum, sadece büyük işlerimin bir kısmını yükledim. Sanırım onlardan biri, gökkuşağı dumanı / dökülen mürekkebi olan şey, allrgb'deki her şeyden daha iyidir :). Katılıyorum, diğerleri o kadar çarpıcı değil, bu yüzden onlardan daha fazlasını yapmak için bir video çektim :).
fejesjoco

Kaynak kodu ve Digisoft kütüphanesine bağlantı eklendi, böylece kodumu derleyebilirsiniz
Mark Jeronimus

72

C ++ a / a

Seni görüyorum versiyon:

görüntü tanımını buraya girin

renkler için normal dağılım kullanma:

görüntü tanımını buraya girin görüntü tanımını buraya girin

veya ilk önce kırmızı / renk tonuna göre sıralanır (daha küçük sapma ile):

görüntü tanımını buraya girin görüntü tanımını buraya girin

veya diğer bazı dağıtımlar:

görüntü tanımını buraya girin görüntü tanımını buraya girin

Cauchy dağılımı (hsl / kırmızı):

görüntü tanımını buraya girin görüntü tanımını buraya girin

açıklığa göre sıralanmış sütunlar (hsl):

görüntü tanımını buraya girin

güncellenmiş kaynak kodu - 6. resmi üretir:

int main() {
    const int c = 256*128;
    std::vector<QRgb> data(c);
    QImage image(256, 128, QImage::Format_RGB32);

    std::default_random_engine gen;
    std::normal_distribution<float> dx(0, 2);
    std::normal_distribution<float> dy(0, 1);

    for(int i = 0; i < c; ++i) {
        data[i] = qRgb(i << 3 & 0xF8, i >> 2 & 0xF8, i >> 7 & 0xF8);
    }
    std::sort(data.begin(), data.end(), [] (QRgb a, QRgb b) -> bool {
        return QColor(a).hsvHue() < QColor(b).hsvHue();
    });

    int i = 0;
    while(true) {
        if(i % 10 == 0) { //no need on every iteration
            dx = std::normal_distribution<float>(0, 8 + 3 * i/1000.f);
            dy = std::normal_distribution<float>(0, 4 + 3 * i/1000.f);
        }
        int x = (int) dx(gen);
        int y = (int) dy(gen);
        if(x < 256 && x >= 0 && y >= 0 && y < 128) {
            if(!image.pixel(x, y)) {
                image.setPixel(x, y, data[i]);
                if(i % (c/100) == 1) {
                    std::cout << (int) (100.f*i/c) << "%\n";
                }
                if(++i == c) break;
            }
        }
    }
    image.save("tmp.png");
    return 0;
}

Güzel bitti. Ancak, image.pixel(x, y) == 0ilk yerleştirilen pikselin üzerine düşüp üzerine yazılamaz mı?
Mark Jeronimus

@ Zom-B: Olabilir, ama sonra sonuncusu siyah olacak, bu yüzden kurallar dahilinde ...
Jaa-c

Yine de kural sorunu yok. Sadece özlemiş olabileceğini düşündüm. Belki o zaman 1'den saymak. Diğerlerini seviyorum!
Mark Jeronimus

@ Zom-B: teşekkürler, birkaç tane daha ekleyebilirim, beğendim: P
Jaa-c

İki dairesi olan ve altındaki taraf maymun yüzüne benziyor.
Jason C,

64

Java’da:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;

import javax.imageio.ImageIO;

public class ImgColor {

    private static class Point {
        public int x, y;
        public color c;

        public Point(int x, int y, color c) {
            this.x = x;
            this.y = y;
            this.c = c;
        }
    }

    private static class color {
        char r, g, b;

        public color(int i, int j, int k) {
            r = (char) i;
            g = (char) j;
            b = (char) k;
        }
    }

    public static LinkedList<Point> listFromImg(String path) {
        LinkedList<Point> ret = new LinkedList<>();
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int x = 0; x < 4096; x++) {
            for (int y = 0; y < 4096; y++) {
                Color c = new Color(bi.getRGB(x, y));
                ret.add(new Point(x, y, new color(c.getRed(), c.getGreen(), c.getBlue())));
            }
        }
        Collections.shuffle(ret);
        return ret;
    }

    public static LinkedList<color> allColors() {
        LinkedList<color> colors = new LinkedList<>();
        for (int r = 0; r < 256; r++) {
            for (int g = 0; g < 256; g++) {
                for (int b = 0; b < 256; b++) {
                    colors.add(new color(r, g, b));
                }
            }
        }
        Collections.shuffle(colors);
        return colors;
    }

    public static Double cDelta(color a, color b) {
        return Math.pow(a.r - b.r, 2) + Math.pow(a.g - b.g, 2) + Math.pow(a.b - b.b, 2);
    }

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        LinkedList<Point> orig = listFromImg(args[0]);
        LinkedList<color> toDo = allColors();

        Point p = null;
        while (orig.size() > 0 && (p = orig.pop()) != null) {
            color chosen = toDo.pop();
            for (int i = 0; i < Math.min(100, toDo.size()); i++) {
                color c = toDo.pop();
                if (cDelta(c, p.c) < cDelta(chosen, p.c)) {
                    toDo.add(chosen);
                    chosen = c;
                } else {
                    toDo.add(c);
                }
            }
            img.setRGB(p.x, p.y, new Color(chosen.r, chosen.g, chosen.b).getRGB());
        }
        try {
            ImageIO.write(img, "PNG", new File(args[1]));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

ve bir giriş görüntüsü:

maki

Böyle bir şey üretiyorum:

acidLemur

Burada sıkıştırılmamış sürüm: https://www.mediafire.com/?7g3fetvaqhoqgh8

Bilgisayarım, 4096 ^ 2 görüntü almak için yaklaşık 30 dakika sürüyor; bu, ilk uygulamamın alacağı 32 gün boyunca büyük bir gelişme.


1
ah; 32 gün komik gelmiyordu ..... fejesjocos'taki ortalama algoritma 4k'dan daha iyi yanıt vermeden önce yanıtlar muhtemelen birden fazla ay
alacaktı

5
Punk kaşlarını seviyorum!
Seviye Nehri St

45

BubbleSort ile Java

(genellikle Bubblesort bundan çok hoşlanmıyordu ama bu meydan okuma için sonunda kullanıldı :) birbirinden ayrı olarak 4096 adımda tüm unsurlarla bir çizgi oluşturdu, sonra karıştırdı; sıralama çarpıldı ve her bir değer, sıralama sırasında değerine 1 eklendi, sonuç olarak sıralanan değerleri ve tüm renkleri aldınız.

Bu büyük çizgilerin kaldırılması için Sourcecode güncellendi
(biraz bitsel büyü gerekli: P)

class Pix
{
    public static void main(String[] devnull) throws Exception
    {
        int chbits=8;
        int colorsperchannel=1<<chbits;
        int xsize=4096,ysize=4096;
        System.out.println(colorsperchannel);
        int[] x = new int[xsize*ysize];//colorstream

        BufferedImage i = new BufferedImage(xsize,ysize, BufferedImage.TYPE_INT_RGB);
        List<Integer> temp = new ArrayList<>();
        for (int j = 0; j < 4096; j++)
        {
            temp.add(4096*j);
        }
        int[] temp2=new int[4096];

        Collections.shuffle(temp,new Random(9263));//intended :P looked for good one
        for (int j = 0; j < temp.size(); j++)
        {
            temp2[j]=(int)(temp.get(j));
        }
        x = spezbubblesort(temp2, 4096);
        int b=-1;
        int b2=-1;
        for (int j = 0; j < x.length; j++)
        {
            if(j%(4096*16)==0)b++;
            if(j%(4096)==0)b2++;
            int h=j/xsize;
            int w=j%xsize;
            i.setRGB(w, h, x[j]&0xFFF000|(b|(b2%16)<<8));
            x[j]=x[j]&0xFFF000|(b|(b2%16)<<8);
        }  

        //validator sorting and checking that all values only have 1 difference
        Arrays.sort(x);
        int diff=0;
        for (int j = 1; j < x.length; j++)
        {
            int ndiff=x[j]-x[j-1];
            if(ndiff!=diff)
            {
                System.out.println(ndiff);
            }
            diff=ndiff;

        }
        OutputStream out = new BufferedOutputStream(new FileOutputStream("RGB24.bmp"));
        ImageIO.write(i, "bmp", out);

    }
    public static int[] spezbubblesort(int[] vals,int lines)
    {
        int[] retval=new int[vals.length*lines];
        for (int i = 0; i < lines; i++)
        {
            retval[(i<<12)]=vals[0];
            for (int j = 1; j < vals.length; j++)
            {
                retval[(i<<12)+j]=vals[j];
                if(vals[j]<vals[j-1])
                {

                    int temp=vals[j-1];
                    vals[j-1]=vals[j];
                    vals[j]=temp;
                }
                vals[j-1]=vals[j-1]+1;
            }
            vals[lines-1]=vals[lines-1]+1;
        }
        return retval;
    }
}

Sonuç:

Eski versiyon

class Pix
{
    public static void main(String[] devnull) throws Exception
    {
        int[] x = new int[4096*4096];//colorstream
        int idx=0;
        BufferedImage i = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        //GENCODE
        List<Integer> temp = new ArrayList<>();
        for (int j = 0; j < 4096; j++)
        {
            temp.add(4096*j);
        }
        int[] temp2=new int[4096];

        Collections.shuffle(temp,new Random(9263));//intended :P looked for good one
        for (int j = 0; j < temp.size(); j++)
        {
            temp2[j]=(int)(temp.get(j));
        }
        x = spezbubblesort(temp2, 4096);
        for (int j = 0; j < x.length; j++)
        {
            int h=j/4096;
            int w=j%4096;
            i.setRGB(w, h, x[j]);
        }
        //validator sorting and checking that all values only have 1 difference
        Arrays.sort(x);
        int diff=0;
        for (int j = 1; j < x.length; j++)
        {
            int ndiff=x[j]-x[j-1];
            if(ndiff!=diff)
            {
                System.out.println(ndiff);
            }
            diff=ndiff;

        }
        OutputStream out = new BufferedOutputStream(new FileOutputStream("RGB24.bmp"));
        ImageIO.write(i, "bmp", out);
    }
    public static int[] spezbubblesort(int[] vals,int lines)
    {
        int[] retval=new int[vals.length*lines];
        for (int i = 0; i < lines; i++)
        {
            retval[(i<<12)]=vals[0];
            for (int j = 1; j < vals.length; j++)
            {
                retval[(i<<12)+j]=vals[j];
                if(vals[j]<vals[j-1])
                {

                    int temp=vals[j-1];
                    vals[j-1]=vals[j];
                    vals[j]=temp;
                }
                vals[j-1]=vals[j-1]+1;
            }
            vals[lines-1]=vals[lines-1]+1;
        }
        return retval;
    }
}

çıktı önizlemesi


AllRGB sayfasında zaten bir QuickSort sürümü var.
Mark Jeronimus

1
@ Zom-B Quicksort, Bubblesort'tan farklı bir algoritmadır
masterX244

43

C

Tamamen farklı girdaplar içeren düz ve tuhaf çerçeveler ile anlamadığım nedenlerle girdap oluşturur.

Bu ilk 50 garip karenin bir önizlemesi:

girdap önizlemesi

PPM’den demo’ya komple renk kapsamına çevrilmiş örnek resim:

örnek resim

Daha sonra, hepsi griye karıştığında, hala döndüğünü görebilirsiniz: daha uzun sıra .

Aşağıdaki gibi kodlayın. Çalıştırmak için, kare numarasını ekleyin, örneğin:

./vortex 35 > 35.ppm

Bunu bir animasyonlu GIF almak için kullandım:

dönüştürmek-gecikme 10 `ls * .ppm | sıralama -n | xargs` - loop 0 vortex.gif
#include <stdlib.h>
#include <stdio.h>

#define W 256
#define H 128

typedef struct {unsigned char r, g, b;} RGB;

int S1(const void *a, const void *b)
{
    const RGB *p = a, *q = b;
    int result = 0;

    if (!result)
        result = (p->b + p->g * 6 + p->r * 3) - (q->b + q->g * 6 + q->r * 3);

    return result;
}

int S2(const void *a, const void *b)
{
    const RGB *p = a, *q = b;
    int result = 0;

    if (!result)
        result = p->b * 6 - p->g;
    if (!result)
        result = p->r - q->r;
    if (!result)
        result = p->g - q->b * 6;

    return result;
}

int main(int argc, char *argv[])
{
    int i, j, n;
    RGB *rgb = malloc(sizeof(RGB) * W * H);
    RGB c[H];

    for (i = 0; i < W * H; i++)
    {
        rgb[i].b = (i & 0x1f) << 3;
        rgb[i].g = ((i >> 5) & 0x1f) << 3;
        rgb[i].r = ((i >> 10) & 0x1f) << 3;
    }

    qsort(rgb, H * W, sizeof(RGB), S1);

    for (n = 0; n < atoi(argv[1]); n++)
    {
        for (i = 0; i < W; i++)
        {
            for (j = 0; j < H; j++)
                c[j] = rgb[j * W + i];
            qsort(c, H, sizeof(RGB), S2);
            for (j = 0; j < H; j++)
                rgb[j * W + i] = c[j];
        }

        for (i = 0; i < W * H; i += W)
            qsort(rgb + i, W, sizeof(RGB), S2);
    }

    printf("P6 %d %d 255\n", W, H);
    fwrite(rgb, sizeof(RGB), W * H, stdout);

    free(rgb);

    return 0;
}

53
Biliyorsun, bir şey olduğunda "anlamıyorum".
Nit

2
Evet, genellikle ne bekleyeceğimi biliyorum, ama burada sadece hangi kalıpları alabileceğimi görmek için uğraşıyordum ve kaosun içindeki bu sonlanma sırası sırası ortaya çıktı.

8
Karşılaştırma işleviniz üçgen eşitsizliğini takip etmediğinden vortekslenir. Örneğin, r> b, b> g, g> r. Java ile bağlantı kuramıyorum bile çünkü bu çok özelliğe dayanıyor, bu nedenle "Karşılaştırma yöntemi genel sözleşmesini ihlal ediyor!" İstisnasını alıyorum.
Mark Jeronimus

2
Deneyeceğim p->b * 6 - q->g;ama girdabı mahvederse düzeltmez!

4
Anlamadığım nedenlerden dolayı +1.
Jason C,

40

Java

512x512'deki renk seçicinin varyasyonları. Şık kod değil , ama güzel resimleri severim:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

public class EighteenBitColors {

    static boolean shuffle_block = false;
    static int shuffle_radius = 0;

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);
        for(int r=0;r<64;r++)
            for(int g=0;g<64;g++)
                for(int b=0;b<64;b++)
                    img.setRGB((r * 8) + (b / 8), (g * 8) + (b % 8), ((r * 4) << 8 | (g * 4)) << 8 | (b * 4));

        if(shuffle_block)
            blockShuffle(img);
        else
            shuffle(img, shuffle_radius);

        try {           
            ImageIO.write(img, "png", new File(getFileName()));
        } catch(IOException e){
            System.out.println("suck it");
        }
    }

    public static void shuffle(BufferedImage img, int radius){
        if(radius < 1)
            return;
        int width = img.getWidth();
        int height = img.getHeight();
        Random rand = new Random();
        for(int x=0;x<512;x++){
            for(int y=0;y<512;y++){
                int xx = -1;
                int yy = -1;
                while(xx < 0 || xx >= width){
                    xx = x + rand.nextInt(radius*2+1) - radius;
                }
                while(yy < 0 || yy >= height){
                    yy = y + rand.nextInt(radius*2+1) - radius;
                }
                int tmp = img.getRGB(xx, yy);
                img.setRGB(xx, yy, img.getRGB(x, y));
                img.setRGB(x,y,tmp);
            }
        }
    }

    public static void blockShuffle(BufferedImage img){
        int tmp;
        Random rand = new Random();
        for(int bx=0;bx<8;bx++){
            for(int by=0;by<8;by++){
                for(int x=0;x<64;x++){
                    for(int y=0;y<64;y++){
                        int xx = bx*64+x;
                        int yy = by*64+y;
                        int xxx = bx*64+rand.nextInt(64);
                        int yyy = by*64+rand.nextInt(64);
                        tmp = img.getRGB(xxx, yyy);
                        img.setRGB(xxx, yyy, img.getRGB(xx, yy));
                        img.setRGB(xx,yy,tmp);
                    }
                }
            }
        }
    }

    public static String getFileName(){
        String fileName = "allrgb_";
        if(shuffle_block){
            fileName += "block";
        } else if(shuffle_radius > 0){
            fileName += "radius_" + shuffle_radius;
        } else {
            fileName += "no_shuffle";
        }
        return fileName + ".png";
    }
}

Yazıldığı gibi çıktı:

karıştırma

Çalıştırırsanız shuffle_block = true, her 64x64 bloğundaki renkleri karıştırır:

blok karıştır

Aksi takdirde, birlikte çalıştırırsanız shuffle_radius > 0, her pikseli shuffle_radiusx / y içinde rastgele bir pikselle karıştırır . Çeşitli boyutlarda oynadıktan sonra 32 piksel yarıçapı severim, çünkü etrafta çok fazla hareket etmeden çizgileri bulanıklaştırır:

görüntü tanımını buraya girin


3
ooh bu resimler en güzel
sevenseacat

Bunlar gerçekten harika 😍
Matthew

37

İşleme

C ile başlıyorum (diğer dillerde programlanmış) ancak Visual C'deki grafikleri takip etmesi zor buldum, bu yüzden @ace tarafından kullanılan bu İşleme programını indirdim.

İşte kodum ve algoritmam.

void setup(){
  size(256,128);
  background(0);
  frameRate(1000000000);
  noLoop();
 }

int x,y,r,g,b,c;
void draw() {
  for(y=0;y<128;y++)for(x=0;x<128;x++){
    r=(x&3)+(y&3)*4;
    g=x>>2;
    b=y>>2;
    c=0;
    //c=x*x+y*y<10000? 1:0; 
    stroke((r^16*c)<<3,g<<3,b<<3);
    point(x,y);
    stroke((r^16*(1-c))<<3,g<<3,b<<3);
    point(255-x,y);  
  } 
}

Algoritma

X, y cinsinden, yeşil ve mavinin 32 değerinin olası tüm kombinasyonlarının 4x4 kareleriyle başlayın. 128x128 kare kare biçiminde, her 4 x 4 kare 16 pikseldir, bu nedenle aşağıdaki resim başına yeşil ve mavi her olası kombinasyondan 32 piksel vermek üzere yanına bir ayna görüntüsü yapın.

(tuhaf tam yeşil tam camgöbeği daha parlak görünüyor. Bu bir optik yanılsama olmalıdır. yorumlarda açıklık)

Soldaki karede 0-15 kırmızı değerlerini ekleyin. Sağ kare için, XOR bu değerleri 16 ile 16-31 arasında yapar.

görüntü tanımını buraya girin

Çıkış 256x128

Bu, aşağıdaki en üstteki görüntüdeki çıktıyı verir.

Bununla birlikte, her piksel ayna görüntüsünden sadece kırmızı değerin en önemli bitinde değişir. Böylece, cbu iki pikseli değiştirmeyle aynı etkiye sahip olan XOR'u tersine çevirmek için değişkenle bir koşul uygulayabilirim .

Buna bir örnek, aşağıdaki alt resimde verilmiştir (şu anda yorumlanmış olan kod satırına uymazsak).

görüntü tanımını buraya girin

512 x 512 - Andy Warhol'un Marylin'i haraç

Quincunx'un bu soruya cevabından ve serbest kırmızı dairelerde "kötü bir sırıtış" dan esinlenerek, bu benim ünlü resmin versiyonudur. Orjinalinde 25 renkli Marilin ve 25 siyah beyaz Marilin vardı ve Warhol'un zamansız ölümünden sonra Marylin'e verdiği haraçtı. Bkz http://en.wikipedia.org/wiki/Marilyn_Diptych

Processing'in 256x128'de kullandıkları yarı saydam olarak oluşturduğunu keşfettikten sonra farklı işlevlere geçtim. Yenileri opaktır.

Görüntü tamamen algoritmik olmasa da, hoşuma gidiyor.

int x,y,r,g,b,c;
PImage img;
color p;
void setup(){
  size(512,512);
  background(0);
  img = loadImage("marylin256.png");
  frameRate(1000000000);
  noLoop();
 }

void draw() {

   image(img,0,0);

   for(y=0;y<256;y++)for(x=0;x<256;x++){
      // Note the multiplication by 0 in the next line. 
      // Replace the 0 with an 8 and the reds are blended checkerboard style
      // This reduces the grain size, but on balance I decided I like the grain.
      r=((x&3)+(y&3)*4)^0*((x&1)^(y&1));
      g=x>>2;
      b=y>>2; 
      c=brightness(get(x,y))>100? 32:0;
      p=color((r^c)<<2,g<<2,b<<2);
      set(x,y,p);
      p=color((r^16^c)<<2,g<<2,b<<2);
      set(256+x,y,p);  
      p=color((r^32^c)<<2,g<<2,b<<2);
      set(x,256+y,p);
      p=color((r^48^c)<<2,g<<2,b<<2);
      set(256+x,256+y,p);  
 } 
 save("warholmarylin.png");

}

görüntü tanımını buraya girin

512x512 Alacakaranlık mesafe dağlar ile bir göl üzerinde

İşte, tamamen algoritmik bir resim. Durumla hangi rengi değiştirdiğimi değiştirerek oynadım, ancak kırmızının en iyi sonuç verdiği sonucuna geri döndüm. Marylin resmine benzer şekilde, önce dağları çizerim, sonra negatif yarıya kopyalarken, pozitif RGB resmin üzerine yazmak için o resimdeki parlaklığı seçerim. Hafif bir fark, dağların çoğunun tabanının (hepsi aynı boyutta çekildiği için) okuma alanının altına uzanmasıdır, bu nedenle bu alan okuma işlemi sırasında basitçe kırpılır (bu nedenle farklı boyuttaki dağların istenen izlenimini verir). )

Bu bir pozitif için 32 kırmızı, 8x4 hücre ve negatif için geri kalan 32 kırmızı kullanın.

Kodumun sonunda expicit komutunu frameRate (1) 'e not edin. Bu komut olmadan, İşlemeyi çizmeyi bitirmiş olmasına rağmen İşlemcimin bir çekirdeğinin% 100'ünü kullanacağını keşfettim. Uyku işlevi olmadığını söyleyebildiğim kadarıyla, tek yapabileceğiniz yoklama sıklığını azaltmak.

int i,j,x,y,r,g,b,c;
PImage img;
color p;
void setup(){
  size(512,512);
  background(255,255,255);
  frameRate(1000000000);
  noLoop();
 }

void draw() {
  for(i=0; i<40; i++){
    x=round(random(512));
    y=round(random(64,256));
    for(j=-256; j<256; j+=12) line(x,y,x+j,y+256);  
  }
  for(y=0;y<256;y++)for(x=0;x<512;x++){
    r=(x&7)+(y&3)*8;
    b=x>>3;
    g=(255-y)>>2;
    c=brightness(get(x,y))>100? 32:0;
    p=color((r^c)<<2,g<<2,b<<2);
    set(x,y,p);
    p=color((r^32^c)<<2,g<<2,b<<2);
    set(x,511-y,p);  
  }
  save("mountainK.png");
  frameRate(1);
}

görüntü tanımını buraya girin


Çünkü hiç de tam mavi değil. (0,217,217). Yine de 32 kombinasyon da gerdirilmemiş halde bulunmaktadır [0,255]. Düzenleme: 7 adımlarını kullanıyorsunuz ancak kodda bulamıyorum. İşlem yapan bir şey olmalı.
Mark Jeronimus

@steveverrill İşleme'de, save("filename.png")geçerli çerçeve arabelleğini bir görüntüye kaydetmek için yapabilirsiniz . Diğer görüntü formatları da desteklenir. Size ekran görüntüsü alma zahmetinden kurtarır. Resim, taslak klasörüne kaydedilir.
Jason C

@Jasonc bahşiş için teşekkürler, bir yol olması gerektiğinden emindim, ancak bunları düzenleyeceğimi sanmıyorum. Çerçeveyi resimlerin etrafından kısmen ayırdım (bunları böylesine küçük resimler için 2 dosya aşıldı.) 512x512'de bazı görüntüler yapmak istiyorum (ve özellikle bir fikrim var.) Bu şekilde yükleyeceğim. Sen öneriyorsun.
Seviye Nehri St

1
@ steveverrill Haha, Warhols hoş bir dokunuş.
Jason C,

@ Zom-B Processing, (sinir bozucu şekilde) belgelerinde bahsedilmeyen birçok şeyi yapıyor gibi görünüyor: fiziksel çıktısında tam 256 mantıksal renk kanalı değerini kullanmamak, istemediğinizde renkleri karıştırmak, tam bir çekirdek kullanmak İşlemcim bittikten sonra bile. Hala girmeniz çok kolay ve orada olduklarını öğrendikten sonra bu sorunların üstesinden gelebilirsiniz (ilki dışında, henüz
Level River St

35

JavaScript’teki bir Hilbert eğrisindeki tüm 16 bit renkleri (5r, 6g, 5b) düzenledim .

Hilbert eğrisi renkleri

Önceki, (Hilbert eğrisi değil) görüntü:

Hilbert eğrisi

JSfiddle: jsfiddle.net/LCsLQ/3

JavaScript

// ported code from http://en.wikipedia.org/wiki/Hilbert_curve
function xy2d (n, p) {
    p = {x: p.x, y: p.y};
    var r = {x: 0, y: 0},
        s,
        d=0;
    for (s=(n/2)|0; s>0; s=(s/2)|0) {
        r.x = (p.x & s) > 0 ? 1 : 0;
        r.y = (p.y & s) > 0 ? 1 : 0;
        d += s * s * ((3 * r.x) ^ r.y);
        rot(s, p, r);
    }
    return d;
}

//convert d to (x,y)
function d2xy(n, d) {
    var r = {x: 0, y: 0},
        p = {x: 0, y: 0},
        s,
        t=d;
    for (s=1; s<n; s*=2) {
        r.x = 1 & (t/2);
        r.y = 1 & (t ^ rx);
        rot(s, p, r);
        p.x += s * r.x;
        p.y += s * r.y;
        t /= 4;
    }
    return p;
}

//rotate/flip a quadrant appropriately
function rot(n, p, r) {
    if (r.y === 0) {
        if (r.x === 1) {
            p.x = n-1 - p.x;
            p.y = n-1 - p.y;
        }

        //Swap x and y
        var t  = p.x;
        p.x = p.y;
        p.y = t;
    }
}
function v2rgb(v) {
    return ((v & 0xf800) << 8) | ((v & 0x7e0) << 5) | ((v & 0x1f) << 3); 
}
function putData(arr, size, coord, v) {
    var pos = (coord.x + size * coord.y) * 4,
        rgb = v2rgb(v);

    arr[pos] = (rgb & 0xff0000) >> 16;
    arr[pos + 1] = (rgb & 0xff00) >> 8;
    arr[pos + 2] = rgb & 0xff;
    arr[pos + 3] = 0xff;
}
var size = 256,
    context = a.getContext('2d'),
    data = context.getImageData(0, 0, size, size);

for (var i = 0; i < size; i++) {
    for (var j = 0; j < size; j++) {
        var p = {x: j, y: i};
        putData(data.data, size, p, xy2d(size, p));
    }
}
context.putImageData(data, 0, 0);

Düzenleme : Hilbert eğrisini hesaplamak için fonksiyonumda bir hata olduğu ortaya çıktı ve hatalıydı; yani, olarak r.x = (p.x & s) > 0; r.y = (p.y & s) > 0;değiştirildir.x = (p.x & s) > 0 ? 1 : 0; r.y = (p.y & s) > 0 ? 1 : 0;

Düzenleme 2: Başka bir fraktal:

Sierpinski

http://jsfiddle.net/jej2d/5/


Güzel! PPCG'ye Hoşgeldiniz.
Jonathan Van Matre

Renkli küpten geçerken bir 3D Hilbert eğrisinde göründüğünde nasıl görünüyor? Düzenleme nm. biri sadece bunu yaptı.
Mark Jeronimus

35

C #: Yinelemeli yerel benzerlik optimizasyonu

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace AllColors
{
    class Program
    {
        static Random _random = new Random();

        const int ImageWidth = 256;
        const int ImageHeight = 128;
        const int PixelCount = ImageWidth * ImageHeight;
        const int ValuesPerChannel = 32;
        const int ChannelValueDelta = 256 / ValuesPerChannel;

        static readonly int[,] Kernel;
        static readonly int KernelWidth;
        static readonly int KernelHeight;

        static Program()
        {
            // Version 1
            Kernel = new int[,] { { 0, 1, 0, },
                                  { 1, 0, 1, },
                                  { 0, 1, 0, } };
            // Version 2
            //Kernel = new int[,] { { 0, 0, 1, 0, 0 },
            //                      { 0, 2, 3, 2, 0 },
            //                      { 1, 3, 0, 3, 1 },
            //                      { 0, 2, 3, 2, 0 },
            //                      { 0, 0, 1, 0, 0 } };
            // Version 3
            //Kernel = new int[,] { { 3, 0, 0, 0, 3 },
            //                      { 0, 1, 0, 1, 0 },
            //                      { 0, 0, 0, 0, 0 },
            //                      { 0, 1, 0, 1, 0 },
            //                      { 3, 0, 0, 0, 3 } };
            // Version 4
            //Kernel = new int[,] { { -9, -9, -9, -9, -9 },
            //                      {  1,  2,  3,  2,  1 },
            //                      {  2,  3,  0,  3,  2 },
            //                      {  1,  2,  3,  2,  1 },
            //                      {  0,  0,  0,  0,  0 } };
            // Version 5
            //Kernel = new int[,] { { 0, 0, 1, 0, 0, 0, 0 },
            //                      { 0, 1, 2, 1, 0, 0, 0 },
            //                      { 1, 2, 3, 0, 1, 0, 0 },
            //                      { 0, 1, 2, 0, 0, 0, 0 },
            //                      { 0, 0, 1, 0, 0, 0, 0 } };
            KernelWidth = Kernel.GetLength(1);
            KernelHeight = Kernel.GetLength(0);

            if (KernelWidth % 2 == 0 || KernelHeight % 2 == 0)
            {
                throw new InvalidOperationException("Invalid kernel size");
            }
        }

        private static Color[] CreateAllColors()
        {
            int i = 0;
            Color[] colors = new Color[PixelCount];
            for (int r = 0; r < ValuesPerChannel; r++)
            {
                for (int g = 0; g < ValuesPerChannel; g++)
                {
                    for (int b = 0; b < ValuesPerChannel; b++)
                    {
                        colors[i] = Color.FromArgb(255, r * ChannelValueDelta, g * ChannelValueDelta, b * ChannelValueDelta);
                        i++;
                    }
                }
            }
            return colors;
        }

        private static void Shuffle(Color[] colors)
        {
            // Knuth-Fisher-Yates shuffle
            for (int i = colors.Length - 1; i > 0; i--)
            {
                int n = _random.Next(i + 1);
                Swap(colors, i, n);
            }
        }

        private static void Swap(Color[] colors, int index1, int index2)
        {
            var temp = colors[index1];
            colors[index1] = colors[index2];
            colors[index2] = temp;
        }

        private static Bitmap ToBitmap(Color[] pixels)
        {
            Bitmap bitmap = new Bitmap(ImageWidth, ImageHeight);
            int x = 0;
            int y = 0;
            for (int i = 0; i < PixelCount; i++)
            {
                bitmap.SetPixel(x, y, pixels[i]);
                x++;
                if (x == ImageWidth)
                {
                    x = 0;
                    y++;
                }
            }
            return bitmap;
        }

        private static int GetNeighborDelta(Color[] pixels, int index1, int index2)
        {
            return GetNeighborDelta(pixels, index1) + GetNeighborDelta(pixels, index2);
        }

        private static int GetNeighborDelta(Color[] pixels, int index)
        {
            Color center = pixels[index];
            int sum = 0;
            for (int x = 0; x < KernelWidth; x++)
            {
                for (int y = 0; y < KernelHeight; y++)
                {
                    int weight = Kernel[y, x];
                    if (weight == 0)
                    {
                        continue;
                    }

                    int xOffset = x - (KernelWidth / 2);
                    int yOffset = y - (KernelHeight / 2);
                    int i = index + xOffset + yOffset * ImageWidth;

                    if (i >= 0 && i < PixelCount)
                    {
                        sum += GetDelta(pixels[i], center) * weight;
                    }
                }
            }

            return sum;
        }

        private static int GetDelta(Color c1, Color c2)
        {
            int sum = 0;
            sum += Math.Abs(c1.R - c2.R);
            sum += Math.Abs(c1.G - c2.G);
            sum += Math.Abs(c1.B - c2.B);
            return sum;
        }

        private static bool TryRandomSwap(Color[] pixels)
        {
            int index1 = _random.Next(PixelCount);
            int index2 = _random.Next(PixelCount);

            int delta = GetNeighborDelta(pixels, index1, index2);
            Swap(pixels, index1, index2);
            int newDelta = GetNeighborDelta(pixels, index1, index2);

            if (newDelta < delta)
            {
                return true;
            }
            else
            {
                // Swap back
                Swap(pixels, index1, index2);
                return false;
            }
        }

        static void Main(string[] args)
        {
            string fileNameFormat = "{0:D10}.png";
            var image = CreateAllColors();
            ToBitmap(image).Save("start.png");
            Shuffle(image);
            ToBitmap(image).Save(string.Format(fileNameFormat, 0));

            long generation = 0;
            while (true)
            {
                bool swapped = TryRandomSwap(image);
                if (swapped)
                {
                    generation++;
                    if (generation % 1000 == 0)
                    {
                        ToBitmap(image).Save(string.Format(fileNameFormat, generation));
                    }
                }
            }
        }
    }
}

Fikir

İlk önce rastgele bir karışıklıkla başlarız:

görüntü tanımını buraya girin

Sonra rastgele iki piksel seçeriz ve değiştiririz. Bu, piksellerin komşularına olan benzerliğini arttırmazsa, geri alıp tekrar deneriz. Bu süreci tekrar tekrar tekrar ediyoruz.

Sadece birkaç kuşaktan sonra (5000) farklar o kadar açık değil ...

görüntü tanımını buraya girin

Ama daha uzun süre çalışır (25000), ...

görüntü tanımını buraya girin

... daha kesin desenler ortaya çıkmaya başlar (100000).

görüntü tanımını buraya girin

Mahalle için farklı tanımlamalar kullanarak , bu kalıpları ve kararlı olup olmadıklarını etkileyebiliriz. KernelBenzer bir matris görüntü işleme filtreleri için kullanılanlar . RGB delta hesaplaması için kullanılan her bir komşunun ağırlığını belirtir.

Sonuçlar

İşte yarattığım sonuçlardan bazıları. Videolar yinelemeli süreci gösteriyor (1 kare == 1000 kuşak), ama ne yazık ki kalite en iyisi değil (vimeo, YouTube vb. Bu küçük boyutları doğru şekilde desteklemiyor). Daha sonra daha kaliteli videolar oluşturmayı deneyebilirim.

0 1 0
1 X 1
0 1 0

185000 kuşak:

görüntü tanımını buraya girin Video (00:06)


0 0 1 0 0
0 2 3 2 0
1 3 X 3 1
0 2 3 2 0
0 0 1 0 0

243000 kuşak:

görüntü tanımını buraya girin Video (00:07)


3 0 0 0 3
0 1 0 1 0
0 0 X 0 0
0 1 0 1 0
3 0 0 0 3

230000 kuşak:

görüntü tanımını buraya girin Video (00:07)


0 0 1 0 0 0 0
0 1 2 1 0 0 0
1 2 3 X 1 0 0
0 1 2 0 0 0 0
0 0 1 0 0 0 0

Bu çekirdek ilginç çünkü asimetrisi nedeniyle desenler sabit değil ve tüm görüntüler nesiller geçtikçe sağa gidiyor.

2331000 kuşak:

görüntü tanımını buraya girin Video (01:10)


Büyük Sonuçlar (512x512)

Yukarıdaki çekirdekleri daha büyük bir görüntü boyutuyla kullanmak, daha geniş bir toplam alana yayılan aynı yerel desenleri oluşturur. 512x512 görüntü sabitlemek için 1-2 milyon nesiller sürüyor.

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin


Tamam, şimdi ciddileşelim ve 15x15 radyal çekirdeğe sahip daha büyük, daha az yerel desen oluşturalım:

0 0 0 0 0 1 1 1 1 1 0 0 0 0 0
0 0 0 1 1 2 2 2 2 2 1 1 0 0 0
0 0 1 2 2 3 3 3 3 3 2 2 1 0 0
0 1 2 2 3 4 4 4 4 4 3 2 2 1 0
0 1 2 3 4 4 5 5 5 4 4 3 2 1 0
1 2 3 4 4 5 6 6 6 5 4 4 3 2 1
1 2 3 4 5 6 7 7 7 6 5 4 3 2 1
1 2 3 4 5 6 7 X 7 6 5 4 3 2 1
1 2 3 4 5 6 7 7 7 6 5 4 3 2 1
1 2 3 4 4 5 6 6 6 5 4 4 3 2 1
0 1 2 3 4 4 5 5 5 4 4 3 2 1 0
0 1 2 2 3 4 4 4 4 4 3 2 2 1 0
0 0 1 2 2 3 3 3 3 3 2 2 1 0 0
0 0 0 1 1 2 2 2 2 2 1 1 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0

Bu, nesil başına hesaplama süresini önemli ölçüde artırır. 1.71 milyon nesiller ve 20 saat sonra:

görüntü tanımını buraya girin


1
Oraya ulaşmak biraz zaman alıyor, ancak sonuç oldukça iyi.
primo

İlginç tesadüf, ben bu aynı konuda bir makale var: nayuki.io/page/simulated-annealing-demo
Nayuki

30

Java

Diğer cevabımdaki birkaç değişiklikle, çok ilginç çıktılar elde edebiliriz.

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Quincunx
 */
public class AllColorImage {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);

        int num = 0;
        ArrayList<Point> points = new ArrayList<>();
        for (int y = 0; y < 4096; y++) {
            for (int x = 0; x < 4096; x++) {
                points.add(new Point(x, y));
            }
        }
        Collections.sort(points, new Comparator<Point>() {

            @Override
            public int compare(Point t, Point t1) {
                int compareVal = (Integer.bitCount(t.x) + Integer.bitCount(t.y))
                        - (Integer.bitCount(t1.x) + Integer.bitCount(t1.y));
                return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
            }

        });
        for (Point p : points) {
            int x = p.x;
            int y = p.y;

            img.setRGB(x, y, num);
            num++;
        }
        try {
            ImageIO.write(img, "png", new File("Filepath"));
        } catch (IOException ex) {
            Logger.getLogger(AllColorImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Önemli kod burada:

Collections.sort(points, new Comparator<Point>() {

    @Override
    public int compare(Point t, Point t1) {
        int compareVal = (Integer.bitCount(t.x) + Integer.bitCount(t.y))
                - (Integer.bitCount(t1.x) + Integer.bitCount(t1.y));
        return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
    }

});

Çıktı (ekran görüntüsü):

görüntü tanımını buraya girin

Karşılaştırıcıyı şununla değiştirin:

public int compare(Point t, Point t1) {
    int compareVal = (Integer.bitCount(t.x + t.y))
            - (Integer.bitCount(t1.x + t1.y));
    return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
}

Ve bunu anlıyoruz:

görüntü tanımını buraya girin

Başka bir varyasyon:

public int compare(Point t, Point t1) {
    int compareVal = (t.x + t.y)
            - (t1.x + t1.y);
    return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
}

görüntü tanımını buraya girin

Yine başka bir varyasyon (bana hücresel otomatları hatırlatıyor):

public int compare(Point t, Point t1) {
    int compareVal = (t1.x - t.y)
            + (t.x - t1.y);
    return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
}

görüntü tanımını buraya girin

Yine başka bir varyasyon (yeni kişisel favori):

public int compare(Point t, Point t1) {
    int compareVal = (Integer.bitCount(t.x ^ t.y))
            - (Integer.bitCount(t1.x ^ t1.y));
    return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
}

görüntü tanımını buraya girin

Çok fraktal görünüyor. XOR çok güzel, özellikle closeup:

görüntü tanımını buraya girin

Başka bir portre:

görüntü tanımını buraya girin

Ve şimdi Sierpinski Üçgeni eğik:

public int compare(Point t, Point t1) {
    int compareVal = (Integer.bitCount(t.x | t.y))
            - (Integer.bitCount(t1.x | t1.y));
    return compareVal < 0 ? -1 : compareVal == 0 ? 0 : 1;
}

görüntü tanımını buraya girin


8
İlk görüntü bir CPU ya da hafıza kalıbı fotoğrafına benziyor
Nick T

@NickT Kontrast için bir bellek ölümü (Google Görseller’e göre): files.macbidouille.com/mbv2/news/news_05_10/25-nm-die.jpg
Justin

4
Doğru, hafıza çok çok çekirdekli işlemci daha sonra muhtemelen ... öylesine biçimsiz geçerli: extremetech.com/wp-content/uploads/2012/07/Aubrey_Isle_die.jpg
Nick T

1
Bunlardan gerçekten hoşlanıyorum. Çok parlak görünümlü ama altında yatan bir organizasyon yapısı var. XOR tasarımı gibi dokunmuş bir halı istiyorum!
Jonathan Van Matre

Bunlar gerçekten harika; Bana bir arcade oyununu ya da nesneyi hatırlatıyorlar.
Jason C,

29

Java

Aslında 15 veya 18 bit renklerin nasıl oluşturulduğundan emin değildim, bu yüzden her kanalın baytının en az anlamlı bitini 2 ^ 18 farklı 24 bit renk yapmak için bıraktım. Gürültünün çoğu, sıralama yoluyla kaldırılır, ancak etkili gürültü giderme, Karşılaştırıcı'nın yaptığı gibi bir anda iki öğeden daha fazlasının karşılaştırılmasını gerektirecek gibi görünür. Daha büyük çekirdekleri kullanarak manipülasyonu deneyeceğim, ancak bu arada, bu yapabileceğimin en iyisi.

görüntü tanımını buraya girin

HD görüntü için tıklayınız # 2

Düşük çözünürlüklü görüntü # 2

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;

public class ColorSpan extends JFrame{
    private int h, w = h = 512;
    private BufferedImage image = 
            new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
    private WritableRaster raster = image.getRaster();
    private DataBufferInt dbInt = (DataBufferInt) 
            (raster.getDataBuffer());
    private int[] data = dbInt.getData();

    private JLabel imageLabel = new JLabel(new ImageIcon(image));
    private JPanel bordered = new JPanel(new BorderLayout());


    public <T> void transpose(ArrayList<T> objects){
        for(int i = 0; i < w; i++){
            for(int j = 0; j < i; j++){
                Collections.swap(objects,i+j*w,j+i*h);
            }
        }
    }

    public <T> void sortByLine(ArrayList<T> objects, Comparator<T> comp){
        for(int i = 0; i < h; i++){
            Collections.sort(objects.subList(i*w, (i+1)*w), comp);
        }
    }

    public void init(){
        ArrayList<Integer> colors = new ArrayList<Integer>();
        for(int i = 0, max = 1<<18; i < max; i++){
            int r = i>>12, g = (i>>6)&63, b = i&63;
            colors.add(((r<<16)+(g<<8)+b)<<2);
        }

        Comparator<Integer> comp1 = new Comparator<Integer>(){
            public int compare(Integer left, Integer right){
                int a = left.intValue(), b = right.intValue();

                int rA = a>>16, rB = b>>16,
                    gA = (a>>8)&255, gB = (b>>8)&255;
                /*double thA = Math.acos(gA*2d/255-1),
                        thB = Math.acos(gB*2d/255-1);*/
                double thA = Math.atan2(rA/255d-.5,gA/255d-.5),
                        thB = Math.atan2(rB/255d-.5,gB/255d-.5);
                return -Double.compare(thA,thB);
            }
        }, comp2 = new Comparator<Integer>(){
            public int compare(Integer left, Integer right){
                int a = left.intValue(), b = right.intValue();

                int rA = a>>16, rB = b>>16,
                    gA = (a>>8)&255, gB = (b>>8)&255,
                    bA = a&255, bB = b&255;
                double dA = Math.hypot(gA-rA,bA-rA),
                        dB = Math.hypot(gB-rB,bB-rB);
                return Double.compare(dA,dB);
            }
        }, comp3 = new Comparator<Integer>(){
            public int compare(Integer left, Integer right){
                int a = left.intValue(), b = right.intValue();

                int rA = a>>16, rB = b>>16,
                    gA = (a>>8)&255, gB = (b>>8)&255,
                    bA = a&255, bB = b&255;

                    return Integer.compare(rA+gA+bA,rB+gB+bB);
            }
        };

        /* Start: Image 1 */
        Collections.sort(colors, comp2);
        transpose(colors);
        sortByLine(colors,comp2);
        transpose(colors);
        sortByLine(colors,comp1);
        transpose(colors);
        sortByLine(colors,comp2);
        sortByLine(colors,comp3);
        /* End: Image 1 */

        /* Start: Image 2 */
        Collections.sort(colors, comp1);
        sortByLine(colors,comp2);

        transpose(colors);
        sortByLine(colors,comp2);
        transpose(colors);
        sortByLine(colors,comp1);
        transpose(colors);
        sortByLine(colors,comp1);
        /* End: Image 2 */

        int index = 0;
        for(Integer color : colors){
            int cInt = color.intValue();
            data[index] = cInt;
            index++;
        }

    }

    public ColorSpan(){
        super("512x512 Unique Colors");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        init();

        bordered.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
        bordered.add(imageLabel,BorderLayout.CENTER);
        add(bordered,BorderLayout.CENTER);
        pack();

    }

    public static void main(String[] args){
        new ColorSpan().setVisible(true);
    }
}

1
Bu ikincisi gerçekten 4096 x 4096 24bit sürümüne sahip olmayı hak ediyor ...
trichoplax

İmgur görüntüyü yaklaşık yarım saattir işliyor. Sanırım sıkıştırmaya çalışıyor. Neyse, bir bağlantı ekledim: SSend.it/hj4ovh
John P

2
İndirme işleminde bir sorun var.
SuperJedi224

28

Scala

Tüm renkleri bir L-System üzerinden 3-boyutlu Hilbert Curve'i yürüyerek sipariş ediyorum . Daha sonra çıktı görüntüsündeki pikselleri 2 boyutlu bir Hilbert Eğrisi boyunca yürüdüm ve tüm renkleri sırayladım.

512 x 512 çıktı:

görüntü tanımını buraya girin

İşte kod. Çoğu sadece pitch / roll / yaw ile üç boyutta hareket etmenin mantığını ve matematiğini kapsar. Eminim bu kısmı yapmanın daha iyi bir yolu vardı, ama ah, peki.

import scala.annotation.tailrec
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import java.io.File

object AllColors {

  case class Vector(val x: Int, val y: Int, val z: Int) {
    def applyTransformation(m: Matrix): Vector = {
      Vector(m.r1.x * x + m.r1.y * y + m.r1.z * z, m.r2.x * x + m.r2.y * y + m.r2.z * z, m.r3.x * x + m.r3.y * y + m.r3.z * z)
    }
    def +(v: Vector): Vector = {
      Vector(x + v.x, y + v.y, z + v.z)
    }
    def unary_-(): Vector = Vector(-x, -y, -z)
  }

  case class Heading(d: Vector, s: Vector) {
    def roll(positive: Boolean): Heading = {
      val (axis, b) = getAxis(d)
      Heading(d, s.applyTransformation(rotationAbout(axis, !(positive ^ b))))
    }

    def yaw(positive: Boolean): Heading = {
      val (axis, b) = getAxis(s)
      Heading(d.applyTransformation(rotationAbout(axis, positive ^ b)), s)
    }

    def pitch(positive: Boolean): Heading = {
      if (positive) {
        Heading(s, -d)
      } else {
        Heading(-s, d)
      }
    }

    def applyCommand(c: Char): Heading = c match {
      case '+' => yaw(true)
      case '-' => yaw(false)
      case '^' => pitch(true)
      case 'v' => pitch(false)
      case '>' => roll(true)
      case '<' => roll(false)
    }
  }

  def getAxis(v: Vector): (Char, Boolean) = v match {
    case Vector(1, 0, 0) => ('x', true)
    case Vector(-1, 0, 0) => ('x', false)
    case Vector(0, 1, 0) => ('y', true)
    case Vector(0, -1, 0) => ('y', false)
    case Vector(0, 0, 1) => ('z', true)
    case Vector(0, 0, -1) => ('z', false)
  }

  def rotationAbout(axis: Char, positive: Boolean) = (axis, positive) match {
    case ('x', true) => XP
    case ('x', false) => XN
    case ('y', true) => YP
    case ('y', false) => YN
    case ('z', true) => ZP
    case ('z', false) => ZN
  }

  case class Matrix(val r1: Vector, val r2: Vector, val r3: Vector)

  val ZP = Matrix(Vector(0,-1,0),Vector(1,0,0),Vector(0,0,1))
  val ZN = Matrix(Vector(0,1,0),Vector(-1,0,0),Vector(0,0,1))

  val XP = Matrix(Vector(1,0,0),Vector(0,0,-1),Vector(0,1,0))
  val XN = Matrix(Vector(1,0,0),Vector(0,0,1),Vector(0,-1,0))

  val YP = Matrix(Vector(0,0,1),Vector(0,1,0),Vector(-1,0,0))
  val YN = Matrix(Vector(0,0,-1),Vector(0,1,0),Vector(1,0,0))

  @tailrec def applyLSystem(current: Stream[Char], rules: Map[Char, List[Char]], iterations: Int): Stream[Char] = {
    if (iterations == 0) {
      current
    } else {
      val nextStep = current flatMap { c => rules.getOrElse(c, List(c)) }
      applyLSystem(nextStep, rules, iterations - 1)
    }
  }

  def walk(x: Vector, h: Heading, steps: Stream[Char]): Stream[Vector] = steps match {
    case Stream() => Stream(x)
    case 'f' #:: rest => x #:: walk(x + h.d, h, rest)
    case c #:: rest => walk(x, h.applyCommand(c), rest)
  }

  def hilbert3d(n: Int): Stream[Vector] = {
    val rules = Map('x' -> "^>x<f+>>x<<f>>x<<+fvxfxvf+>>x<<f>>x<<+f>x<^".toList)
    val steps = applyLSystem(Stream('x'), rules, n) filterNot (_ == 'x')
    walk(Vector(0, 0, 0), Heading(Vector(1, 0, 0), Vector(0, 1, 0)), steps)
  }

  def hilbert2d(n: Int): Stream[Vector] = {
    val rules = Map('a' -> "-bf+afa+fb-".toList, 'b' -> "+af-bfb-fa+".toList)
    val steps = applyLSystem(Stream('a'), rules, n) filterNot (c => c == 'a' || c == 'b')
    walk(Vector(0, 0, 0), Heading(Vector(1, 0, 0), Vector(0, 0, 1)), steps)
  }

  def main(args: Array[String]): Unit = {
    val n = 4
    val img = new BufferedImage(1 << (3 * n), 1 << (3 * n), BufferedImage.TYPE_INT_RGB)
    hilbert3d(n * 2).zip(hilbert2d(n * 3)) foreach { case (Vector(r,g,b), Vector(x,y,_)) => img.setRGB(x, y, (r << (24 - 2 * n)) | (g << (16 - 2 * n)) | (b << (8 - 2 * n))) }
    ImageIO.write(img, "png", new File(s"out_$n.png"))
  }
}

28

C #

Vay, bu meydan okumada gerçekten harika şeyler. Bunu C #'da bıçakladım ve Random Walk mantığı ile her bir rengi kullanarak yaklaşık 3 dakikada (i7 CPU) 4096x4096 görüntü oluşturdum.

Tamam, kod için. Saatlerce süren araştırmalarla uğraştıktan ve koddaki döngüler için her bir HSL rengini oluşturmaya çalıştıktan sonra, HSL renklerini okumak için düz bir dosya oluşturmaya karar verdim. Yaptığım her RGB rengini bir Listede oluşturmaktı, sonra Hue, Luminosity, ardından Saturation tarafından sipariş ettim. Sonra Listeyi bir metin dosyasına kaydettim. ColorData, yazdığım bir RGB rengini kabul eden ve aynı zamanda HSL eşdeğeri depolayan küçük bir sınıftır. Bu kod BÜYÜK RAM yiyicidir. Yaklaşık 4GB RAM lol kullanılır.

public class RGB
{
    public double R = 0;
    public double G = 0;
    public double B = 0;
    public override string ToString()
    {
        return "RGB:{" + (int)R + "," + (int)G + "," + (int)B + "}";
    }
}
public class HSL
{
    public double H = 0;
    public double S = 0;
    public double L = 0;
    public override string ToString()
    {
        return "HSL:{" + H + "," + S + "," + L + "}";
    }
}
public class ColorData
{
    public RGB rgb;
    public HSL hsl;
    public ColorData(RGB _rgb)
    {
        rgb = _rgb;
        var _hsl = ColorHelper._color_rgb2hsl(new double[]{rgb.R,rgb.G,rgb.B});
        hsl = new HSL() { H = _hsl[0], S = _hsl[1], L = _hsl[2] };
    }
    public ColorData(double[] _rgb)
    {
        rgb = new RGB() { R = _rgb[0], G = _rgb[1], B = _rgb[2] };
        var _hsl = ColorHelper._color_rgb2hsl(_rgb);
        hsl = new HSL() { H = _hsl[0], S = _hsl[1], L = _hsl[2] };
    }
    public override string ToString()
    {
        return rgb.ToString() + "|" + hsl.ToString();
    }
    public int Compare(ColorData cd)
    {
        if (this.hsl.H > cd.hsl.H)
        {
            return 1;
        }
        if (this.hsl.H < cd.hsl.H)
        {
            return -1;
        }

        if (this.hsl.S > cd.hsl.S)
        {
            return 1;
        }
        if (this.hsl.S < cd.hsl.S)
        {
            return -1;
        }

        if (this.hsl.L > cd.hsl.L)
        {
            return 1;
        }
        if (this.hsl.L < cd.hsl.L)
        {
            return -1;
        }
        return 0;
    }
}
public static class ColorHelper
{


    public static void MakeColorFile(string savePath)
    {
        List<ColorData> Colors = new List<ColorData>();
        System.IO.File.Delete(savePath);

        for (int r = 0; r < 256; r++)
        {
            for (int g = 0; g < 256; g++)
            {
                for (int b = 0; b < 256; b++)
                {
                    double[] rgb = new double[] { r, g, b };
                    ColorData cd = new ColorData(rgb);
                    Colors.Add(cd);
                }
            }
        }
        Colors = Colors.OrderBy(x => x.hsl.H).ThenBy(x => x.hsl.L).ThenBy(x => x.hsl.S).ToList();

        string cS = "";
        using (System.IO.StreamWriter fs = new System.IO.StreamWriter(savePath))
        {

            foreach (var cd in Colors)
            {
                cS = cd.ToString();
                fs.WriteLine(cS);
            }
        }
    }


    public static IEnumerable<Color> NextColorHThenSThenL()
    {
        HashSet<string> used = new HashSet<string>();
        double rMax = 720;
        double gMax = 700;
        double bMax = 700;
        for (double r = 0; r <= rMax; r++)
        {
            for (double g = 0; g <= gMax; g++)
            {
                for (double b = 0; b <= bMax; b++)
                {
                    double h = (r / (double)rMax);
                    double s = (g / (double)gMax);
                    double l = (b / (double)bMax);
                    var c = _color_hsl2rgb(new double[] { h, s, l });
                    Color col = Color.FromArgb((int)c[0], (int)c[1], (int)c[2]);
                    string key = col.R + "-" + col.G + "-" + col.B;
                    if (!used.Contains(key))
                    {
                        used.Add(key);
                        yield return col;
                    }
                    else
                    {
                        continue;
                    }
                }
            }
        }
    }

    public static Color HSL2RGB(double h, double s, double l){
        double[] rgb= _color_hsl2rgb(new double[] { h, s, l });
        return Color.FromArgb((int)rgb[0], (int)rgb[1], (int)rgb[2]);
    }
    public static double[] _color_rgb2hsl(double[] rgb)
    {
        double r = rgb[0]; double g = rgb[1]; double b = rgb[2];
        double min = Math.Min(r, Math.Min(g, b));
        double max = Math.Max(r, Math.Max(g, b));
        double delta = max - min;
        double l = (min + max) / 2.0;
        double s = 0;
        if (l > 0 && l < 1)
        {
            s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
        }
        double h = 0;
        if (delta > 0)
        {
            if (max == r && max != g) h += (g - b) / delta;
            if (max == g && max != b) h += (2 + (b - r) / delta);
            if (max == b && max != r) h += (4 + (r - g) / delta);
            h /= 6;
        } return new double[] { h, s, l };
    }


    public static double[] _color_hsl2rgb(double[] hsl)
    {
        double h = hsl[0];
        double s = hsl[1];
        double l = hsl[2];
        double m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
        double m1 = l * 2 - m2;
        return new double[]{255*_color_hue2rgb(m1, m2, h + 0.33333),
           255*_color_hue2rgb(m1, m2, h),
           255*_color_hue2rgb(m1, m2, h - 0.33333)};
    }


    public static double _color_hue2rgb(double m1, double m2, double h)
    {
        h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
        if (h * (double)6 < 1) return m1 + (m2 - m1) * h * (double)6;
        if (h * (double)2 < 1) return m2;
        if (h * (double)3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * (double)6;
        return m1;
    }


}

Bunun dışında. Oluşturulan dosyadan bir sonraki rengi almak için bir sınıf yazdım. Renk tonu başlangıcını ve renk tonunu ayarlamanızı sağlar. Gerçekte, dosya ilk önce hangi boyutta olursa olsun genelleştirilebilir ve genelleştirilmelidir. Ayrıca burada performans artışı için, RGB değerlerini dosyaya ekleyip her satırı sabit bir uzunlukta tutabileceğimin farkındayım. Bu şekilde, başlatmak istediğim çizgiye ulaşana kadar her çizgiden döngü yapmak yerine bayt ofsetini kolayca belirleyebilirdim. Ama bu benim için çok fazla bir performans değildi. Ama işte o sınıf

public class HSLGenerator
{

    double hEnd = 1;
    double hStart = 0;

    double colCount = 256 * 256 * 256;

    public static Color ReadRGBColorFromLine(string line)
    {
        string sp1 = line.Split(new string[] { "RGB:{" }, StringSplitOptions.None)[1];
        string sp2 = sp1.Split('}')[0];
        string[] sp3 = sp2.Split(',');
        return Color.FromArgb(Convert.ToInt32(sp3[0]), Convert.ToInt32(sp3[1]), Convert.ToInt32(sp3[2]));
    }
    public IEnumerable<Color> GetNextFromFile(string colorFile)
    {
        int currentLine = -1;
        int startLine = Convert.ToInt32(hStart * colCount);
        int endLine = Convert.ToInt32(hEnd * colCount);
        string line = "";
        using(System.IO.StreamReader sr = new System.IO.StreamReader(colorFile))
        {

            while (!sr.EndOfStream)
            {
                line = sr.ReadLine();
                currentLine++;
                if (currentLine < startLine) //begin at correct offset
                {
                    continue;
                }
                yield return ReadRGBColorFromLine(line);
                if (currentLine > endLine) 
                {
                    break;
                }
            }
    }

    HashSet<string> used = new HashSet<string>();

    public void SetHueLimits(double hueStart, double hueEnd)
    {
        hEnd = hueEnd;
        hStart = hueStart;
    }
}

Şimdi renkli dosyaya sahibiz ve dosyayı okuyacak bir yolumuz var, şimdi görüntüyü yapabiliriz. LockBitmap adlı bir bitmap'te piksellerin ayar performansını artırmak için bulduğum bir sınıfı kullandım. LockBitmap kaynağı

Koordinat konumlarını depolamak için küçük bir Vector2 sınıfı oluşturdum

public class Vector2
{
    public int X = 0;
    public int Y = 0;
    public Vector2(int x, int y)
    {
        X = x;
        Y = y;
    }
    public Vector2 Center()
    {
        return new Vector2(X / 2, Y / 2);
    }
    public override string ToString()
    {
        return X.ToString() + "-" + Y.ToString();
    }
}

Ayrıca, komşu pikselleri bulmak için yardımcı olan SearchArea adlı bir sınıf oluşturdum. Komşularını bulmak istediğiniz pikseli, aranacak sınırları ve aranacak "komşu karenin" boyutunu belirlersiniz. Öyleyse boyut 3 ise, ortada belirtilen pikseli içeren 3x3 kare aradığınız anlamına gelir.

public class SearchArea
{
    public int Size = 0;
    public Vector2 Center;
    public Rectangle Bounds;

    public SearchArea(int size, Vector2 center, Rectangle bounds)
    {
        Center = center;
        Size = size;
        Bounds = bounds;
    }
    public bool IsCoordinateInBounds(int x, int y)
    {
        if (!IsXValueInBounds(x)) { return false; }
        if (!IsYValueInBounds(y)) { return false; }
        return true;

    }
    public bool IsXValueInBounds(int x)
    {
        if (x < Bounds.Left || x >= Bounds.Right) { return false; }
        return true;
    }
    public bool IsYValueInBounds(int y)
    {
        if (y < Bounds.Top || y >= Bounds.Bottom) { return false; }
        return true;
    }

}

İşte aslında bir sonraki komşuyu seçen sınıf. Temelde 2 arama modu var. A) Tam kare, B) karenin sadece çevresi. Bu, karenin dolu olduğunu fark ettikten sonra tekrar tam kareyi aramayı önlemek için yaptığım bir optimizasyon oldu. DepthMap, aynı kareleri tekrar tekrar aramayı önlemek için başka bir optimizasyondu. Ancak, bunu tamamen optimize etmedim. GetNeighbors'a yapılan her çağrı ilk önce tam kare aramayı yapacaktır. İlk tam kareyi tamamladıktan sonra sadece çevre araması yapmak için bunu optimize edebileceğimi biliyorum. Henüz bu optimizasyona ulaşamadım ve hatta onsuz kod oldukça hızlı. Yorumlanan "kilitleme" satırları bir noktada Parallel.ForEach kullanıyordum, ancak bu lol için istediğimden daha fazla kod yazmam gerektiğinden kaynaklanıyor.

public class RandomWalkGenerator
{
    HashSet<string> Visited = new HashSet<string>();
    Dictionary<string, int> DepthMap = new Dictionary<string, int>();
    Rectangle Bounds;
    Random rnd = new Random();
    public int DefaultSearchSize = 3;
    public RandomWalkGenerator(Rectangle bounds)
    {
        Bounds = bounds;
    }
    private SearchArea GetSearchArea(Vector2 center, int size)
    {
        return new SearchArea(size, center, Bounds);
    }

    private List<Vector2> GetNeighborsFullSearch(SearchArea srchArea, Vector2 coord)
    {
        int radius = (int)Math.Floor((double)((double)srchArea.Size / (double)2));
        List<Vector2> pixels = new List<Vector2>();
        for (int rX = -radius; rX <= radius; rX++)
        {
            for (int rY = -radius; rY <= radius; rY++)
            {
                if (rX == 0 && rY == 0) { continue; } //not a new coordinate
                int x = rX + coord.X;
                int y = rY + coord.Y;
                if (!srchArea.IsCoordinateInBounds(x, y)) { continue; }
                var key = x + "-" + y;
                // lock (Visited)
                {
                    if (!Visited.Contains(key))
                    {
                        pixels.Add(new Vector2(x, y));
                    }
                }
            }
        }
        if (pixels.Count == 0)
        {
            int depth = 0;
            string vecKey = coord.ToString();
            if (!DepthMap.ContainsKey(vecKey))
            {
                DepthMap.Add(vecKey, depth);
            }
            else
            {
                depth = DepthMap[vecKey];
            }

            var size = DefaultSearchSize + 2 * depth;
            var sA = GetSearchArea(coord, size);
            pixels = GetNeighborsPerimeterSearch(sA, coord, depth);
        }
        return pixels;
    }
    private Rectangle GetBoundsForPerimeterSearch(SearchArea srchArea, Vector2 coord)
    {
        int radius = (int)Math.Floor((decimal)(srchArea.Size / 2));
        Rectangle r = new Rectangle(-radius + coord.X, -radius + coord.Y, srchArea.Size, srchArea.Size);
        return r;
    }
    private List<Vector2> GetNeighborsPerimeterSearch(SearchArea srchArea, Vector2 coord, int depth = 0)
    {
        string vecKey = coord.ToString();
        if (!DepthMap.ContainsKey(vecKey))
        {
            DepthMap.Add(vecKey, depth);
        }
        else
        {
            DepthMap[vecKey] = depth;
        }
        Rectangle bounds = GetBoundsForPerimeterSearch(srchArea, coord);
        List<Vector2> pixels = new List<Vector2>();
        int depthMax = 1500;

        if (depth > depthMax)
        {
            return pixels;
        }

        int yTop = bounds.Top;
        int yBot = bounds.Bottom;

        //left to right scan
        for (int x = bounds.Left; x < bounds.Right; x++)
        {

            if (srchArea.IsCoordinateInBounds(x, yTop))
            {
                var key = x + "-" + yTop;
                // lock (Visited)
                {
                    if (!Visited.Contains(key))
                    {
                        pixels.Add(new Vector2(x, yTop));
                    }
                }
            }
            if (srchArea.IsCoordinateInBounds(x, yBot))
            {
                var key = x + "-" + yBot;
                // lock (Visited)
                {
                    if (!Visited.Contains(key))
                    {
                        pixels.Add(new Vector2(x, yBot));
                    }
                }
            }
        }

        int xLeft = bounds.Left;
        int xRight = bounds.Right;
        int yMin = bounds.Top + 1;
        int yMax = bounds.Bottom - 1;
        //top to bottom scan
        for (int y = yMin; y < yMax; y++)
        {
            if (srchArea.IsCoordinateInBounds(xLeft, y))
            {
                var key = xLeft + "-" + y;
                // lock (Visited)
                {
                    if (!Visited.Contains(key))
                    {
                        pixels.Add(new Vector2(xLeft, y));
                    }
                }
            }
            if (srchArea.IsCoordinateInBounds(xRight, y))
            {
                var key = xRight + "-" + y;
                // lock (Visited)
                {
                    if (!Visited.Contains(key))
                    {
                        pixels.Add(new Vector2(xRight, y));
                    }
                }
            }
        }

        if (pixels.Count == 0)
        {
            var size = srchArea.Size + 2;
            var sA = GetSearchArea(coord, size);
            pixels = GetNeighborsPerimeterSearch(sA, coord, depth + 1);
        }
        return pixels;
    }
    private List<Vector2> GetNeighbors(SearchArea srchArea, Vector2 coord)
    {
        return GetNeighborsFullSearch(srchArea, coord);
    }
    public Vector2 ChooseNextNeighbor(Vector2 coord)
    {
        SearchArea sA = GetSearchArea(coord, DefaultSearchSize);
        List<Vector2> neighbors = GetNeighbors(sA, coord);
        if (neighbors.Count == 0)
        {
            return null;
        }
        int idx = rnd.Next(0, neighbors.Count);
        Vector2 elm = neighbors.ElementAt(idx);
        string key = elm.ToString();
        // lock (Visited)
        {
            Visited.Add(key);
        }
        return elm;
    }
}

Tamam, harika, işte şimdi görüntüyü oluşturan sınıf.

public class RandomWalk
{
    Rectangle Bounds;
    Vector2 StartPath = new Vector2(0, 0);
    LockBitmap LockMap;
    RandomWalkGenerator rwg;
    public int RandomWalkSegments = 1;
    string colorFile = "";

    public RandomWalk(int size, string _colorFile)
    {
        colorFile = _colorFile;
        Bounds = new Rectangle(0, 0, size, size);
        rwg = new RandomWalkGenerator(Bounds);
    }
    private void Reset()
    {
        rwg = new RandomWalkGenerator(Bounds);
    }
    public void CreateImage(string savePath)
    {
        Reset();
        Bitmap bmp = new Bitmap(Bounds.Width, Bounds.Height);
        LockMap = new LockBitmap(bmp);
        LockMap.LockBits();
        if (RandomWalkSegments == 1)
        {
            RandomWalkSingle();
        }
        else
        {
            RandomWalkMulti(RandomWalkSegments);
        }
        LockMap.UnlockBits();
        bmp.Save(savePath);

    }
    public void SetStartPath(int X, int Y)
    {
        StartPath.X = X;
        StartPath.Y = Y;
    }
    private void RandomWalkMulti(int buckets)
    {

        int Buckets = buckets;
        int PathsPerSide = (Buckets + 4) / 4;
        List<Vector2> Positions = new List<Vector2>();

        var w = Bounds.Width;
        var h = Bounds.Height;
        var wInc = w / Math.Max((PathsPerSide - 1),1);
        var hInc = h / Math.Max((PathsPerSide - 1),1);

        //top
        for (int i = 0; i < PathsPerSide; i++)
        {
            var x = Math.Min(Bounds.Left + wInc * i, Bounds.Right - 1);
            Positions.Add(new Vector2(x, Bounds.Top));
        }
        //bottom
        for (int i = 0; i < PathsPerSide; i++)
        {
            var x = Math.Max(Bounds.Right -1 - wInc * i, 0);
            Positions.Add(new Vector2(x, Bounds.Bottom - 1));
        }
        //right and left
        for (int i = 1; i < PathsPerSide - 1; i++)
        {
            var y = Math.Min(Bounds.Top + hInc * i, Bounds.Bottom - 1);
            Positions.Add(new Vector2(Bounds.Left, y));
            Positions.Add(new Vector2(Bounds.Right - 1, y));
        }
        Positions = Positions.OrderBy(x => Math.Atan2(x.X, x.Y)).ToList();
        double cnt = 0;
        List<IEnumerator<bool>> _execs = new List<IEnumerator<bool>>();
        foreach (Vector2 startPath in Positions)
        {
            double pct = cnt / (Positions.Count);
            double pctNext = (cnt + 1) / (Positions.Count);

            var enumer = RandomWalkHueSegment(pct, pctNext, startPath).GetEnumerator();

            _execs.Add(enumer);
            cnt++;
        }

        bool hadChange = true;
        while (hadChange)
        {
            hadChange = false;
            foreach (var e in _execs)
            {
                if (e.MoveNext())
                {
                    hadChange = true;
                }
            }
        }

    }
    private IEnumerable<bool> RandomWalkHueSegment(double hueStart, double hueEnd, Vector2 startPath)
    {
        var colors = new HSLGenerator();
        colors.SetHueLimits(hueStart, hueEnd);
        var colorFileEnum = colors.GetNextFromFile(colorFile).GetEnumerator();
        Vector2 coord = new Vector2(startPath.X, startPath.Y);
        LockMap.SetPixel(coord.X, coord.Y, ColorHelper.HSL2RGB(0, 0, 0));

        while (true)
        {
            if (!colorFileEnum.MoveNext())
            {
                break;
            }
            var rgb = colorFileEnum.Current;
            coord = ChooseNextNeighbor(coord);
            if (coord == null)
            {
                break;
            }
            LockMap.SetPixel(coord.X, coord.Y, rgb);
            yield return true;

        }
    }
    private void RandomWalkSingle()
    {
        Vector2 coord = new Vector2(StartPath.X, StartPath.Y);
        LockMap.SetPixel(coord.X, coord.Y, ColorHelper.HSL2RGB(0, 0, 0));
        int cnt = 1;
        var colors = new HSLGenerator();
        var colorFileEnum = colors.GetNextFromFile(colorFile).GetEnumerator();
        while (true)
        {
            if (!colorFileEnum.MoveNext())
            {
                return;
            }
            var rgb = colorFileEnum.Current;
            var newCoord = ChooseNextNeighbor(coord);
            coord = newCoord;
            if (newCoord == null)
            {
                return;
            }
            LockMap.SetPixel(newCoord.X, newCoord.Y, rgb);
            cnt++;

        }

    }

    private Vector2 ChooseNextNeighbor(Vector2 coord)
    {
        return rwg.ChooseNextNeighbor(coord);
    }


}

Ve işte örnek bir uygulama:

class Program
{
    static void Main(string[] args)
    {
        {
           // ColorHelper.MakeColorFile();
          //  return;
        }
        string colorFile = "colors.txt";
        var size = new Vector2(1000,1000);
        var ctr = size.Center();
        RandomWalk r = new RandomWalk(size.X,colorFile);
        r.RandomWalkSegments = 8;
        r.SetStartPath(ctr.X, ctr.Y);
        r.CreateImage("test.bmp");

    }
}

Eğer RandomWalkSegments = 1 ise, temelde sadece söylediğiniz yere yürümeye başlar ve dosyadaki ilk renkten başlar.

Kabul edeceğim en temiz kod değil, ama oldukça hızlı çalışıyor!

Kırpılmış çıkış

3 Yol

128 Yol

DÜZENLE:

Bu yüzden OpenGL ve Shader'ları öğrendim. GPU'da hızlı bir şekilde yanan her renkteki 2 basit gölgelendirici komut dosyası kullanılarak bir 4096x4096 ürettim. Çıktı sıkıcı, ama birisinin bunu ilginç bulabileceğini ve güzel fikirler bulabileceğini düşündüm:

Vertex Shader

attribute vec3 a_position;
varying vec2 vTexCoord;
   void main() {
      vTexCoord = (a_position.xy + 1) / 2;
      gl_Position = vec4(a_position, 1);
  }

Frag Shader

void main(void){
    int num = int(gl_FragCoord.x*4096.0 + gl_FragCoord.y);
    int h = num % 256;
    int s = (num/256) % 256;
    int l = ((num/256)/256) % 256;
    vec4 hsl = vec4(h/255.0,s/255.0,l/255.0,1.0);
    gl_FragColor = hsl_to_rgb(hsl); // you need to implement a conversion method
}

Düzenleme (10/15/16): Sadece genetik algoritma kavramının bir kanıtını göstermek istedim. Bu kodu 24 saat sonra 100x100 rastgele renk grubuyla çalıştırıyorum, ancak şimdiye kadar çıktı çok güzel!görüntü tanımını buraya girin

Düzenleme (10/26/16): Şimdilik genetik algoritma kodunu 12 gündür çalıştırıyorum .. ve hala çıktıları optimize ediyor. Temel olarak bazı yerel asgariye yakınsadı, ancak görünüşe göre hala daha fazla gelişme kaydediyor:görüntü tanımını buraya girin

Düzenleme: 8/12/17 - Yeni bir rastgele yürüyüş algoritması yazdım - temelde bir dizi "yürüyüşçü" belirlersiniz, ancak rastgele yürümek yerine - rastgele başka bir yürüteç seçer ve bunlardan kaçınırlar (en uzaktaki bir sonraki pikseli seçer) ) - veya onlara doğru yürüyün (onlara en yakın olan sonraki pikseli seçin). Örnek bir gri tonlama çıktısı burada (Renklendirmeyi bağladıktan sonra tam bir 4096x4096 renkli render yapacağım!):görüntü tanımını buraya girin


4
Biraz gecikmiş, ama PPCG'ye hoş geldiniz! Bu mükemmel bir ilk yazı.
Bir spaghetto

1
Teşekkür ederim! Daha fazla zorluğu tamamlamayı dört gözle bekliyorum! Son zamanlarda daha fazla görüntü kodlama işi yapıyorum, bu benim yeni hobim
applejacks01

Vay bunlar harika; Bugün bu yazıya geri döndüğüm ve sonraki tüm işleri kontrol ettiğim için memnunum.
Jason C,

Teşekkür ederim! Aslında ilginç degradeler üretmek için şimdi kodlayan bazı genetik algoritmalar yapıyorum. Temel olarak 100x100 ızgara oluşturan 10000 renk al. Her piksel için komşu pikselleri alın. Her biri için CIEDE2000 mesafesini alın. Topla şunu. Tüm 10000 piksel için topla. Genetik algoritma bu toplam toplamı azaltmaya çalışır. Yavaş, ama 20x20 görüntü için çıktısı gerçekten ilginç
applejacks01

Ben özellikle bu çözümün çıktısını seviyorum.
r_alex_hall

22

HTML5 tuval + JavaScript

Buna randoGraph diyorum ve burada istediğiniz kadar yaratabilirsiniz

Bazı örnekler:

örnek 1

örnek 2

örnek 3

örnek 4

örnek 5

örnek 6

örnek 7

Örneğin, Firefox'ta tuval üzerine sağ tıkladığınızda (bittiğinde) ve resim olarak kaydedebilirsiniz. 4096x4096 görüntü üretmek, bazı tarayıcıların bellek limiti nedeniyle bir tür problemdir.

Fikir oldukça basit ama her görüntü benzersiz. İlk önce renk paletini yaratıyoruz. Daha sonra, X noktalarından başlayarak paletteki rasgele renkleri seçer ve bunlar için konumlar seçeriz (her seferinde palette sildiğimiz bir rengi seçeriz) ve bir sonraki piksele aynı pozisyona koymamak için nereye koyduğumuzu kaydederiz.

Buna teğet olan her piksel için olası renklerden bir sayı (X) yaratırız ve sonra o piksele en uygun olanı seçeriz. Bu, görüntü tamamlanana kadar devam eder.

HTML kodu

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="el">
<head>
<script type="text/javascript" src="randoGraph.js"></script>
</head>
<body>
    <canvas id="randoGraphCanvas"></canvas> 
</body>
</html>

Ve randoGraph.js için JavaScript

window.onload=function(){
    randoGraphInstance = new randoGraph("randoGraphCanvas",256,128,1,1);
    randoGraphInstance.setRandomness(500, 0.30, 0.11, 0.59);
    randoGraphInstance.setProccesses(10);
    randoGraphInstance.init(); 
}

function randoGraph(canvasId,width,height,delay,startings)
{
    this.pixels = new Array();
    this.colors = new Array(); 
    this.timeouts = new Array(); 
    this.randomFactor = 500;
    this.redFactor = 0.30;
    this.blueFactor = 0.11;
    this.greenFactor  = 0.59;
    this.processes = 1;
    this.canvas = document.getElementById(canvasId); 
    this.pixelsIn = new Array(); 
    this.stopped = false;

    this.canvas.width = width;
    this.canvas.height = height;
    this.context = this.canvas.getContext("2d");
    this.context.clearRect(0,0, width-1 , height-1);
    this.shadesPerColor = Math.pow(width * height, 1/3);
    this.shadesPerColor = Math.round(this.shadesPerColor * 1000) / 1000;

    this.setRandomness = function(randomFactor,redFactor,blueFactor,greenFactor)
    {
        this.randomFactor = randomFactor;
        this.redFactor = redFactor;
        this.blueFactor = blueFactor;
        this.greenFactor = greenFactor;
    }

    this.setProccesses = function(processes)
    {
        this.processes = processes;
    }

    this.init = function()
    {
        if(this.shadesPerColor > 256 || this.shadesPerColor % 1 > 0) 
        { 
            alert("The dimensions of the image requested to generate are invalid. The product of width multiplied by height must be a cube root of a integer number up to 256."); 
        }
        else 
        {
            var steps = 256 / this.shadesPerColor;
            for(red = steps / 2; red <= 255;)
            {
                for(blue = steps / 2; blue <= 255;)
                {
                    for(green = steps / 2; green <= 255;)
                    {   
                        this.colors.push(new Color(Math.round(red),Math.round(blue),Math.round(green)));
                        green = green + steps;
                    }
                    blue = blue + steps; 
                }
                red = red + steps; 
            }   

            for(var i = 0; i < startings; i++)
            {
                var color = this.colors.splice(randInt(0,this.colors.length - 1),1)[0];
                var pixel = new Pixel(randInt(0,width - 1),randInt(0,height - 1),color);
                this.addPixel(pixel);       
            }

            for(var i = 0; i < this.processes; i++)
            {
                this.timeouts.push(null);
                this.proceed(i);
            }
        }
    }

    this.proceed = function(index) 
    { 
        if(this.pixels.length > 0)
        {
            this.proceedPixel(this.pixels.splice(randInt(0,this.pixels.length - 1),1)[0]);
            this.timeouts[index] = setTimeout(function(that){ if(!that.stopped) { that.proceed(); } },this.delay,this);
        }
    }

    this.proceedPixel = function(pixel)
    {
        for(var nx = pixel.getX() - 1; nx < pixel.getX() + 2; nx++)
        {
            for(var ny = pixel.getY() - 1; ny < pixel.getY() + 2; ny++)
            {
                if(! (this.pixelsIn[nx + "x" + ny] == 1 || ny < 0 || nx < 0 || nx > width - 1 || ny > height - 1 || (nx == pixel.getX() && ny == pixel.getY())) )
                {
                    var color = this.selectRelevantColor(pixel.getColor());
                    var newPixel = new Pixel(nx,ny,color);
                    this.addPixel(newPixel);
                }
            }
        }   
    }

    this.selectRelevantColor = function(color)
    {
        var relevancies = new Array(); 
        var relColors = new Array(); 
        for(var i = 0; i < this.randomFactor && i < this.colors.length; i++)
        {
            var index = randInt(0,this.colors.length - 1);
            var c = this.colors[index];
            var relevancy = Math.pow( ((c.getRed()-color.getRed()) * this.redFactor) , 2)
            + Math.pow( ((c.getBlue()-color.getBlue()) * this.blueFactor), 2)
            + Math.pow( ((c.getGreen()-color.getGreen()) * this.greenFactor) , 2);
            relevancies.push(relevancy); 
            relColors[relevancy+"Color"] = index;
        }
        return this.colors.splice(relColors[relevancies.min()+"Color"],1)[0]
    }

    this.addPixel = function(pixel)
    {
        this.pixels.push(pixel);
        this.pixelsIn[pixel.getX() + "x" + pixel.getY() ] = 1;
        var color = pixel.getColor();
        this.context.fillStyle = "rgb("+color.getRed()+","+color.getBlue()+","+color.getGreen()+")";
        this.context.fillRect( pixel.getX(), pixel.getY(), 1, 1);   
    }

    var toHex = function toHex(num) 
    {
        num = Math.round(num);
        var hex = num.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    }

    this.clear = function()
    {
        this.stopped = true;
    }
}

function Color(red,blue,green)
{   
    this.getRed = function() { return red; } 
    this.getBlue = function() { return blue; } 
    this.getGreen = function() { return green; } 
}

function Pixel(x,y,color)
{   
    this.getX = function() { return x; } 
    this.getY = function() { return y; } 
    this.getColor = function() { return color; } 
}


function randInt(min, max) 
{
    return Math.floor(Math.random() * (max - min + 1)) + min;
}


// @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
Array.prototype.min = function() 
{
      return Math.min.apply(null, this);
};

// @see http://stackoverflow.com/questions/5223/length-of-javascript-object-ie-associative-array
Object.size = function(obj) 
{
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

Çok hoş ama fejesjoco'nun C # cevabı gibi görünüyor . Sadece şans eseri mi?
AL,

1
Algoritmalar burada ve herkes gerçekten farklı olduğunu okuyabilir ve anlayabilir. Fejesjoco tarafından C # cevabından sonra yayınlanan bu cevap, sonucunun ne kadar iyi olduğunu motive eden kazanan ilan etti. Sonra komşu renklerin işlenmesi ve seçilmesi konusunda tamamen farklı bir yaklaşım düşündüm ve bu kadar. Elbette, her iki cevap da aynı temele sahiptir, görünür spektrum boyunca kullanılan renklerin eşit dağılımı, ilgili renkler kavramı ve başlangıç ​​noktaları, belki de bu temeli düşüren biri, bazı durumlarda üretilen görüntülerin benzerlik gösterebileceğini düşünebilir.
konstantinosX

Tamam, cevabınızı eleştirdiğimi düşünüyorsanız, üzgünüm. Sadece ortaya çıkan çıktı benzer göründüğü için fejesjoco'nun cevabından ilham alıp almadığınızı merak ettim.
AL,

1
“Söz konusu sınıf birkaç kez kullanılıyorsa prototip zincirini kullanmak yerine yapıcı içindeki bir sınıfın yöntemlerini tanımlamak gerçekten verimsiz” diyor Patrick Roberts. Bunu doğrulayan bir örneğiniz var mı? İçtenlikle bu iddianın herhangi bir temeli olup olmadığını (bunu kullanmayı bırakmak için) ve ne olduğunu bilmek istiyorum.
konstantinosX

2
Prototip kullanımıyla ilgili olarak: statik bir yöntemin yapacağı gibi çalışır. Nesne değişmezinde tanımlanmış bir işleve sahip olduğunuzda, yarattığınız her yeni nesnenin, işlevin yeni bir kopyasını da oluşturması ve bunları bu nesne örneğiyle birlikte saklaması gerekir (yani 16 milyon renkli nesne, aynı işlevin 16 milyon kopyası anlamına gelir). hafıza). Karşılaştırma yapmak gerekirse, prototip kullanmak, nesneyi değil de "sınıf" ile ilişkilendirilmek için yalnızca bir kez oluşturur. Bu, belirgin bellek avantajlarının yanı sıra potansiyel hız avantajlarına da sahiptir.
Mwr247

20

piton

İşte işte python'daki çözümüm, bir tane yapmak neredeyse bir saat sürüyor, bu yüzden muhtemelen yapılması gereken bazı optimizasyonlar var:

import PIL.Image as Image
from random import shuffle
import math

def mulColor(color, factor):
    return (int(color[0]*factor), int(color[1]*factor), int(color[2]*factor))

def makeAllColors(arg):
    colors = []
    for r in range(0, arg):
        for g in range(0, arg):
            for b in range(0, arg):
                colors.append((r, g, b))
    return colors

def distance(color1, color2):
    return math.sqrt(pow(color2[0]-color1[0], 2) + pow(color2[1]-color1[1], 2) + pow(color2[2]-color1[2], 2))

def getClosestColor(to, colors):
    closestColor = colors[0]
    d = distance(to, closestColor)
    for color in colors:
        if distance(to, color) < d:
            closestColor = color
            d = distance(to, closestColor)
    return closestColor

imgsize = (256, 128)
#imgsize = (10, 10)
colors = makeAllColors(32)
shuffle(colors)
factor = 255.0/32.0
img = Image.new("RGB", imgsize, "white")
#start = (imgsize[0]/4, imgsize[1]/4)
start = (imgsize[0]/2, 0)
startColor = colors.pop()
img.putpixel(start, mulColor(startColor, factor))

#color = getClosestColor(startColor, colors)
#img.putpixel((start[0]+1, start[1]), mulColor(color, factor))

edgePixels = [(start, startColor)]
donePositions = [start]
for pixel in edgePixels:
    if len(colors) > 0:
        color = getClosestColor(pixel[1], colors)
    m = [(pixel[0][0]-1, pixel[0][1]), (pixel[0][0]+1, pixel[0][2]), (pixel[0][0], pixel[0][3]-1), (pixel[0][0], pixel[0][4]+1)]
    if len(donePositions) >= imgsize[0]*imgsize[1]:
    #if len(donePositions) >= 100:
        break
    for pos in m:
        if (not pos in donePositions):
            if not (pos[0]<0 or pos[1]<0 or pos[0]>=img.size[0] or pos[1]>=img.size[1]):
                img.putpixel(pos, mulColor(color, factor))
                #print(color)
                donePositions.append(pos)
                edgePixels.append((pos, color))
                colors.remove(color)
                if len(colors) > 0:
                    color = getClosestColor(pixel[1], colors)
    print((len(donePositions) * 1.0) / (imgsize[0]*imgsize[1]))
print len(donePositions)
img.save("colors.png")

İşte bazı örnek çıktılar:

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin


1
Bazı çılgın ses dalga formlarına benziyor
Mark Jeronimus

19

Java

Bu zorluğu denemeye karar verdim. Bu cevaptan başka bir kod golfüne ilham aldım . Programım çirkin görüntüler oluşturuyor, ancak hepsi renkli.

Ayrıca, ilk kez kod golf. :)

(4k görüntüler küçük yükleme hızım için çok büyüktü, bir tane yüklemeyi denedim, ancak bir saat sonra yüklenmedi. Kendikini oluşturabilirsin.)

Kapatmak:

Makinemde 70 saniyede bir görüntü oluşturuyor, oluştururken yaklaşık 1,5 GB bellek alıyor

Main.java

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;

import javax.imageio.ImageIO;


public class Main {
    static char[][] colors = new char[4096 * 4096][3];
    static short[][] pixels = new short[4096 * 4096][2];

    static short[][] iterMap = new short[4096][4096];  

    public static int mandel(double re0, double im0, int MAX_ITERS) {
        double re = re0;
        double im = im0;
        double _r;
        double _i;
        double re2;
        double im2;
        for (int iters = 0; iters < MAX_ITERS; iters++) {
            re2 = re * re;
            im2 = im * im;
            if (re2 + im2 > 4.0) {
                return iters;
            }
            _r = re;
            _i = im;
            _r = re2 - im2;
            _i = 2 * (re * im);
            _r += re0;
            _i += im0;
            re = _r;
            im = _i;
        }
        return MAX_ITERS;
    }

    static void shuffleArray(Object[] ar) {
        Random rnd = new Random();
        for (int i = ar.length - 1; i > 0; i--) {
          int index = rnd.nextInt(i + 1);
          // Simple swap
          Object a = ar[index];
          ar[index] = ar[i];
          ar[i] = a;
        }
      }

    public static void main(String[] args) {
        long startTime = System.nanoTime();

        System.out.println("Generating colors...");

        for (int i = 0; i < 4096 * 4096; i++) {
            colors[i][0] = (char)((i >> 16) & 0xFF); // Red
            colors[i][1] = (char)((i >> 8) & 0xFF);  // Green
            colors[i][2] = (char)(i & 0xFF);         // Blue
        }

        System.out.println("Sorting colors...");

        //shuffleArray(colors); // Not needed

        Arrays.sort(colors, new Comparator<char[]>() {
            @Override
            public int compare(char[] a, char[] b) {
                return (a[0] + a[1] + a[2]) - (b[0] + b[1] + b[2]);
            }
        });

        System.out.println("Generating fractal...");

        for (int y = -2048; y < 2048; y++) {
            for (int x = -2048; x < 2048; x++) {
                short iters = (short) mandel(x / 1024.0, y / 1024.0, 1024);
                iterMap[x + 2048][y + 2048] = iters;
            }
        }

        System.out.println("Organizing pixels in the image...");

        for (short x = 0; x < 4096; x++) {
            for (short y = 0; y < 4096; y++) {
                pixels[x * 4096 + y][0] = x;
                pixels[x * 4096 + y][1] = y;
            }
        }

        shuffleArray(pixels);

        Arrays.sort(pixels, new Comparator<short[]>() {
            @Override
            public int compare(short[] a, short[] b) {
                return iterMap[b[0]][b[1]] - iterMap[a[0]][a[1]];
            }
        });

        System.out.println("Writing image to BufferedImage...");

        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = img.createGraphics();

        for (int i = 0; i < 4096 * 4096; i++) {
            g.setColor(new Color(colors[i][0], colors[i][1], colors[i][2]));
            g.fillRect(pixels[i][0], pixels[i][1], 1, 1);
        }

        g.dispose();

        System.out.println("Writing image to file...");

        File imageFile = new File("image.png");

        try {
            ImageIO.write(img, "png", imageFile);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Done!");
        System.out.println("Took " + ((System.nanoTime() - startTime) / 1000000000.) + " seconds.");
        System.out.println();
        System.out.println("The result is saved in " + imageFile.getAbsolutePath());

    }

}

18

Mathematica

colors = Table[
r = y*256 + x; {BitAnd[r, 2^^111110000000000]/32768., 
BitAnd[r, 2^^1111100000]/1024., BitAnd[r, 2^^11111]/32.}, {y, 0, 
127}, {x, 0, 255}];
SeedRandom[1337];
maxi = 5000000;
Monitor[For[i = 0, i < maxi, i++,
x1 = RandomInteger[{2, 255}];
x2 = RandomInteger[{2, 255}];
y1 = RandomInteger[{2, 127}];
y2 = RandomInteger[{2, 127}];
c1 = colors[[y1, x1]];
c2 = colors[[y2, x2]];
ca1 = (colors[[y1 - 1, x1]] + colors[[y1, x1 - 1]] + 
  colors[[y1 + 1, x1]] + colors[[y1, x1 + 1]])/4.;
ca2 = (colors[[y2 - 1, x2]] + colors[[y2, x2 - 1]] + 
  colors[[y2 + 1, x2]] + colors[[y2, x2 + 1]])/4.;
d1 = Abs[c1[[1]] - ca1[[1]]] + Abs[c1[[2]] - ca1[[2]]] + 
Abs[c1[[3]] - ca1[[3]]];
d1p = Abs[c2[[1]] - ca1[[1]]] + Abs[c2[[2]] - ca1[[2]]] + 
Abs[c2[[3]] - ca1[[3]]];
d2 = Abs[c2[[1]] - ca2[[1]]] + Abs[c2[[2]] - ca2[[2]]] + 
Abs[c2[[3]] - ca2[[3]]];
d2p = Abs[c1[[1]] - ca2[[1]]] + Abs[c1[[2]] - ca2[[2]]] + 
Abs[c1[[3]] - ca2[[3]]];
If[(d1p + d2p < 
  d1 + d2) || (RandomReal[{0, 1}] < 
   Exp[-Log10[i]*(d1p + d2p - (d1 + d2))] && i < 1000000),
temp = colors[[y1, x1]];
colors[[y1, x1]] = colors[[y2, x2]];
colors[[y2, x2]] = temp
]
], ProgressIndicator[i, {1, maxi}]]
Image[colors]

Sonuç (2x):

256x128 2x

Orijinal 256x128 görüntü

Düzenle:

Log10 [i] 'ı Log10 [i] / 5 ile değiştirerek şunları elde edersiniz: görüntü tanımını buraya girin

Yukarıdaki kod benzetilmiş tavlama ile ilgilidir. Bu şekilde bakıldığında, ikinci resim ilk 10 ^ 6 adımda daha yüksek bir "sıcaklık" ile yaratılır. Yüksek "sıcaklık", pikseller arasında daha fazla permütasyona neden olur, oysa ilk görüntüde, sipariş edilen görüntünün yapısı hala hafifçe görülebilir.


17

JavaScript

Hala bir öğrenci ve ilk kez gönderim yaptığım için kodlarım muhtemelen dağınık ve resimlerimin tüm gerekli renklere sahip olduğundan% 100 emin değilim, ancak sonuçlarımdan çok memnun kaldım, bu yüzden bunları göndereceğimi düşündüm.

Yarışmanın bittiğini biliyorum ama bunların sonuçlarını gerçekten çok sevdim ve her zaman özyinelemeli geriye dönük labirentlerin görünümünü çok sevdim, bu yüzden renkli pikseller yerleştirilirse birinin nasıl görüneceğini görmenin harika olacağını düşündüm. Böylece bir dizideki tüm renkleri üreterek başlıyorum, sonra diziden renkleri çıkarırken özyinelemeli geri izlemeyi yapıyorum.

İşte benim JSFiddle'ım http://jsfiddle.net/Kuligoawesome/3VsCu/

// Global variables
const FPS = 60;// FrameRate
var canvas = null;
var ctx = null;

var bInstantDraw = false;
var MOVES_PER_UPDATE = 50; //How many pixels get placed down
var bDone = false;
var width; //canvas width
var height; //canvas height
var colorSteps = 32;

var imageData;
var grid;
var colors;

var currentPos;
var prevPositions;

// This is called when the page loads
function Init()
{
    canvas = document.getElementById('canvas'); // Get the HTML element with the ID of 'canvas'
    width = canvas.width;
    height = canvas.height;
    ctx = canvas.getContext('2d'); // This is necessary, but I don't know exactly what it does

    imageData = ctx.createImageData(width,height); //Needed to do pixel manipulation

    grid = []; //Grid for the labyrinth algorithm
    colors = []; //Array of all colors
    prevPositions = []; //Array of previous positions, used for the recursive backtracker algorithm

    for(var r = 0; r < colorSteps; r++)
    {
        for(var g = 0; g < colorSteps; g++)
        {
            for(var b = 0; b < colorSteps; b++)
            {
                colors.push(new Color(r * 255 / (colorSteps - 1), g * 255 / (colorSteps - 1), b * 255 / (colorSteps - 1)));
                //Fill the array with all colors
            }
        }
    }

    colors.sort(function(a,b)
    {
        if (a.r < b.r)
            return -1;
        if (a.r > b.r)
            return 1;
        if (a.g < b.g)
            return -1;
        if (a.g > b.g)
            return 1;
        if (a.b < b.b)
            return -1;
        if (a.b > b.b)
            return 1;
        return 0;
    });

    for(var x = 0; x < width; x++)
    {
        grid.push(new Array());
        for(var y = 0; y < height; y++)
        {
            grid[x].push(0); //Set up the grid
            //ChangePixel(imageData, x, y, colors[x + (y * width)]);
        }
    }

    currentPos = new Point(Math.floor(Math.random() * width),Math.floor(Math.random() * height)); 

    grid[currentPos.x][currentPos.y] = 1;
    prevPositions.push(currentPos);
    ChangePixel(imageData, currentPos.x, currentPos.y, colors.pop());

    if(bInstantDraw)
    {
        do
        {
            var notMoved = true;
            while(notMoved)
            {
                var availableSpaces = CheckForSpaces(grid);

                if(availableSpaces.length > 0)
                {
                    var test = availableSpaces[Math.floor(Math.random() * availableSpaces.length)];
                    prevPositions.push(currentPos);
                    currentPos = test;
                    grid[currentPos.x][currentPos.y] = 1;
                    ChangePixel(imageData, currentPos.x, currentPos.y, colors.pop());
                    notMoved = false;
                }
                else
                {
                    if(prevPositions.length != 0)
                    {
                        currentPos = prevPositions.pop();
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
        while(prevPositions.length > 0)

        ctx.putImageData(imageData,0,0);
    }
    else
    {
        setInterval(GameLoop, 1000 / FPS);
    }
}

// Main program loop
function GameLoop()
{
    Update();
    Draw();
}

// Game logic goes here
function Update()
{
    if(!bDone)
    {
        var counter = MOVES_PER_UPDATE;
        while(counter > 0) //For speeding up the drawing
        {
            var notMoved = true;
            while(notMoved)
            {
                var availableSpaces = CheckForSpaces(grid); //Find available spaces

                if(availableSpaces.length > 0) //If there are available spaces
                {
                    prevPositions.push(currentPos); //add old position to prevPosition array
                    currentPos = availableSpaces[Math.floor(Math.random() * availableSpaces.length)]; //pick a random available space
                    grid[currentPos.x][currentPos.y] = 1; //set that space to filled
                    ChangePixel(imageData, currentPos.x, currentPos.y, colors.pop()); //pop color of the array and put it in that space
                    notMoved = false;
                }
                else
                {
                    if(prevPositions.length != 0)
                    {
                        currentPos = prevPositions.pop(); //pop to previous position where spaces are available
                    }
                    else
                    {
                        bDone = true;
                        break;
                    }
                }
            }
            counter--;
        }
    }
}
function Draw()
{
    // Clear the screen
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.fillStyle='#000000';
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    ctx.putImageData(imageData,0,0);
}

function CheckForSpaces(inGrid) //Checks for available spaces then returns back all available spaces
{
    var availableSpaces = [];

    if(currentPos.x > 0 && inGrid[currentPos.x - 1][currentPos.y] == 0)
    {
        availableSpaces.push(new Point(currentPos.x - 1, currentPos.y));
    }

    if(currentPos.x < width - 1 && inGrid[currentPos.x + 1][currentPos.y] == 0)
    {
        availableSpaces.push(new Point(currentPos.x + 1, currentPos.y));
    }

    if(currentPos.y > 0 && inGrid[currentPos.x][currentPos.y - 1] == 0)
    {
        availableSpaces.push(new Point(currentPos.x, currentPos.y - 1));
    }

    if(currentPos.y < height - 1 && inGrid[currentPos.x][currentPos.y + 1] == 0)
    {
        availableSpaces.push(new Point(currentPos.x, currentPos.y + 1));
    }

    return availableSpaces;
}

function ChangePixel(data, x, y, color) //Quick function to simplify changing pixels
{
    data.data[((x + (y * width)) * 4) + 0] = color.r;
    data.data[((x + (y * width)) * 4) + 1] = color.g;
    data.data[((x + (y * width)) * 4) + 2] = color.b;
    data.data[((x + (y * width)) * 4) + 3] = 255;
}

/*Needed Classes*/
function Point(xIn, yIn)
{
    this.x = xIn;
    this.y = yIn;
}

function Color(r, g, b)
{
    this.r = r;
    this.g = g;
    this.b = b;
    this.hue = Math.atan2(Math.sqrt(3) * (this.g - this.b), 2 * this.r - this.g, this.b);
    this.min = Math.min(this.r, this.g);
    this.min = Math.min(this.min, this.b);
    this.min /= 255;
    this.max = Math.max(this.r, this.g);
    this.max = Math.max(this.max, this.b);
    this.max /= 255;
    this.luminance = (this.min + this.max) / 2;
    if(this.min === this.max)
    {
        this.saturation = 0;
    }
    else if(this.luminance < 0.5)
    {
        this.saturation = (this.max - this.min) / (this.max + this.min);
    }
    else if(this.luminance >= 0.5)
    {
        this.saturation = (this.max - this.min) / (2 - this.max - this.min);
    }
}

256x128 resim, kırmızı -> yeşil -> mavi renk sıralaması
RGB Sıralı Renkler

256x128 resim, sıralı renkler mavi-> yeşil-> kırmızı
BGR Sıralama Renkleri

256x128 resim, renk tonları sıralı-> parlaklık-> doygunluk
HLS Sıralı Renkler

Ve nihayet bir tane üretilmekte olan bir GIF
Renkli Labirent GIF


Renkleriniz en aydınlık bölgelerde kırpılarak kopyalara neden olur. Değişim r * Math.ceil(255 / (colorSteps - 1)için r * Math.floor(255 / (colorSteps - 1), hatta daha iyi: r * 255 / (colorSteps - 1)(denenmemiş, bir jsfiddle arz etmediği)
Mark JERONIMUS

Boğmaca, evet, sorunlara yol açacak bir his vardı, umarım şimdi sabittir ve jsfiddle eksikliği yüzünden üzgünüm (var olduğunu bilmiyordum!) Teşekkürler!
Kuligoawesome

Bunun sipariş edilen kaosunu / gürültüsünü görünümlü çıktısını ve benzer çıktısı üreten başka bir çözümü seviyorum.
r_alex_hall

17

C #

Ben de bunun üzerine eğlenceli bir alıştırma olarak çalışmaya başladım ve en azından bana çok temiz görünen bir çıktı verdim. Çözümümdeki (en azından) diğerlerinden en önemli farkı, nesli saf beyazdan saf siyaha eşitlemek için eşit bir şekilde aralıklarla başlamak için gereken renkleri tam olarak üretmemdir. Ayrıca içe doğru bir spiralde çalışan renkleri ayarlıyorum ve ayarlanmış tüm komşular arasındaki renk farkının ortalamasına bağlı olarak bir sonraki rengi seçiyorum.

İşte şimdiye kadar ürettiğim küçük bir örnek çıktı, 4k render üzerinde çalışıyorum ama bitmesi için bir güne kadar devam etmesini bekliyorum.

256x128'deki spec çıktısının bir örneği:

Spec Render

Yine de makul oluşturma sürelerine sahip bazı daha büyük resimler:

Render 360 x 240'de

360 x 240’da yapılan ikinci deneme daha yumuşak bir görüntü üretti

Render # 2'yi 360 x 240'da

Performansı arttırdıktan sonra, 2 gün süren bir HD render çalıştırabildi, 4k vermedim ancak haftalar sürebilir.

HD Render

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace SandBox
{
    class Program
    {
        private static readonly List<Point> directions = new List<Point>
        {
            new Point(1, 0),
            new Point(0, 1),
            new Point(-1, 0),
            new Point(0, -1)
        };

        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                HelpFile();
                return;
            }
            try
            {
                var config = new ColorGeneratorConfig
                {
                    XLength = int.Parse(args[0]),
                    YLength = int.Parse(args[1])
                };

                Console.WriteLine("Starting image generation with:");
                Console.WriteLine($"\tDimensions:\t\t{config.XLength} X {config.YLength}");
                Console.WriteLine($"\tSteps Per Channel:\t{config.NumOfSteps}");
                Console.WriteLine($"\tStep Size:\t\t{config.ColorStep}");
                Console.WriteLine($"\tSteps to Skip:\t\t{config.StepsToSkip}\n");

                var runner = new TaskRunner();
                var colors = runner.Run(() => GenerateColorList(config), "color selection");
                var pixels = runner.Run(() => BuildPixelArray(colors, config), "pixel array generation");
                runner.Run(() => OutputBitmap(pixels, config), "bitmap creation");
            }
            catch (Exception ex)
            {
               HelpFile("There was an issue in execution");
            }

            Console.ReadLine();
        }

        private static void HelpFile(string errorMessage = "")
        {
            const string Header = "Generates an image with every pixel having a unique color";
            Console.WriteLine(errorMessage == string.Empty ? Header : $"An error has occured: {errorMessage}\n Ensure the Arguments you have provided are valid");
            Console.WriteLine();
            Console.WriteLine($"{AppDomain.CurrentDomain.FriendlyName} X Y");
            Console.WriteLine();
            Console.WriteLine("X\t\tThe Length of the X dimension eg: 256");
            Console.WriteLine("Y\t\tThe Length of the Y dimension eg: 128");
        }

        public static List<Color> GenerateColorList(ColorGeneratorConfig config)
        {

            //Every iteration of our color generation loop will add the iterationfactor to this accumlator which is used to know when to skip
            decimal iterationAccumulator = 0;

            var colors = new List<Color>();
            for (var r = 0; r < config.NumOfSteps; r++)
                for (var g = 0; g < config.NumOfSteps; g++)
                    for (var b = 0; b < config.NumOfSteps; b++)
                    {
                        iterationAccumulator += config.IterationFactor;

                        //If our accumulator has reached 1, then subtract one and skip this iteration
                        if (iterationAccumulator > 1)
                        {
                            iterationAccumulator -= 1;
                            continue;
                        }

                        colors.Add(Color.FromArgb(r*config.ColorStep, g*config.ColorStep,b*config.ColorStep));
                    }
            return colors;
        }

        public static Color?[,] BuildPixelArray(List<Color> colors, ColorGeneratorConfig config)
        {
            //Get a random color to start with.
            var random = new Random(Guid.NewGuid().GetHashCode());
            var nextColor = colors[random.Next(colors.Count)];

            var pixels = new Color?[config.XLength, config.YLength];
            var currPixel = new Point(0, 0);

            var i = 0;

            //Since we've only generated exactly enough colors to fill our image we can remove them from the list as we add them to our image and stop when none are left.
            while (colors.Count > 0)
            {
                i++;

                //Set the current pixel and remove the color from the list.
                pixels[currPixel.X, currPixel.Y] = nextColor;
                colors.RemoveAt(colors.IndexOf(nextColor));

                //Our image generation works in an inward spiral generation GetNext point will retrieve the next pixel given the current top direction.
                var nextPixel = GetNextPoint(currPixel, directions.First());

                //If this next pixel were to be out of bounds (for first circle of spiral) or hit a previously generated pixel (for all other circles)
                //Then we need to cycle the direction and get a new next pixel
                if (nextPixel.X >= config.XLength || nextPixel.Y >= config.YLength || nextPixel.X < 0 || nextPixel.Y < 0 ||
                    pixels[nextPixel.X, nextPixel.Y] != null)
                {
                    var d = directions.First();
                    directions.RemoveAt(0);
                    directions.Add(d);
                    nextPixel = GetNextPoint(currPixel, directions.First());
                }

                //This code sets the pixel to pick a color for and also gets the next color
                //We do this at the end of the loop so that we can also support haveing the first pixel set outside of the loop
                currPixel = nextPixel;

                if (colors.Count == 0) continue;

                var neighbours = GetNeighbours(currPixel, pixels, config);
                nextColor = colors.AsParallel().Aggregate((item1, item2) => GetAvgColorDiff(item1, neighbours) <
                                                                            GetAvgColorDiff(item2, neighbours)
                    ? item1
                    : item2);
            }

            return pixels;
        }

        public static void OutputBitmap(Color?[,] pixels, ColorGeneratorConfig config)
        {
            //Now that we have generated our image in the color array we need to copy it into a bitmap and save it to file.
            var image = new Bitmap(config.XLength, config.YLength);

            for (var x = 0; x < config.XLength; x++)
                for (var y = 0; y < config.YLength; y++)
                    image.SetPixel(x, y, pixels[x, y].Value);

            using (var file = new FileStream($@".\{config.XLength}X{config.YLength}.png", FileMode.Create))
            {
                image.Save(file, ImageFormat.Png);
            }
        }

        static Point GetNextPoint(Point current, Point direction)
        {
            return new Point(current.X + direction.X, current.Y + direction.Y);
        }

        static List<Color> GetNeighbours(Point current, Color?[,] grid, ColorGeneratorConfig config)
        {
            var list = new List<Color>();
            foreach (var direction in directions)
            {
                var xCoord = current.X + direction.X;
                var yCoord = current.Y + direction.Y;
                if (xCoord < 0 || xCoord >= config.XLength|| yCoord < 0 || yCoord >= config.YLength)
                {
                    continue;
                }
                var cell = grid[xCoord, yCoord];
                if (cell.HasValue) list.Add(cell.Value);
            }
            return list;
        }

        static double GetAvgColorDiff(Color source, IList<Color> colors)
        {
            return colors.Average(color => GetColorDiff(source, color));
        }

        static int GetColorDiff(Color color1, Color color2)
        {
            var redDiff = Math.Abs(color1.R - color2.R);
            var greenDiff = Math.Abs(color1.G - color2.G);
            var blueDiff = Math.Abs(color1.B - color2.B);
            return redDiff + greenDiff + blueDiff;
        }
    }

    public class ColorGeneratorConfig
    {
        public int XLength { get; set; }
        public int YLength { get; set; }

        //Get the number of permutations for each color value base on the required number of pixels.
        public int NumOfSteps
            => (int)Math.Ceiling(Math.Pow((ulong)XLength * (ulong)YLength, 1.0 / ColorDimensions));

        //Calculate the increment for each step
        public int ColorStep
            => 255 / (NumOfSteps - 1);

        //Because NumOfSteps will either give the exact number of colors or more (never less) we will sometimes to to skip some
        //this calculation tells how many we need to skip
        public decimal StepsToSkip
            => Convert.ToDecimal(Math.Pow(NumOfSteps, ColorDimensions) - XLength * YLength);

        //This factor will be used to as evenly as possible spread out the colors to be skipped so there are no large gaps in the spectrum
        public decimal IterationFactor => StepsToSkip / Convert.ToDecimal(Math.Pow(NumOfSteps, ColorDimensions));

        private double ColorDimensions => 3.0;
    }

    public class TaskRunner
    {
        private Stopwatch _sw;
        public TaskRunner()
        {
            _sw = new Stopwatch();
        }

        public void Run(Action task, string taskName)
        {
            Console.WriteLine($"Starting {taskName}...");
            _sw.Start();
            task();
            _sw.Stop();
            Console.WriteLine($"Finished {taskName}. Elapsed(ms): {_sw.ElapsedMilliseconds}");
            Console.WriteLine();
            _sw.Reset();
        }

        public T Run<T>(Func<T> task, string taskName)
        {
            Console.WriteLine($"Starting {taskName}...");
            _sw.Start();
            var result = task();
            _sw.Stop();
            Console.WriteLine($"Finished {taskName}. Elapsed(ms): {_sw.ElapsedMilliseconds}");
            Console.WriteLine();
            _sw.Reset();
            return result;
        }
    }
}

Renk seçimi algoritmasının performansını nasıl artıracağınıza dair herhangi bir fikri olan varsa, lütfen bana bildirin, çünkü 360 * 240 render yaklaşık 15 dakika sürer. Paralelleştirilebileceğine inanmıyorum ama en düşük renk farkını elde etmenin daha hızlı bir yolu olup olmadığını merak ediyorum.
Phaeze

360 * 240 görüntü nasıl 'tüm renkleri' oluşturur? Bileşen başına cbrt (360 * 240) = 44.208377983684639269357874002958 renkleri nasıl üretiyorsunuz?
Mark Jeronimus

Bu hangi dil? Bir liste türünü ve Rastgele'yi rastgele seçmek, ne olursa olsun, kötü bir fikirdir, çünkü algoritmaya ve uygulamaya bağlı olarak, aşağıdakileri belirten taraflı bir sonuca veya istisnalara neden olabilir "Comparison method violates its general contract!": çünkü sözleşme bunu belirtir (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0. Bir listeyi randomize etmek için sağlanan bazı Shuffle yöntemini kullanın. ( colors.Shuffle()?)
Mark Jeronimus

@MarkJeronimus 256x128 resimle ilgili teknik özellikleri kaçırdığımı itiraf ediyorum, bu boyutları kullanarak basit renderleri tekrar yapacağım, her piksele odaklandım, diğer sunumlar gibi her bir pikselin zorluğun benzersiz bir renk yönü ve daha büyük renderler üzerine odaklandığını gördüm.
Phaeze

@ MarkJeronimus Ben rastgele sıralama kötü olduğunu fark, aslında çok söyleyen bir yorum var. Bu benim almaya başladığım başka bir yaklaşımın bir parçasıydı ve çok uzun sürdüğü gibi, büyük renderlerin yapılmasına öncelik verdim.
Phaeze

16

Git

İşte benden bir diğeri, daha ilginç sonuçlar verdiğini düşünüyorum:

package main

import (
    "image"
    "image/color"
    "image/png"
    "os"

    "math"
    "math/rand"
)

func distance(c1, c2 color.Color) float64 {
    r1, g1, b1, _ := c1.RGBA()
    r2, g2, b2, _ := c2.RGBA()
    rd, gd, bd := int(r1)-int(r2), int(g1)-int(g2), int(b1)-int(b2)
    return math.Sqrt(float64(rd*rd + gd*gd + bd*bd))
}

func main() {
    allcolor := image.NewRGBA(image.Rect(0, 0, 256, 128))
    for y := 0; y < 128; y++ {
        for x := 0; x < 256; x++ {
            allcolor.Set(x, y, color.RGBA{uint8(x%32) * 8, uint8(y%32) * 8, uint8(x/32+(y/32*8)) * 8, 255})
        }
    }

    for y := 0; y < 128; y++ {
        for x := 0; x < 256; x++ {
            rx, ry := rand.Intn(256), rand.Intn(128)

            c1, c2 := allcolor.At(x, y), allcolor.At(rx, ry)
            allcolor.Set(x, y, c2)
            allcolor.Set(rx, ry, c1)
        }
    }

    for i := 0; i < 16384; i++ {
        for y := 0; y < 128; y++ {
            for x := 0; x < 256; x++ {
                xl, xr := (x+255)%256, (x+1)%256
                cl, c, cr := allcolor.At(xl, y), allcolor.At(x, y), allcolor.At(xr, y)
                dl, dr := distance(cl, c), distance(c, cr)
                if dl < dr {
                    allcolor.Set(xl, y, c)
                    allcolor.Set(x, y, cl)
                }

                yu, yd := (y+127)%128, (y+1)%128
                cu, c, cd := allcolor.At(x, yu), allcolor.At(x, y), allcolor.At(x, yd)
                du, dd := distance(cu, c), distance(c, cd)
                if du < dd {
                    allcolor.Set(x, yu, c)
                    allcolor.Set(x, y, cu)
                }
            }
        }
    }

    filep, err := os.Create("EveryColor.png")
    if err != nil {
        panic(err)
    }
    err = png.Encode(filep, allcolor)
    if err != nil {
        panic(err)
    }
    filep.Close()
}

Diğer cevabımdaki gif ile aynı kalıpla başlar . Sonra, bunu içine karıştırır:

sadece gürültü

Ne kadar yinelenirseniz, daha çok eskimeyen komşu-karşılaştırma algoritmasını çalıştırdığımda, gökkuşağı deseni o kadar belirgin hale gelir.

İşte 16384:

16384 yinelemede çok gürültülü bir gökkuşağı

Ve 65536:

görüntü tanımını buraya girin


6
+1 Bundan bir kalıp çıkması hoşuma gidiyor; Bir animasyon yapmalısın!
Jason C,

16

Bu görüntüler "Langton's Rainbow". Basitçe çizilirler: Langton'un karınca hareket ettikçe, pikselin ilk ziyareti sırasında her pikselin üzerine bir renk çizilir. Sonra çizilecek renk daha sonra 1 ile artırılır ve her piksel için bir tane olmak üzere 2 ^ 15 renk kullanılır.

DÜZENLE: 2 ^ 24 renk kullanarak 4096X4096 görüntü veren bir sürüm yaptım. Renkler aynı zamanda “yansıtılır”, böylece güzel, pürüzsüz gradyanlar oluştururlar. Çok büyük oldukları için onlara yalnızca bağlantı sağlayacağım (> 28 MB)

Langton's Rainbow büyük, LR kural

Langton'un Gökkuşağı büyük, LLRR kural

// Düzenlemenin sonu.

Klasik LR kural kümesi için bu:

Langton's Rainbow LR

İşte LLRR:

Langton's Rainbow LLRR

Son olarak, bu LRRRRRLLR kuralını kullanır:

Langton'ın Gökkuşağı LRRRRRLLR

C ++ ile yazılmış, grafikler için CImg kullanılmıştır. Renklerin nasıl seçildiğini de belirtmeliyim: İlk önce, RGB renk verilerini içermek için imzasız bir kısa kullandım. Bir hücre ilk ziyaret edildiğinde, bitleri 5 katının bir kaçına, VE 31'e çarptıktan sonra 8 ile çarparım. Sonra işaretsiz kısa renk 1 ile artar. Bu, en çok 0 - 248 arasında değerler üretir. Ancak, ben bu değeri çıkarmak ettik den nedenle R ve B 7'ye aşağı, 255 başlayarak, 8 katları olan kırmızı ve mavi bileşenleri 255:

c[0]=255-((color&0x1F)*8);
c[2]=255-(((color>>5)&0x1F)*8);
c[1]=(((color>>10)&0x1F)*8);

Ancak, bu, 0'dan 248'e kadar 8'in katları olan yeşil bileşen için geçerli değildir. Her durumda, her pikselin kendine özgü bir renk içermesi gerekir.

Neyse, kaynak kodu aşağıda:

#include "CImg.h"
using namespace cimg_library;
CImgDisplay screen;
CImg<unsigned char> surf;
#define WIDTH 256
#define HEIGHT 128
#define TOTAL WIDTH*HEIGHT
char board[WIDTH][HEIGHT];


class ant
{
  public:
  int x,y;
  char d;
  unsigned short color;
  void init(int X, int Y,char D)
  {
    x=X;y=Y;d=D;
    color=0;
  }

  void turn()
  {
    ///Have to hard code for the rule set here.
    ///Make sure to set RULECOUNT to the number of rules!
    #define RULECOUNT 9
    //LRRRRRLLR
    char get=board[x][y];
    if(get==0||get==6||get==7){d+=1;}
    else{d-=1;}
    if(d<0){d=3;}
    else if(d>3){d=0;}
  }

  void forward()
  {
    if(d==0){x++;}
    else if(d==1){y--;}
    else if(d==2){x--;}
    else {y++;}
    if(x<0){x=WIDTH-1;}
    else if(x>=WIDTH){x=0;}
    if(y<0){y=HEIGHT-1;}
    else if(y>=HEIGHT){y=0;}
  }

  void draw()
  {
    if(board[x][y]==-1)
    {
      board[x][y]=0;
      unsigned char c[3];
      c[0]=255-((color&0x1F)*8);
      c[2]=255-(((color>>5)&0x1F)*8);
      c[1]=(((color>>10)&0x1F)*8);
      surf.draw_point(x,y,c);
      color++;
    }

    board[x][y]++;
    if(board[x][y]==RULECOUNT){board[x][y]=0;}

  }

  void step()
  {
    draw();
    turn();
    forward();
  }
};

void renderboard()
{
  unsigned char white[]={200,190,180};
  surf.draw_rectangle(0,0,WIDTH,HEIGHT,white);
  for(int x=0;x<WIDTH;x++)
  for(int y=0;y<HEIGHT;y++)
  {
    char get=board[x][y];
    if(get==1){get=1;unsigned char c[]={255*get,255*get,255*get};
    surf.draw_point(x,y,c);}
    else if(get==0){get=0;unsigned char c[]={255*get,255*get,255*get};
    surf.draw_point(x,y,c);}
  }
}

int main(int argc, char** argv)
{

  screen.assign(WIDTH*3,HEIGHT*3);
  surf.assign(WIDTH,HEIGHT,1,3);
  ant a;
  a.init(WIDTH/2,HEIGHT/2,2);
  surf.fill(0);
  for(int x=0;x<WIDTH;x++)
  for(int y=0;y<HEIGHT;y++)
  {
    board[x][y]=-1;
  }

  while(a.color<TOTAL)
  {
    a.step();
  }

  screen=surf;
  while(screen.is_closed()==false)
  {
    screen.wait();
  }
  surf.save_bmp("LangtonsRainbow.bmp");
  return 0;
}

1
Hoşgeldiniz ve kulübe katılın. Belki code.google.com/p/ruletablerepository/wiki/… adresindeki diğer türitleri denemek ilginç olabilir (buna katıldım)
Mark Jeronimus

3
Dropbox Ortak Klasörleri öldürdüğü için resim bağlantıları kesildi .
user2428118

15

Yakut

Devam edip PNG'yi sıfırdan yapmaya karar verdim, çünkü bunun ilginç olacağını düşündüm. Bu kod tam anlamıyla ham çıktı ikili veriyi bir dosyaya .

512x512 sürümünü yaptım. (Algoritma yine de ilginç değil.) Makinemde yaklaşık 3 saniye içinde bitiyor.

require 'zlib'

class RBPNG
  def initialize
    # PNG header
    @data = [137, 80, 78, 71, 13, 10, 26, 10].pack 'C*'
  end

  def chunk name, data = ''
    @data += [data.length].pack 'N'
    @data += name
    @data += data
    @data += [Zlib::crc32(name + data)].pack 'N'
  end

  def IHDR opts = {}
    opts = {bit_depth: 8, color_type: 6, compression: 0, filter: 0, interlace: 0}.merge opts
    raise 'IHDR - Missing width param' if !opts[:width]
    raise 'IHDR - Missing height param' if !opts[:height]

    self.chunk 'IHDR', %w[width height].map {|x| [opts[x.to_sym]].pack 'N'}.join +
                       %w[bit_depth color_type compression filter interlace].map {|x| [opts[x.to_sym]].pack 'C'}.join
  end

  def IDAT data; self.chunk 'IDAT', Zlib.deflate(data); end
  def IEND; self.chunk 'IEND'; end
  def write filename; IO.binwrite filename, @data; end
end

class Color
  attr_accessor :r, :g, :b, :a

  def initialize r = 0, g = 0, b = 0, a = 255
    if r.is_a? Array
      @r, @g, @b, @a = @r
      @a = 255 if !@a
    else
      @r = r
      @g = g
      @b = b
      @a = a
    end
  end

  def hex; '%02X' * 4 % [@r, @g, @b, @a]; end
  def rgbhex; '%02X' * 3 % [@r, @g, @b]; end
end

img = RBPNG.new
img.IHDR({width: 512, height: 512, color_type: 2})
#img.IDAT ['00000000FFFFFF00FFFFFF000000'].pack 'H*'
r = g = b = 0
data = Array.new(512){ Array.new(512){
  c = Color.new r, g, b
  r += 4
  if r == 256
    r = 0
    g += 4
    if g == 256
      g = 0
      b += 4
    end
  end
  c
} }
img.IDAT [data.map {|x| '00' + x.map(&:rgbhex).join }.join].pack 'H*'
img.IEND
img.write 'all_colors.png'

Çıktı (inç all_colors.png) (büyütmek için bu resimlerden birine tıklayın):

Çıktı

Biraz daha ilginç degrade-ish çıktısı (dördüncü son çizgiyi değiştirerek }.shuffle }):

Çıkış 2

Ve onu değiştirerek }.shuffle }.shuffleçılgın renkli çizgiler elde edersiniz:

Çıkış 3


Bu gerçekten havalı. Yine de daha güzel yapmanın bir yolu var mı? Belki pikselleri rastgele? Scoring is by vote. Vote for the most beautiful images made by the most elegant code.

1
@LowerClassOverflowian Tamam, düzenlendi
Doorknob

Çok daha iyi!!!!!!!

1
4. sırayı son satırına değiştirirseniz ne olacak }.shuffle }.shuffle }.shuffle?
John Odom

6
@John Erm, muhtemelen sözdizimi hatası?
Doorknob

14

piton

plazma

Renkleri parlaklığa göre sıralamak için bir python kullanmak, bir parlaklık deseni oluşturmak ve en uygun rengi seçmek. Pikseller rasgele sırayla yinelenir, böylece kullanılabilir renkler listesi küçüldüğünde doğal olarak meydana gelen daha az parlaklık eşleşir, resim boyunca eşit şekilde yayılır.

#!/usr/bin/env python

from PIL import Image
from math import pi, sin, cos
import random

WIDTH = 256
HEIGHT = 128

img = Image.new("RGB", (WIDTH, HEIGHT))

colors = [(x >> 10, (x >> 5) & 31, x & 31) for x in range(32768)]
colors = [(x[0] << 3, x[1] << 3, x[2] << 3) for x in colors]
colors.sort(key=lambda x: x[0] * 0.2126 + x[1] * 0.7152 + x[2] * 0.0722)

def get_pixel(lum):
    for i in range(len(colors)):
        c = colors[i]
        if c[0] * 0.2126 + c[1] * 0.7152 + c[2] * 0.0722 > lum:
            break
    return colors.pop(i)

def plasma(x, y):
    x -= WIDTH / 2
    p = sin(pi * x / (32 + 10 * sin(y * pi / 32)))
    p *= cos(pi * y / 64)
    return 128 + 127 * p

xy = []
for x in range(WIDTH):
    for y in range(HEIGHT):
        xy.append((x, y))
random.shuffle(xy)

count = 0
for x, y in xy:
    l = int(plasma(x, y))
    img.putpixel((x, y), get_pixel(plasma(x, y)))
    count += 1
    if not count & 255:
        print "%d pixels rendered" % count

img.save("test.png")

13

Java

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Quincunx
 */
public class AllColorImage {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        int num = 0;
        ArrayList<Point> points = new ArrayList<>();
        for (int y = 0; y < 4096; y++) {
            for (int x = 0; x < 4096 ; x++) {
                points.add(new Point(x, y));
            }
        }
        for (Point p : points) {
            int x = p.x;
            int y = p.y;

            img.setRGB(x, y, num);
            num++;
        }
        try {
            ImageIO.write(img, "png", new File("Filepath"));
        } catch (IOException ex) {
            Logger.getLogger(AllColorImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

4096'ya 4096'ya gittim çünkü bütün renkleri nasıl elde edeceğimi bulamadım.

Çıktı:

Buraya sığmayacak kadar büyük. Bu bir ekran görüntüsüdür:

görüntü tanımını buraya girin

Küçük bir değişiklikle daha güzel bir resim elde edebiliriz:

Collections.shuffle(points, new Random(0));Noktaları oluşturmak ve renkleri yapmak arasına ekleyin :

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Quincunx
 */
public class AllColorImage {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);
        int num = 0;
        ArrayList<Point> points = new ArrayList<>();
        for (int y = 0; y < 4096; y++) {
            for (int x = 0; x < 4096 ; x++) {
                points.add(new Point(x, y));
            }
        }
        Collections.shuffle(points, new Random(0));
        for (Point p : points) {
            int x = p.x;
            int y = p.y;

            img.setRGB(x, y, num);
            num++;
        }
        try {
            ImageIO.write(img, "png", new File("Filepath"));
        } catch (IOException ex) {
            Logger.getLogger(AllColorImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

görüntü tanımını buraya girin

Kapatmak:

görüntü tanımını buraya girin


29
Büyük gri bir blob'a "güzel" mi diyorsun?
Doorknob

22
@Doorknob Evet. Ben çok güzel diyorum. Tüm renklerin büyük bir gri blob halinde düzenlenebildiğini şaşırtıcı buluyorum. Yakınlaştırdığımda blob'u daha ilginç buluyorum. Biraz daha ayrıntılı olarak Java'nın ne kadar rasgele olduğunu görebilirsiniz. Daha fazla zoom yaptığımızda, ikinci ekran görüntüsü gibi, o şeyin içinde kaç rengin olduğu belli oluyor. Daha da yakınlaştırdığımda, bir Piet programına benziyor.
Justin,

Alttaki parçaları düşürerek renkleri daha küçük sürümlerde aldım.
Mark Jeronimus

Evet, düşük bit için r, gve bayrı ayrı, ama bir numara olarak onlarla uğraşırken edildi.
Justin,

Bir sonraki cevabınızda b1t magicz'i çözdüğünüzü görüyorum. Konu üzerinde, Randomdaha az ideal rasgele sayılar üreten kendi alt sınıfınızla deneme yapmak ilginç olabilir .
Mark Jeronimus

13

C ++ 11

( Güncelleme: ancak daha sonra benzer bir yaklaşımın denendiğini, yinelemelerin sayısı konusunda daha fazla sabırla denediğimi fark ettim .)

Her piksel için, bir dizi komşu piksel tanımlarım. İki piksel arasındaki tutarsızlığı, R / G / B farklarının karelerinin toplamı olarak tanımlarım. Belirli bir pikselin cezası, piksel ile komşuları arasındaki tutarsızlıkların toplamıdır.

Şimdi, önce rastgele bir permütasyon üretiyorum, sonra rastgele piksel çiftleri almaya başladım. İki pikselin değiştirilmesi, tüm piksellerin toplam cezalarının toplamını azaltırsa, değişim geçer. Bunu milyonlarca kez tekrarlıyorum.

Çıktı, standart yardımcı programları kullanarak PNG'ye dönüştürdüğüm PPM biçiminde.

Kaynak:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <random>

static std::mt19937 rng;

class Pixel
{
public:
    int r, g, b;

    Pixel() : r(0), g(0), b(0) {}
    Pixel(int r, int g, int b) : r(r), g(g), b(b) {}

    void swap(Pixel& p)
    {
        int r = this->r,  g = this->g,    b = this->b;
        this->r = p.r;    this->g = p.g;  this->b = p.b;
        p.r = r;          p.g = g;        p.b = b;
    }
};

class Image
{
public:
    static const int width = 256;
    static const int height = 128;
    static const int step = 32;
    Pixel pixel[width*height];
    int penalty[width*height];
    std::vector<int>** neighbors;

    Image()
    {
        if (step*step*step != width*height)
        {
            std::cerr << "parameter mismatch" << std::endl;
            exit(EXIT_FAILURE);
        }

        neighbors = new std::vector<int>*[width*height];

        for (int i = 0; i < width*height; i++)
        {
            penalty[i] = -1;
            neighbors[i] = pixelNeighbors(i);
        }

        int i = 0;
        for (int r = 0; r < step; r++)
        for (int g = 0; g < step; g++)
        for (int b = 0; b < step; b++)
        {
            pixel[i].r = r * 255 / (step-1);
            pixel[i].g = g * 255 / (step-1);
            pixel[i].b = b * 255 / (step-1);
            i++;
        }
    }

    ~Image()
    {
        for (int i = 0; i < width*height; i++)
        {
            delete neighbors[i];
        }
        delete [] neighbors;
    }

    std::vector<int>* pixelNeighbors(const int pi)
    {
        // 01: X-shaped structure
        //const int iRad = 7, jRad = 7;
        //auto condition = [](int i, int j) { return abs(i) == abs(j); };
        //
        // 02: boring blobs
        //const int iRad = 7, jRad = 7;
        //auto condition = [](int i, int j) { return true; };
        //
        // 03: cross-shaped
        //const int iRad = 7, jRad = 7;
        //auto condition = [](int i, int j) { return i==0 || j == 0; };
        //
        // 04: stripes
        const int iRad = 1, jRad = 5;
        auto condition = [](int i, int j) { return i==0 || j == 0; };

        std::vector<int>* v = new std::vector<int>;

        int x = pi % width;
        int y = pi / width;

        for (int i = -iRad; i <= iRad; i++)
        for (int j = -jRad; j <= jRad; j++)
        {
            if (!condition(i,j))
                continue;

            int xx = x + i;
            int yy = y + j;

            if (xx < 0 || xx >= width || yy < 0 || yy >= height)
                continue;

            v->push_back(xx + yy*width);
        }

        return v;
    }

    void shuffle()
    {
        for (int i = 0; i < width*height; i++)
        {
            std::uniform_int_distribution<int> dist(i, width*height - 1);
            int j = dist(rng);
            pixel[i].swap(pixel[j]);
        }
    }

    void writePPM(const char* filename)
    {
        std::ofstream fd;
        fd.open(filename);
        if (!fd.is_open())
        {
            std::cerr << "failed to open file " << filename
                      << "for writing" << std::endl;
            exit(EXIT_FAILURE);
        }
        fd << "P3\n" << width << " " << height << "\n255\n";
        for (int i = 0; i < width*height; i++)
        {
            fd << pixel[i].r << " " << pixel[i].g << " " << pixel[i].b << "\n";
        }
        fd.close();
    }

    void updatePixelNeighborhoodPenalty(const int pi)
    {
        for (auto j : *neighbors[pi])
            updatePixelPenalty(j);
    }

    void updatePixelPenalty(const int pi)
    {
        auto pow2 = [](int x) { return x*x; };
        int pen = 0;
        Pixel* p1 = &pixel[pi];
        for (auto j : *neighbors[pi])
        {
            Pixel* p2 = &pixel[j];
            pen += pow2(p1->r - p2->r) + pow2(p1->g - p2->g) + pow2(p1->b - p2->b);
        }
        penalty[pi] = pen / neighbors[pi]->size();
    }

    int getPixelPenalty(const int pi)
    {
        if (penalty[pi] == (-1))
        {
            updatePixelPenalty(pi);
        }
        return penalty[pi];
    }

    int getPixelNeighborhoodPenalty(const int pi)
    {
        int sum = 0;
        for (auto j : *neighbors[pi])
        {
            sum += getPixelPenalty(j);
        }
        return sum;
    }

    void iterate()
    {
        std::uniform_int_distribution<int> dist(0, width*height - 1);       

        int i = dist(rng);
        int j = dist(rng);

        int sumBefore = getPixelNeighborhoodPenalty(i)
                        + getPixelNeighborhoodPenalty(j);

        int oldPenalty[width*height];
        std::copy(std::begin(penalty), std::end(penalty), std::begin(oldPenalty));

        pixel[i].swap(pixel[j]);
        updatePixelNeighborhoodPenalty(i);
        updatePixelNeighborhoodPenalty(j);

        int sumAfter = getPixelNeighborhoodPenalty(i)
                       + getPixelNeighborhoodPenalty(j);

        if (sumAfter > sumBefore)
        {
            // undo the change
            pixel[i].swap(pixel[j]);
            std::copy(std::begin(oldPenalty), std::end(oldPenalty), std::begin(penalty));
        }
    }
};

int main(int argc, char* argv[])
{
    int seed;
    if (argc >= 2)
    {
        seed = atoi(argv[1]);
    }
    else
    {
        std::random_device rd;
        seed = rd();
    }
    std::cout << "seed = " << seed << std::endl;
    rng.seed(seed);

    const int numIters = 1000000;
    const int progressUpdIvl = numIters / 100;
    Image img;
    img.shuffle();
    for (int i = 0; i < numIters; i++)
    {
        img.iterate();
        if (i % progressUpdIvl == 0)
        {
            std::cout << "\r" << 100 * i / numIters << "%";
            std::flush(std::cout);
        }
    }
    std::cout << "\rfinished!" << std::endl;
    img.writePPM("AllColors2.ppm");

    return EXIT_SUCCESS;
}

Komşuların adımını değiştirmek farklı sonuçlar verir. Bu, Image :: pixelNeighbors () işlevinde düzenlenebilir. Kod dört seçenek için örnekler içerir: (kaynağa bakın)

örnek 01 örnek 02 örnek 03 örnek 04

Düzenleme: Yukarıdaki dördüncü birine benzer, ancak daha büyük bir çekirdek ve daha fazla yineleme ile başka bir örnek:

örnek 05

Bir tane daha: kullanma

const int iRad = 7, jRad = 7;
auto condition = [](int i, int j) { return (i % 2==0 && j % 2==0); };

ve on milyon yineleme, bunu anladım:

örnek 06


11

En şık kod değil, ancak iki sayıdaki ilginç: Ölçülerden renk sayısının hesaplanması (boyutların ürünü iki güç olduğu sürece) ve trippy renk boşluğu işlerinin yapılması:

void Main()
{
    var width = 256;
    var height = 128;
    var colorCount = Math.Log(width*height,2);
    var bitsPerChannel = colorCount / 3;
    var channelValues = Math.Pow(2,bitsPerChannel);
    var channelStep = (int)(256/channelValues);

    var colors = new List<Color>();

    var m1 = new double[,] {{0.6068909,0.1735011,0.2003480},{0.2989164,0.5865990,0.1144845},{0.00,0.0660957,1.1162243}};
    for(var r=0;r<255;r+=channelStep)
    for(var g=0;g<255;g+=channelStep)
    for(var b=0;b<255;b+=channelStep)   
    {
        colors.Add(Color.FromArgb(0,r,g,b));
    }
    var sortedColors = colors.Select((c,i)=>
                            ToLookupTuple(MatrixProduct(m1,new[]{c.R/255d,c.G/255d,c.B/255d}),i))
                            .Select(t=>new
                                            {
                                                x = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 : t.Item1/(t.Item1+t.Item2+t.Item3),
                                                y = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 :t.Item2/(t.Item1+t.Item2+t.Item3),
                                                z = (t.Item1==0 && t.Item2==0 && t.Item3==0) ? 0 :t.Item3/(t.Item1+t.Item2+t.Item3),
                                                Y = t.Item2,
                                                i = t.Item4
                                            })
                            .OrderBy(t=>t.x).Select(t=>t.i).ToList();
    if(sortedColors.Count != (width*height))
    {
        throw new Exception(string.Format("Some colors fell on the floor: {0}/{1}",sortedColors.Count,(width*height)));
    }
    using(var bmp = new Bitmap(width,height,PixelFormat.Format24bppRgb))
    {
        for(var i=0;i<colors.Count;i++)
        {
            var y = i % height;
            var x = i / height;

            bmp.SetPixel(x,y,colors[sortedColors[i]]);
        }
        //bmp.Dump(); //For LINQPad use
        bmp.Save("output.png");
    }
}
static Tuple<double,double,double,int>ToLookupTuple(double[] t, int index)
{
    return new Tuple<double,double,double,int>(t[0],t[1],t[2],index);
}

public static double[] MatrixProduct(double[,] matrixA,
    double[] vectorB)
{
    double[] result=new double[3];
    for (int i=0; i<3; ++i) // each row of A
        for (int k=0; k<3; ++k)
            result[i]+=matrixA[i,k]*vectorB[k];
    return result;
}

OrderBy yan tümcesini değiştirerek bazı ilginç değişiklikler olabilir:

x:

görüntü tanımını buraya girin

y:

görüntü tanımını buraya girin

z:

görüntü tanımını buraya girin

Y:

görüntü tanımını buraya girin

Keşke ilk üçte tek sıralara neyin sebep olduğunu bulabilseydim.


2
Bu garip çizgiler muhtemelen bir sıralama veya arama yönteminin önyargısıdır (ikili arama / quicksort?)
Mark Jeronimus

Aslında buradaki çizgileri gerçekten seviyorum.
Jason C,

11

Java

Bu çok daha iyi bir fikirdi. Bu çok kısa bir Java kodu; Ana yöntem sadece 13 satır uzunluğundadır:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author Quincunx
 */
public class AllColorImage {

    public static void main(String[] args) {
        BufferedImage img = new BufferedImage(4096, 4096, BufferedImage.TYPE_INT_RGB);

        for (int r = 0; r < 256; r++) {
            for (int g = 0; g < 256; g++) {
                for (int b = 0; b < 256; b++) {
                    img.setRGB(((r & 15) << 8) | g, ((r >>> 4) << 8 ) | b, (((r << 8) | g) << 8) | b);
                }
            }
        }
        try {
             ImageIO.write(img, "png", new File("Filepath"));
        } catch (IOException ex) {
            Logger.getLogger(AllColorImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

"Renk toplayıcıları" blokları oluşturur. Temel olarak, birinci blok, r=0, ikinci, r=1her blok içinde, vs. gile ilgili olarak artışlarla xve bile ilgili olarak y.

Gerçekten bitsel operatörleri severim. İfadeyi bozmama izin verin setRGB:

img.setRGB(((r & 15) << 8) | g, ((r >>> 4) << 8 ) | b, (((r << 8) | g) << 8) | b);

((r & 15) << 8) | g         is the x-coordinate to be set.
r & 15                      is the same thing as r % 16, because 16 * 256 = 4096
<< 8                        multiplies by 256; this is the distance between each block.
| g                         add the value of g to this.

((r >>> 4) << 8 ) | b       is the y-coordinate to be set.
r >>> 4                     is the same thing as r / 16.
<< 8 ) | b                  multiply by 256 and add b.

(((r << 8) | g) << 8) | b   is the value of the color to be set.
r << 8                      r is 8 bits, so shift it 8 bits to the left so that
| g                         we can add g to it.
<< 8                        shift those left 8 bits again, so that we can
| b                         add b

Bitsel operatörlerin bir sonucu olarak, bu işlemin tamamlanması sadece 7 saniye sürer. İle r & 15değiştirilirse r % 16, 9 saniye sürer.

4096 x 4096'yı seçtim

Çıktı (ekran görüntüsü, aksi takdirde çok büyük):

görüntü tanımını buraya girin

Serbest el-kırmızı daireler tarafından çizilen kötü sırıtarak çıktı:

görüntü tanımını buraya girin


2
Orijinali ilişkilendir, böylece geçerliliğini doğrulayabilirim (sayma renkleri)
Mark Jeronimus

2
Lol! Java kodunu çalıştırabileceğimi unuttum. İlk görüntü geçiyor ve ikinci görüntüyü çoğaltamıyorum (lol) ☺
Mark Jeronimus

16
Serbest el çevrelerinin hepsi diskalifiye olmuş aynı renge sahiptir. : P
Nick, T,

3
@ Quincunx +1 eğer korkutucu bir yüz çizebilir ve renk gereksinimlerini koruyabilirseniz!
Jason C,

2
@JasonC Cevabımı gör. Kredi ilham için Quincunx'a gidiyor.
Seviye Nehri St
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.