Rastgele siyah beyaz orman çizin


66

Göreviniz ormana benzeyen bir şeyle 800x600 siyah beyaz görüntü çizecek bir program yazmak.

Bunun gibi (dithered fotoğraf):

kurallar

  • Var olan görüntüleri kullanmanıza izin verilmez - tamamen algoritmik olarak görüntü üretmelisiniz
  • Yalnızca 2 renk kullanın - siyah beyaz (gri tonlamalı değil)
  • Her program çalıştığında görüntü yeni olmalı - her seferinde rastgele
  • Bir ağaç orman değildir (en az 5 ağaç diyelim)
  • Ağaç / orman çizmeye yarayan özel kütüphanelere izin verilmez
  • Çoğu oyla cevapla kazanır

9
Bu soru konu dışı görünüyor çünkü bir programlama yarışmasından ziyade bir sanat yarışması.
ProgramFOX

19
@ProgramFOX Programlama sanatı değil mi? :)
Somnium

15
Birincisi, bu zorluk için bazı girişler görmek istiyorum ve beklemeye alındığı için hayal kırıklığına uğradım.
Braden Best

3
Bu mücadeleyi seviyorum. Ruhu içinde olmayan cevaplar, o kadar fazla oylanmayacak, peki sorun ne?
cjfaure

3
@cjfaure Farklı amaçlar için, örneğin oyunlar için modeller ve görüntüler üretmek için.
Somnium

Yanıtlar:


98

C: 3863 1144 1023 999 942 927

Orijinal çözüm, çalışma başına 2 pnm dosya kaydeder (dithering'den önce g eklenmiş). Renk taklidi ilk birkaç satır için güzel olmadığından, gerekenden daha fazla satır oluşturmak ve çıktı sırasında kesmek için bir kesmek vardır.

Golf edilen çözüm daha basit bir renk geçişine sahiptir ve yalnızca renk alan görüntüyü kaydeder. (gcc -std = c11 -pedantic -Wall -Wextra ile uyarı yok)

3 orijinal program çalışmasından ve golf versiyonunun bir çalışmasından örnek görüntüler (son görüntü):

örnek 1 örnek 2 örnek 3 örnek 4

Golf versiyonu

  #include <math.h>
  #include <time.h>
  #include <stdlib.h>
  #include <stdio.h>
  #define D float
  #define R rand()/RAND_MAX
  #define Z(a,b,c) if(10.*R>a)T(h,s,j+b+c*R,g);
  #define U a[y][x]
  #define V e[y+1][x
  #define F(x) for(i=0;i<x;++i)
  int i,x,y,W=800,H=600;unsigned char a[600][800],c;D e[601][802],r,b,k,l,m,n,f,w,
  d,q=.01;void T(D h,D s,D j,D g){r=b=0;do{j+=.04*R-.02;h+=sin(j)*q;s+=cos(j)*q;b
  +=q;g+=q;f=525/d;r=.25-g/44;m=w*f+s*f+W/2;n=2*f-h*f+H/2;f*=r;for(y=n-f-2;y<n+f+2
  ;++y)if(y>=0&&y<H)for(x=m-f-2;x<m+f+2;++x)if(x>=0&&x<W)if(k=m-x,l=n-y,f>sqrt(k*k
  +l*l))if(U>d*3)U=d*3;}while(b<10*r+12*r*R&&r>q);if(r>q){Z(2,.26,.35)Z(2,-.26,-
  .35)Z(7,-.05,.1)}}int main(){FILE* o=fopen("i","wb");srand(time(0));F(W*H){y=i/W
  ;a[y][i%W]=(y<313)?255:6e3/(2*y-H);}F(200)w=1e2*R-60,d=80.*R+5,T(0,0,1.58,0);F(W
  *H){x=i%W;y=i/W;k=U+e[y][x+1];U=-(k>0);l=(k-U)*.1;e[y][x+2]+=l*4;V]+=l*2;V+1]+=l
  *3;V+2]+=l;}fprintf(o,"P5 800 600 255 ");fwrite(a,1,W*H,o);}

Orijinal versiyon

  #include <math.h>
  #include <stdio.h>
  #include <stdlib.h>

  #define W 800
  #define H 600
  #define SPEED 0.01
  #define HEIGHT 11.0

  #define R(m) ((double)(m) * rand() / RAND_MAX)
  #define RAD(deg) ((deg) / 180.0 * M_PI)
  #define LIMIT(x, min, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x))

  void shade(void);
  void growTree(double dist, double side, double h, double s, double alpha, double grown);
  void plot(double dist, double side, double h, double s, double alpha, double diam);
  void dither(void);
  void writeImg(int dither);

  unsigned char img[H+10][W];
  double err[H+10+2][W+4];
  long tim;

  int main(void)
  {
     int i;
     tim = time(0);
     srand(tim);
     shade();
     for(i = 0; i < 200; ++i)
     {
        growTree(5 + R(75), -60 + R(120), 0.0, 0.0, RAD(90), 0.0);
     }
     writeImg(0);
     dither();
     writeImg(1);
  }

  void shade(void)
  {
     int y;
     for(y = -10; y < H; ++y)
     {
        double dist = H * 3.5 / (2 * y - H);
        unsigned char color = dist / 80 * 255;
        if(y <= H / 2 || dist > 80) color = 255;
        memset(img[y+10], color, W);
     }
  }

  void growTree(double dist, double side, double h, double s, double alpha, double grown)
  {
     double diam, branchLength = 0.0;

     do
     {
        alpha += R(RAD(3)) - RAD(1.5);
        h += sin(alpha) * SPEED;
        s += cos(alpha) * SPEED;
        branchLength += SPEED;
        grown += SPEED;
        diam = (1.0 - grown / HEIGHT) * 0.5;
        plot(dist, side, h, s, alpha, diam);
     } while(branchLength < 5 * diam + R(6 * diam) && diam > 0.02);

     if(diam > 0.02)
     {
        int br = 0;

        if(R(10) > 2) br++,growTree(dist, side, h, s, alpha + RAD(15) + R(RAD(20)), grown);
        if(R(10) > 2) br++,growTree(dist, side, h, s, alpha - RAD(15) - R(RAD(20)), grown);
        if(R(10) < 2 || br == 0) growTree(dist, side, h, s, alpha - RAD(2.5) + R(RAD(5)), grown);
     }
  }

  void plot(double dist, double side, double h, double s, double alpha, double diam)
  {
     int x, y;
     double scale = H / 4.0 * 3.5 / dist;
     double x0 = side * scale + s * scale + W / 2.0;
     double y0 = H / 2.0 + 2.0 * scale - h * scale;
     diam *= scale;
     h *= scale;
     s *= scale;
     for(y = y0 - diam / 2 - 2; y < y0 + diam / 2 + 2; ++y)
     {
        if(y < -10 || y >= H) continue;
        for(x = x0 - diam / 2 - 2; x < x0 + diam / 2 + 2; ++x)
        {
           double dx, dy, d;
           if(x < 0 || x >= W) continue;
           dx = x0 - x;
           dy = y0 - y;
           d = diam / 2 - sqrt(dx * dx + dy * dy) + 0.5;
           if(d > 0)
           {
              unsigned char color = dist / 80 * 255;
              if(img[y+10][x] > color) img[y+10][x] = color;
           }
        }
     }
  }

  void dither(void)
  {
     int x0, x, y;
     for(y = -10; y < H; ++y)
     {
        for(x0 = 0; x0 < W; ++x0)
        {
           double error, oldpixel;
           unsigned char newpixel;
           if(y%2) x = W - 1 - x0;
           else x = x0;
           oldpixel = img[y+10][x] + err[y+10][x+2];
           newpixel = oldpixel > 127 ? 255 : 0;
           img[y+10][x] = newpixel;
           error = oldpixel - newpixel;
           err[y+10  ][x+1+2*(1-y%2)] += error * 7 / 48;
           err[y+10  ][x+4*(1-y%2)] += error * 5 / 48;
           err[y+10+1][x  ] += error * 3 / 48;
           err[y+10+1][x+1] += error * 5 / 48;
           err[y+10+1][x+2] += error * 7 / 48;
           err[y+10+1][x+3] += error * 5 / 48;
           err[y+10+1][x+4] += error * 3 / 48;
           err[y+10+2][x  ] += error * 1 / 48;
           err[y+10+2][x+1] += error * 3 / 48;
           err[y+10+2][x+2] += error * 5 / 48;
           err[y+10+2][x+3] += error * 3 / 48;
           err[y+10+2][x+4] += error * 1 / 48;
        }
     }
  }

  void writeImg(int dither)
  {
     FILE* fp;
     char buffer[32];
     sprintf(buffer, "%ld%s.pnm", tim, dither ? "" : "g");
     fp = fopen(buffer, "wb");
     fprintf(fp, "P5\n%d %d\n255\n", W, H);
     fwrite(&img[10][0], 1, W * H, fp);
     fclose(fp);
  }

3
+1. Güzel fotoğraflar. Neyse, bu popülerlik yarışması, kod golf değil. Yani, golf oynamaya gerek yok. :)
Vectorized

2
İyi görünüyor, benzer bir fikrim vardı ama çok tembeldim =) Şubelerin özyineleme derinliğini randomize etmeye çalışabileceğinizi düşünüyorum, bunun daha da doğal görüneceğini düşünüyorum.
kusur

3
Golf oynamak zorunda kalmadığımı biliyorum, ama bu benim için en eğlenceli kısım!
Manuel Kasten

2
Bu muhteşem.
Quentin

12
Ayrıca, sepya tonuna değiştirilmemiş bir versiyonunu koydum - muhteşem! Buraya bakın: i.imgur.com/lCrJCp7.jpg
DreamWarrior

42

Java Ormanı

(954 golf oynadı)

Derin, bükümlü çalılıklarla doludur, bu kolay geçmeyen bir ormandır.

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

Temelde yavaşça daralan, kıvrılan sarmaşıkların olduğu fraktal rastgele bir yürüyüş. 75 tanesini çiziyorum, yavaş yavaş arkadan beyaza, siyahtan öne doğru değişiyor. Sonra utanmadan İbn Rüşd'ün kodunu adapte, her şeyi Titrek burada bunun için.

Golf: (Sadece diğerleri karar verdi çünkü)

import java.awt.*;import java.awt.image.*;import java.util.*;class P{static Random rand=new Random();public static void main(String[]a){float c=255;int i,j;Random rand=new Random();final BufferedImage m=new BufferedImage(800,600,BufferedImage.TYPE_INT_RGB);Graphics g=m.getGraphics();for(i=0;i++<75;g.setColor(new Color((int)c,(int)c,(int)c)),b(g,rand.nextInt(800),599,25+(rand.nextInt(21-10)),rand.nextInt(7)-3),c-=3.4);for(i=0;i<800;i++)for(j=0;j<600;j++)if(((m.getRGB(i,j)>>>16)&0xFF)/255d<rand.nextFloat()*.7+.05)m.setRGB(i,j,0);else m.setRGB(i,j,0xFFFFFF);new Frame(){public void paint(Graphics g){setSize(800,600);g.drawImage(m,0,0,null);}}.show();}static void b(Graphics g,float x,float y,float s,float a){if(s>1){g.fillOval((int)(x-s/2),(int)(y-s/2),(int)s,(int)s);s-=0.1;float n,t,u;for(int i=0,c=rand.nextInt(50)<1?2:1;i++<c;n=a+rand.nextFloat()-0.5f,n=n<-15?-15:n>15?15:n,t=x+s/2*(float)Math.cos(n),u=y-s/2*(float)Math.sin(n),b(g,t,u,s,n));}}}

Sane orijinal kodu:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;

public class Paint {

    static int minSize = 1;
    static int startSize = 25;
    static double shrink = 0.1;
    static int branch = 50;
    static int treeCount = 75;

    static Random rand = new Random();
    static BufferedImage img;

    public static void main(String[] args) {
        img = new BufferedImage(800,600,BufferedImage.TYPE_INT_ARGB);
        forest(img);
        dither(img);
        new JFrame() {
            public void paint(Graphics g) {
                setSize(800,600);
                g.drawImage(img,0,0,null);
            }
        }.show();
    }

    static void forest(BufferedImage img){
        Graphics g = img.getGraphics();
        for(int i=0;i<treeCount;i++){
            int c = 255-(int)((double)i/treeCount*256);
            g.setColor(new Color(c,c,c));
            tree(g,rand.nextInt(800), 599, startSize+(rand.nextInt(21-10)), rand.nextInt(7)-3);
        }
    }

    static void tree(Graphics g, double x, double y, double scale, double angle){
        if(scale < minSize)
            return;
        g.fillOval((int)(x-scale/2), (int)(y-scale/2), (int)scale, (int)scale);
        scale -= shrink;
        int count = rand.nextInt(branch)==0?2:1;
        for(int i=0;i<count;i++){
            double newAngle = angle + rand.nextDouble()-0.5;
            if(newAngle < -15) newAngle = -15;
            if(newAngle > 15) newAngle = 15;
            double nx = x + (scale/2)*Math.cos(newAngle);
            double ny = y - (scale/2)*Math.sin(newAngle);
            tree(g, nx, ny, scale, newAngle);
        }
    }

    static void dither(BufferedImage img) {
        for (int i=0;i<800;i++)
            for (int j=0;j<600;j++) {
                double lum = ((img.getRGB(i, j) >>> 16) & 0xFF) / 255d;
                if (lum <= threshold[rand.nextInt(threshold.length)]-0.2)
                    img.setRGB(i, j, 0xFF000000);
                else
                    img.setRGB(i, j, 0xFFFFFFFF);
            }
    }

    static double[] threshold = { 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31,
            0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42,
            0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53,
            0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64,
            0.65, 0.66, 0.67, 0.68, 0.69 };

}

Bir tane daha? Tamam! Bu dithering biraz ayarlanmış, bu yüzden önündeki siyahlar çok daha düz.

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

Ne yazık ki, dither asma katmanlarının ince detaylarını göstermiyor. İşte sadece karşılaştırma amacıyla, gri tonlamalı bir sürüm:

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


1
Güzel. Kodumun yardımcı olması sevindim;)
Averroes

1
Titreşimin gerekli olduğu kuralların hiçbir yerinde okudum. Bence ayrılmamış versiyon daha güzel görünüyor.
Lars Ebert

4
@Lars dithering gerekli değildir, AMA: sadece siyah ve beyaz kullanılabilir, gri değerlere izin verilmez ....
Manuel Kasten

31

Javascript + HTML - golf oynadı

@Manuel Kansten algoritmasının bir javascript tasviri - bu ağaçların ne kadar iyi göründüğü şaşırtıcı.

Sadece farklı bir şey yapmak için görüntüyü renkli çizerim, sonra son adımda s / b'ye dither.

Nedenini bilmiyorum ama ormanım daha az karanlık ve Manuel'inkine göre daha az korkutucu.

JSfiddle ile test edin veya aşağıdaki yeni Snippet'i çalıştırın . Bu hızlı değil. Sabırlı olun ve ormanın büyümesini izleyin.

Orman 1 Orman 1 rengi

Orman 2 Orman 2 rengi

W=800
H=600
canvas.width = W;
canvas.height = H;

var ctx = canvas.getContext("2d");

R=function(m) { return m * Math.random()};
RAD=function(deg) { return deg / 180 * Math.PI};
LIMIT=function(x, min, max) {return x < min ? min : x > max ? max : x};
var SPEED = 0.01, HEIGHT = 11.0;

// Ground
var grd = ctx.createLinearGradient(0,0,0,H);
grd.addColorStop(0,"#88ccff");
grd.addColorStop(0.45,"#ffffee");
grd.addColorStop(0.5,"#80cc80");
grd.addColorStop(1,"#001100");
ctx.fillStyle = grd;
ctx.fillRect(0,0, W,H);


Plot = function(dist, side, h, s, alpha, diam)
{
    var x, y, a1,a2,scale = H/4 * 3.5 / dist, 
        x0 = side * scale + s * scale + W/2,
        y0 = H/2 + 2.5*scale - h*scale;
    
    k = dist
    if (diam > 0.05) {
        red = k*3|0;     
        green = k|0;
        a1=alpha+1
        a2=alpha-1
    }
    else
    {
        green= 80+(1-diam)*k*2|0;
        red = k|0;
        a1=0;
        a2=2*Math.PI;
    }
    diam *= scale;
    h *= scale;
    s *= scale;
    ctx.beginPath();
    ctx.arc(x0,y0,diam/2, a1,a2);//lpha-1, alpha+1);//0,2*Math.PI);
    ctx.fillStyle = 'rgb('+red+','+green+',0)';
    ctx.fill();
}

Grow = function(dist, side, h, s, alpha, grown)
{
    var diam, branchLength = 0.0;
    diam = (1.0 - grown / HEIGHT) * 0.5;
    do
    {
        alpha += R(RAD(3)) - RAD(1.5);
        h += Math.sin(alpha) * SPEED;
        s += Math.cos(alpha) * SPEED;
        branchLength += SPEED;
        grown += SPEED;
        diam = (1.0 - grown / HEIGHT) * 0.5;
        Plot(dist, side, h, s, alpha, diam);
    } while(branchLength < 5 * diam + R(6 * diam) && diam > 0.02);

    if (diam > 0.02)
    {
        var br = 0;

        if(R(10) > 2) br++,Grow(dist, side, h, s, alpha + RAD(15) + R(RAD(20)), grown);
        if(R(10) > 2) br++,Grow(dist, side, h, s, alpha - RAD(15) - R(RAD(20)), grown);
        if(R(10) < 2 || br == 0) Grow(dist, side, h, s, alpha - RAD(2.5) + R(RAD(5)), grown);
    }
}

trees=[]
for(i = 0; i < 300; ++i) trees.push({ z: 1+R(70), s:R(120)-60 });
trees.sort( function (a,b) { return a.z - b.z} );

Draw = function()
{
    t = trees.pop();
    if (t)
    {
        Grow(t.z, t.s, 0, 0, RAD(90), 0);
        setTimeout(Draw, 100);
    }
    else 
    {
        var e,c,d,p,i,l, img = ctx.getImageData(0,0,W,H);
        l = img.data.length;
        for (i = 0; i < l-W*4-4; i+=4)
        {
            c = (img.data[i]+img.data[i+1])/2|0
            c = img.data[i]
            d = c > 120 + R(16) ? 255 : 0
            e = c - d;
            img.data[i]=img.data[i+1]=img.data[i+2]=d
            c = (img.data[i+4]+img.data[i+5])/2|0
            
            c = LIMIT(c + ((e*7)>>4),0,255)
            img.data[i+4]=img.data[i+5]=img.data[i+6]=c
            p = i+W*4
            c = (img.data[p-4]+img.data[p-3])/2|0
            c = LIMIT(c + ((e*3)>>4),0,255)
            img.data[p-4]=img.data[p-3]=img.data[p-2]=c
            c = (img.data[p]+img.data[p+1])/2|0
            c = LIMIT(c+ ((e*5)>>4),0,255)
            img.data[p]=img.data[p+1]=img.data[p+2]=c
            c = (img.data[p+4]+img.data[p+5]*2)/3|0
            c = LIMIT(c + (e>>4),0,255)
            img.data[p+4]=img.data[p+5]=img.data[p+6]=c
    
        }
        bwcanvas.width = W;
        bwcanvas.height = H;
        var bwx = bwcanvas.getContext("2d");
        bwx.putImageData(img,0,0);
    }
}

setTimeout(Draw, 10);
<canvas id='bwcanvas'  width="2" height="2"></canvas>
<canvas id='canvas'  width="2" height="2"></canvas>


2
Bu yer sanırım. Manuel'in ağaçları toprağa karışarak puslu ve bulanık bir görünüm oluşturur. Yer düzleminiz daha hafiftir, daha yüksek kontrastlı daha havadar bir görünüm verir. Ayrıca, düz renkli gökyüzü ve Manuel'in resimlerindeki mesafe soluyor, bulanık bir sis veya pus görüntüsü oluşturmanıza yardımcı olur. (Dikkat edin, resimlerinizin farklı görünmesini tercih ederim.)
Ilmari Karonen

Evet, bu Manuel'in derin ormanlarına bir meyve bahçesi.
shadowtalker

23

Bağlamsız Sanat 3 (1133)

CF bir vektör grafik oluşturma dilidir, bu nedenle anti-alising'den kaçınamıyorum. Bunu aynı yerde birkaç (değişken N) kez kare çizerek çalıştım . Sis rastgele yerlere küçük kareler çizerek yapılır.

startshape main

W = 80*0.6
H = 60*0.6

N = 3

CF::Background = [ b -1 ]
CF::Size = [ x 0 y -20 s W H ]
CF::Color = 0
CF::ColorDepth = 16
CF::MinimumSize = 0.6

shape main {
  transform [ z 0 y (H/2) b 1 ]
  loop 30 [ z -1 y -2 ] {
    loop 200000 []
      SQUARE1 [ s (0.1/3) x -W..W y -H..H z -0.5..0.5 ]
  }

  transform [ b -1 z 3 ]
  loop 14 [[ s 1.1 y -0.8..-1 s 0.6 z -3 ]] {
    loop 14 [] tree [ x (-30..-20) z (-3..3) ]
    loop 14 [] tree [ x (20..30) z (-3..3) ]
  }
}

shape tree {
  branch [ ]
}

shape branch
rule 7 {
  transform [ s (1..2) 1]
  SQUARE1 [ ]

  branch [ y (0.2..0.3) x (-0.05..0.05) s 0.994 r (-6..6) z (-0.3..0.3)  ]
  branch1 [ b 0.001 z -2 r -20..20 ]
}
rule 0.001 { }
rule 0.3 { branch [ r 4..20 ] }
rule 0.3 { branch [ r -4..-20 ] }

shape branch1
rule 90 { }
rule { branch [ r -22..22 s 0.8..1 ] }

path SQUARE1 {
  MOVETO( 0.5,  0.5)
  LINETO(-0.5,  0.5)
  LINETO(-0.5, -0.5)
  LINETO( 0.5, -0.5)
  CLOSEPOLY()
  loop N [] FILL()[]
}

shape S {
  SQUARE [ a -1 ]
  loop 1000 [ ] SQUARE [ x (-0.5..0.5) y (-0.5..0.5) s 0.01..0.001 ]
}

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

Farklı sayılar kullanarak daha fazla render 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
Hiçbir taklit seçeneğinin olmadığını anladım, ancak çıktı yalnızca siyah / beyaz olmalı.
Geobits

1
Takılmanın yolunu bulamaz mısın? Olduğu gibi, geçerli bir cevap değil.
edc65

1
Titreşim yapmak zorunda değilsiniz, ancak sadece 2 renk kullanmak zorundasınız - siyah ve beyaz. Gri tonlama kullanımı kurallara uymuyor. Soru belirsizliği ortadan kaldırmak için düzenlendi. Bunu elde etmek için bazı yöntemleri kullanmanızı öneririm (taklit olsun ya da olmasın), böylece cevabınızı çok daha fazla indirme gelmeden önce düzenleyebilirsiniz.
trichoplax

Yardımcı olabileceği bir öneri gibi: Siyah beyaz görüntüyü elde etmek için mevcut şeffaf dikdörtgen yaklaşımınızı kullanabilirsiniz; kısmi saydamlık yerine, tam saydamlığı bir tür ızgara deseninde kullanın, böylece yalnızca her diğer ızgara hücresi şeffaftır.
trichoplax

1
Bu şimdi, sorunun özünde olmak için çok daha yakın.
trichoplax

19

C: 301

Bu program, PGM formatında basit, soyut bir görüntü oluşturur . GIMP ile açabilirsiniz.

int x,y,i,d,w;srand(time(NULL));unsigned char p[480000];FILE *f=fopen("a.pgm","w");fprintf(f,"P5\n800 600\n1\n");i=480000;while(i--)p[i]=i>240000|(i%800+i/800&3)!=0;i=100;while(i--){d=(11000-i*i)/99;y=300+1100/d;x=rand()%800;while(y--){w=300/d;while(w--)p[y*800+w+x]=0;}}fwrite(p, 1, 480000, f);fclose(f);

İşte bir örnek çalışma:Oluşturulan görüntü


34
Bu bir ormandan çok bir barkoda benziyor :)
Sylwester

6
baş aşağı bartree orman
Fabricio

5
Aşağı kaydırırken tarayıcımın görüntüyü doğru şekilde oluşturamadığını düşündüm. Barkod tarayıcı ile taranan barmenleriniz bu zorluğun URL'sini verirse size bir ton bonus puanı veririm. Bunun dışında rastgele bir orman olmazdı.
nwp

6
Taradım ve barkod tarayıcım bana küfretti. teşekkür ederim.
PlazmaHH,

1
@nwp Yine de bir UPC veritabanından rastgele bir kod kapabilirsiniz . Taranabilir henüz rastgele :)
Geobits

18

JAVA ile IFS

Bu çözüm, bir (proto) ağacı tanımlamak için bir İterasyon Fonksiyon Sistemi (IFS) kullanır. IFS 100 kez uygulanır (= orman). Her ağaç boyanmadan önce (ormana dikilir) IFS hafifçe yerinde değişir (rastgele yürüyüş tarzı). Böylece her ağaç biraz farklı görünüyor.

Resimler rastgele tohumlardandır:

  • -824737443
  • -1220897877
  • -644492215
  • 1133984583

Titreşime gerek yok.

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;

public class IFS {
    static Random random=new Random();
    static int BLACK = 0xff000000;
    static int treeCount = 100;
    static Random rand = new Random();
    static int Height = 600;
    static int Width = 800;
    static BufferedImage img = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_ARGB);

    static double[][] ifs=new double[][] {//Tree 3 {; Paul Bourke  http://ecademy.agnesscott.edu/~lriddle/ifskit/gallery/bourke/bourke.ifs
       {0.050000,  0.000000,  0.000000,  0.600000,  0.000000,  0.000000,  0.028000},
       {0.050000,  0.000000,  0.000000, -0.500000,  0.000000,  1.000000,  0.023256},
       {0.459627, -0.321394,  0.385673,  0.383022,  0.000000,  0.600000,  0.279070},
       {0.469846, -0.153909,  0.171010,  0.422862,  0.000000,  1.100000,  0.209302},
       {0.433013,  0.275000, -0.250000,  0.476314,  0.000000,  1.000000,  0.555814 /*Paul Bourke has: 0.255814*/},
       {0.421325,  0.257115, -0.353533,  0.306418,  0.000000,  0.700000,  0.304651 /*Paul Bourke has: 0.204651*/},
    };

    public static void main(String[] args) {
        int seed=random.nextInt();
        //seed=-1220897877;
        random=new Random(seed);
        for (int t = 0; t < treeCount; t++) {
            for (int i = 0; i < ifs.length; i++) {
                for (int j = 0; j < ifs[0].length; j++) {
                    ifs[i][j]=R(ifs[i][j]);
                }
            }
            tree(random.nextDouble(), 0.1*random.nextDouble());
        }
        JFrame frame = new JFrame(""+seed) {
            public void paint(Graphics g) {
                setSize(800,600);
                g.drawImage(img,0,0,null);
            }
        };
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static void tree(double x0, double dist) {
        double y0=Math.atan(dist+0.01);
        double scale=Math.atan(0.01)/y0;
        double x=0;
        double y=0;
        for (int n = 0; n < 200000/Math.pow(20*dist+1, 8); n++) {
            int k = select(ifs);
            double newx=ifs[k][0]*x + ifs[k][1]*y + ifs[k][2];
            double newy=ifs[k][3]*x + ifs[k][4]*y + ifs[k][5];
            x=newx;
            y=newy;
            newx= Width*(0.5*scale*newx+x0);
            newy= Height*((1-0.5*scale*newy)-y0-0.1);
            if (0<=newx && newx<Width && 0<=newy && newy<Height) {
                img.setRGB((int)newx, (int)newy, BLACK);
            }
        }
    }

    private static double R(double x) {
        return (1+ 0.01*random.nextGaussian())*x;
    }

    private static int select(double[][] ifs) {
        int k;
        double sum=0;
        for(k=0; k<ifs.length; k++) {
            sum+=ifs[k][6];
        }
        double r=sum*random.nextDouble();
        sum=ifs[0][6];
        for(k=0; k<ifs.length-1 && r>sum; k++) {
            sum+=ifs[k+1][6];
        }
        return k;
    }
}

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


Son görüntüler en iyi şekilde görünür. Ancak bence daha az ağaç denemelisiniz, çünkü artık her zaman tanınmayan siyah bir alan var, ancak kenarlarda daha iyi görünüyor.
Somnium

"Güzellik bakanın gözlerindedir." Çok fazla varyasyon test ettim. Sonunda treeCount = 100 ile geldim. Diğer herkes benim çözümümü kopyalayıp değiştirebilir.
Bob Genom

15

Burada belirgin bir kozalaklılık eksikliği olduğunu fark ettim, bu yüzden Python'da birlikte bir şey hackledim.

from PIL import Image
import random

#Generates the seed for a tree
def makeSeed(y):
    random.seed()
    seed_x = random.randint(10, 590)
    seed_y = y
    width = random.randint(5, 10)
    height = random.randint(width*5, width*30)

    return (seed_x, seed_y, width, height)

#Grows the vertical components
def growStems(seed_data, pixel_field):
    seed_x = seed_data[0]
    seed_y = seed_data[1]
    width = seed_data[2]
    height = seed_data[3]
    for x in range(seed_x, seed_x+width):
        for y in range(seed_y-height, seed_y):
            pixel_field[x][y] = (0, 0, 0)
            #Dithering
            if seed_y > 300 and seed_y < 320:
                if (x+y)%2==0:
                    pixel_field[x][y] = (255, 255, 255)
            elif seed_y >= 320 and seed_y < 340:
                if (x+y)%4==0:
                    pixel_field[x][y] = (255, 255, 255)
            elif seed_y >= 340 and seed_y < 360:
                if (x+y)%8==0:
                    pixel_field[x][y] = (255, 255, 255)

    return pixel_field

#Grows the horizontal components
def growBranches(seed_data, pixel_field):
    seed_x = seed_data[0]
    seed_y = seed_data[1]
    width = seed_data[2]
    height = seed_data[3]
    branch_height = seed_y-height
    branch_width = width
    branch_length = 2
    max_prev = branch_length
    branches = []
    while(branch_height >= seed_y-height and branch_height < seed_y-(3*width) and branch_length < height/3):
        branches.append((branch_height, branch_width, branch_length))
        branch_height+= 4
        branch_length+=2
        #Gives the conifer unevenness to make it look more organic
        if random.randint(0,110) > 100 and branch_length > max_prev:
            max_prev = branch_length
            branch_length -= branch_length/4
    max_length = height/3


    for x in range(seed_x-max_length, seed_x+max_length):
        for y in range(seed_y-height, seed_y):
            for branch in branches:
                bh = branch[0]
                bw = branch[1]
                bl = branch[2]
                #Establishing whether a point is "in" a branch
                if x >= seed_x-bl+(width/2) and x <= seed_x+bl+(width/2):
                    if x > 1 and x < 599:
                        if y >= bh-(bw/2) and y <= bh+(bw/2):
                            if y < 400 and y > 0:
                                pixel_field[x][y] = (0, 0, 0)
                                #Dithering
                                if seed_y > 300 and seed_y < 320:
                                    if (x+y)%2==0:
                                        pixel_field[x][y] = (255, 255, 255)
                                elif seed_y >= 320 and seed_y < 340:
                                    if (x+y)%4==0:
                                        pixel_field[x][y] = (255, 255, 255)
                                elif seed_y >= 340 and seed_y < 360:
                                    if (x+y)%8==0:
                                        pixel_field[x][y] = (255, 255, 255)

    return pixel_field


def growTrees(n):
    pixel_field = [[(255, 255, 255) for y in range(400)] for x in range(600)]
    #Create the ground
    for i in range(600):    
        for j in range(400):
            if pixel_field[i][j]==(255,255,255) and j > 300:
                if (i+j)%2 == 0:
                    pixel_field[i][j]=(0,0,0)
    seed_ys=[]
    #Generates seeds for the trees and orders them back to front to make the dithering work
    for t in range(n):
        seed_ys.append(random.randint(300,390))
    seed_ys.sort()

    for s in range(len(seed_ys)):
        seed= makeSeed(seed_ys[s])
        pixel_field = growStems(seed, pixel_field)
        pixel_field = growBranches(seed, pixel_field)
    return pixel_field

def makeForest():
    forest = growTrees(25)
    img = Image.new( 'RGB', (600,400), "white") # create a new black image
    pixels = img.load() # create the pixel map
    for i in range(img.size[0]):    # for every pixel:
        for j in range(img.size[1]):
            if pixels[i,j]==(255,255,255) and j > 300:
                if (i+j)%2 == 0:
                    pixels[i,j]=(0,0,0)
            pixels[i,j] = forest[i][j] # set the colour accordingly

    img.save("Forest25.jpg")

if __name__ == '__main__':
    makeForest()

5 ağaçlı orman 10 ağaçlı orman 25 ağaçlı orman

Bu benim ilk Code Golf'umdu, çok eğlenceliydi!


1
İyi görünüyor! Bunu sevdim.
TonySniper

5

Bu cevap umduğum kadar iyi değil, ancak üzerinde çalıştığım daha 3D bir fikre atılan bir taş, ve aslında hangi ağaçların kaynak aldığını taklit etme fikrini gerçekten seviyorumgörüntü tanımını buraya girin

package forest;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Forest extends Canvas{
    private int[] heights = new int[800];
    private BufferedImage buffered_image;
    File outputFile = new File("saved.png");
    Random r = new Random();
    public Forest() {
        buffered_image = new BufferedImage(800, 600,
                BufferedImage.TYPE_INT_RGB);
        for( int j = 0; j < 800; j++){
            heights[j] = -10000;
            for(int k = 0; k < 600; k++){
                buffered_image.setRGB(j, k, 0xFFFFFF);
            }
        }
        for(int i = 0; i < 7; i ++){
            heights[r.nextInt(800)] = 0;
        }

        this.setPreferredSize(new Dimension(800, 600));
        this.setSize(new Dimension(800, 600));
        for( int i = 0; i < 200000; i++){
            int x = r.nextInt(798) + 1;
            heights[x] =  Math.min(599, heights[x - 1] == heights[x + 1] ? heights[x] : Math.max(Math.max(heights[x - 1], heights[x]),heights[x + 1]) + 1);
            buffered_image.setRGB(x, Math.min(599, 600 - heights[x]), 0);
        } 

        try {

            ImageIO.write(buffered_image, "png", outputFile);
        } catch (IOException e) {

        }
        update();
    }
    public void repaint(){
        if(this.getGraphics() != null)
        paint(this.getGraphics());
    }


    public void paint(Graphics g) {
        g.drawImage(buffered_image, 0, 0, this);
    }

    public void update() {  
        repaint();
    }

    public static void main(String[] args) throws IOException {
        JFrame main_frame = new JFrame();
        main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel top_panel = new JPanel();
        top_panel.setLayout(new BorderLayout());
        Forest s = new Forest();
        top_panel.add(s, BorderLayout.CENTER);
        main_frame.setContentPane(top_panel);

        main_frame.pack();
        main_frame.setVisible(true);
    }

}

6
Belki köknar ağaçlarına benzetmek için dikey olarak döndürürsünüz?
Somnium
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.