कंप्यूटर जनित दरार


43

एक प्रोग्राम लिखें जो 0 से 65535 (2 16 -1) तक पूर्णांक में होता है और एक अद्वितीय 500 × 500 पिक्सेल छवि उत्पन्न करता है जो दरार वाली मिट्टी के इन 6 वास्तविक जीवन चित्रों के समान संभव होता है:

फटा हुआ मिट्टी का नमूना 1 फटा हुआ मिट्टी का नमूना २ फटा मिट्टी का नमूना 3 फटा मिट्टी का नमूना 4 फटा हुआ मिट्टी का नमूना ५ फटा मिट्टी का नमूना 6
ये थंबनेल हैं, पूर्ण-आकार के 500 × 500 चित्र देखने के लिए उन्हें क्लिक करें।

यहां लक्ष्य आपके कंप्यूटर द्वारा तैयार की गई छवियों को संभव के रूप में फोटोरिअलिस्टिक बनाना है । इसलिए आदर्श रूप से, यदि आपके कार्यक्रम के किसी भी चित्र आउटपुट को ऊपर की 6 छवियों के साथ मिलाया गया है, तो पहली बार छवियों को देखने वाला कोई व्यक्ति वास्तविक रूप से अलग कंप्यूटर उत्पन्न नहीं कर पाएगा।

परफेक्ट फोटोरैलिज्म हालांकि मुश्किल है, इसलिए बस आप जो कर सकते हैं, उसे बेहतरीन तरीके से करें। यह एक इसलिए अधिक यथार्थवादी आउटपुट वाले उत्तर अधिक उत्कीर्ण किए जाएंगे और जीतने की संभावना अधिक होगी।

नियम

  • आप छवि प्रसंस्करण कार्यों या पुस्तकालयों का उपयोग कर सकते हैं।

  • 6 नमूना चित्रों से एकत्रित जानकारी पर आप अपने एल्गोरिथ्म को आधार बना सकते हैं, लेकिन आपकी 65536 (2 16 ) संभावित आउटपुट छवियां एक दूसरे से और नमूना चित्रों से दृष्टिगत रूप से अलग होनी चाहिए , खासकर दरार की व्यवस्था के संबंध में। आपको वास्तव में अपनी छवियां उत्पन्न करनी चाहिए, न कि केवल एक चित्र से चयन करें और घुमाएं।

  • आपको अन्यथा अपने आउटपुट को हार्डकोड नहीं करना चाहिए। एक सामान्य एल्गोरिथ्म का उपयोग किया जाना चाहिए और 65535 से बड़ी संख्या को सैद्धांतिक रूप से वैध आउटपुट का उत्पादन करना चाहिए। (मैंने इसे केवल छोटे-अधिकतम पूर्णांक प्रकारों को समायोजित करने के लिए प्रतिबंधित किया है।)

  • इनपुट पूर्णांक को एक बीज के रूप में सोचा जा सकता है, जिसके परिणामस्वरूप यादृच्छिक दरार वाली मिट्टी का उत्पादन छवि होता है। यह हालांकि नियतात्मक होना चाहिए, इसलिए एक ही इनपुट हमेशा एक ही आउटपुट में परिणाम होना चाहिए।

  • आउटपुट चित्र बिल्कुल 500 × 500 पिक्सेल के होने चाहिए।

  • आउटपुट छवियों को किसी भी सामान्य छवि फ़ाइल प्रारूप में सहेजा जा सकता है, या बस प्रदर्शित किया जा सकता है।

  • अपने उत्तर में कुछ उदाहरण आउटपुट छवियों और उनके संबंधित इनपुट नंबरों को शामिल करना सुनिश्चित करें।

  • सबसे ज्यादा वोटों के साथ जवाब मिला। मतदाताओं को निश्चित रूप से उन उत्तरों को उखाड़ फेंकना चाहिए जो 6 नमूनों के समान छवियों का उत्पादन करने का प्रयास करते हैं, और उत्तर तोड़ते हैं जो नियमों को तोड़ते हैं या असंगत परिणाम देते हैं।

6 नमूना छवियां बनावटलिब.कॉम से ली गई थीं । 1000 × 1000 पिक्सेल क्षेत्र चयन दरार वाली मिट्टी की दो बड़ी छवियों से लिया गया और फिर 500 × 500 का आकार दिया गया। आप अपने कार्यक्रम में इन बड़ी छवियों से विश्लेषण का उपयोग कर सकते हैं, लेकिन आउटपुट को विशेष रूप से 6 चुने हुए नमूना छवियों का अनुकरण करना चाहिए।


6
मैंने इस चुनौती को बहुत व्यापक के रूप में बंद करने के लिए मतदान किया है क्योंकि इसमें उद्देश्य वैधता मानदंडों का अभाव है
AdmBorkBork

4
@HelkaHomba एक पुरानी चुनौती को अच्छी तरह से प्राप्त किया गया था या नहीं, इस बात पर असर नहीं होना चाहिए कि क्या एक चुनौती अब साइट के नियमों के अनुरूप है जैसा कि आम सहमति से तय किया गया है। पिछले महीनों में पॉपकॉन्स की जबरदस्त चर्चा हुई है, एक परिणाम यह था कि सभी पॉपकॉन को एक उद्देश्य वैधता मानदंड की आवश्यकता है। इस चुनौती में ऐसा नहीं है। इस प्रकार, यह बहुत व्यापक है।
AdmBorkBork

15
पॉप विपक्ष के बारे में मौजूदा नियम इतने गूंगे हैं कि मैं उन्हें अनदेखा करने और यह देखने का मौका देता हूं कि यह कैसे काम करता है। इस विषय को मेटा पर लाया गया है जहाँ इसकी मृत्यु पर चर्चा की जाती है लेकिन वास्तव में कुछ भी नहीं बदलता है, इसलिए मुझे लगता है कि ऐसा होने का सबसे अच्छा मौका कुछ पॉप विपक्ष रखने और यह देखने के लिए है कि वे कैसे करते हैं।
xnor

6
यहाँ उद्देश्य वैधता मानदंड "अद्वितीय" (अन्य 65535 से अलग) और "500x500 पिक्सेल" हैं। उदाहरण छवियों के समान उद्देश्य को परिभाषित नहीं किया जा सकता है, या यह एक लोकप्रियता प्रतियोगिता नहीं बल्कि एक कोड चुनौती होगी।
ट्राइकोप्लाक्स

14
मैं बिना किसी प्रतिबंध के साथ "कुछ सुंदर बनाऊं" जैसे खराब पॉप विपक्ष को देखता हूं, और "पॉप इस स्पेसिफिकेशन" जैसे मनुष्यों के साथ अच्छा पॉप विपक्ष है, जिस पर सबसे अच्छा मिलान होता है। मैं निश्चित रूप से इस चुनौती को अच्छी तरह से देखता हूं।
ट्राइकोप्लाक्स

जवाबों:


30

मेथेमेटिका

एक वोरोनोई आरेख विकिपीडिया से इस तरह दिखता है, जिसमें 19 कोशिकाएं दिखाई देती हैं, जिनमें से प्रत्येक में एक एकल बीज बिंदु होता है। एक सेल में उन बिंदुओं का सबग्रेशन होता है, जो संबंधित जेनरेटिंग पॉइंट अन्य सीड पॉइंट्स की तुलना में करीब होता है।

voronoi

नीचे दिया गया कोड 80 यादृच्छिक बिंदुओं ((-1, -1) और (1,1) से घिरा वर्ग क्षेत्र) से एक आरेख उत्पन्न करता है।

यह बहुभुज में (3 डी में) निर्माण के लिए आरेख में बहुभुज आदिम (2 डी में) का उपयोग करता है। कल्पना करें कि प्रत्येक बहुभुज, उसके नीचे, स्वयं का एक अनुवाद (-.08 z में) है। पॉलीहेड्रोन के ऊपरी और निचले चेहरे के रूप में दो बहुभुज के बारे में सोचो। "साइड चेहरों" को पॉलीहेड्रॉन को पूरा करने के लिए जोड़ा जाता है।

प्रत्येक पॉलीहेड्रन को तब छवि के केंद्र से, एक्स प्लेन पर, बाहर की ओर अनुवादित किया जाता है; यह बीच से हट जाता है। अनुवाद का परिमाण सीधे पॉलीहेड्रॉन के मूल उत्पादक यादृच्छिक बिंदु और स्क्रीन के केंद्र के बीच की दूरी के साथ भिन्न होता है। एक्स प्लेन में पॉलीहेड्रा के इस "फैलने" के परिणामस्वरूप दरारें होती हैं।

crackedMud[1]

एक

crackedMud[65535]

अंतिम

कोड

ClearAll[polyhedronFromPolygon, voronoiPolygons, generatingPointFromPolygon, crackedMud]


(* polyhedronFromPolygon returns a single polyhedron from a polygon *)

polyhedronFromPolygon[polygon_] :=      
 Module[{twoPolygons, verticesOfUpperPolygonCell, nVertices, n = 1},
 verticesOfUpperPolygonCell = Join @@ (polygon[[1]] /. {x_, y_} :> {{x, y, 0}, {x, y, -.08}});
 (* number of vertices in a single *Voronoi* cell *)
 nVertices = Length[verticesOfUpperPolygonCell]/2;   

(*vertex indices of the upper and lower polygon faces *)  
twoPolygons = Select[Range@(2*nVertices), #] & /@ {OddQ, EvenQ};    

(*vertex indices of a rectangular face of the polyhedron *)
While[n < nVertices + 1, AppendTo[twoPolygons,
    {twoPolygons[[1, n]], twoPolygons[[2, n]], 
     twoPolygons[[2, If[n + 1 < nVertices + 1, n + 1, 1]]], 
     twoPolygons[[1, If[n + 1 < nVertices + 1, n + 1, 1]]]}]; n++];
(*the graphics complex returned is a polyhedron, even though it says Polygon *)
 GraphicsComplex[verticesOfUpperPolygonCell, Polygon[twoPolygons]] ] 


(* takes two dimensional coordinates and returns all of the cells of a Voronoi diagram *)

voronoiPolygons[pts_] := 
Module[{voronoiRegion, data},
  voronoiRegion = VoronoiMesh[pts, ImageSize -> Medium, 
  PlotTheme -> "Lines", Axes -> True, AxesOrigin -> {0, 0}];
  data = Join @@ (MeshPrimitives[voronoiRegion, 2][[All, 1]] /. {x_, y_} :> {{x, y, 0}, {x, y, .04}});
 (* the mesh primitives are the polygons *)
  MeshPrimitives[voronoiRegion, 2]]   

(* Returns, in 3D, the point which was used to generate the nth Voronoi cell. *)
generatingPointFromPolygon[n_, points_, pgons_] := 
 FirstCase[points, {x_, y_} /; RegionMember[pgons[[n]], {x, y}] :> {x,y,0}]

crackedMud[seedNumber_] :- 
 Module[{pts, pts3D, geometricImage, nPts, polygons, polyhedra, centerPtinImage},
  SeedRandom[seedNumber];
  nPts = 80;
  pts = RandomReal[{-1, 1}, {nPts, 2}];
  pts3D = pts /. {x_, y_} :> {x, y, .0};
  polygons = voronoiPolygons[pts];
  polyhedra = polyhedronFromPolygon /@ polygons;
  centerPtinImage =   (Mean /@ (PlotRange /. 
        AbsoluteOptions[
         Graphics3D[{polyhedra, Blue, Point@pts3D}, Axes -> False, 
         Boxed -> False]])) /. {x_Real, y_, _} :> {x, y, 0};
  geometricImage =
  Graphics3D[{RGBColor[0.75, 0.75, 0.8], EdgeForm[Darker@Gray],
        (* # is the nth polygon which yields the nth polyhedron *)
        (* generatingPointFromPolygon returns the point the generated the #th polygon *)

     GeometricTransformation[{polyhedronFromPolygon[polygons[[#]]]},   
        TranslationTransform[(generatingPointFromPolygon[#, pts, polygons] - centerPtinImage)/5]] & /@ Range@nPts},
         Axes -> False,  Boxed -> False, ViewPoint -> {0., -1, 1.5}, 
         Background -> Black, ImageSize -> 1200];

     (*ImageTrim returns a 500 by 500 pixel clip from the center of the image *)
     ImageTrim[
        (*ImageEffect speckles the image *)
        ImageEffect[Rasterize[geometricImage], {"Noise", 1/5}], 
     {{250, 250}, {750, 750}}]
  ] 

आप एक बिखर-ग्लास पैटर्न निर्माता के लिए इसे अनुकूलित करने के लिए अच्छी तरह से कर सकते हैं।
स्पर्म

@ शेपर, हाँ यह टूटे हुए कांच (या टाइल्स) जैसा दिखता है।
डेविड

Golfed ........?
बिल्ली

@cat नहीं, यह गोल्फ नहीं है।
डेविड

@DavidC सभी व्हाट्सएप कहाँ है? क्या आप इसे ऐसे लिखते हैं? क्या वुल्फराम अपठनीय कोड लागू करता है?
बिल्ली

24

जावा

मैंने पुनरावर्ती वोरोनोई आरेखों पर आधारित एक दृष्टिकोण का उपयोग किया। आउटपुट बहुत यथार्थवादी नहीं लगते, लेकिन मुझे लगता है कि वे ठीक हैं।

यहां कुछ उदाहरण चित्र दिए गए हैं (250x250 का आकार दिया गया है ताकि यह पूरी स्क्रीन को न भरे)

0:

छवि 0

1:

चित्र 1

एल्गोरिथ्म के बारे में अधिक जानकारी:

इस खंड के सभी चित्र समान बीज का उपयोग कर रहे हैं।

एल्गोरिथ्म 5 अंकों के साथ एक वोरोनोई आरेख उत्पन्न करके शुरू होता है:

वोरोनोई आरेख

यदि हम मूल चित्रों को चुनौती में देखते हैं, तो हम देख सकते हैं कि लाइनें बिल्कुल सीधी नहीं हैं, इसलिए हम एक यादृच्छिक मान से दूरी को मापते हैं, जो बिंदु के कोण पर आधारित होता है, साथ ही, करीब कोणों को करीब मान देता है :

भारित वोरोनोई आरेख

अब, हम पुनरावर्ती रूप से इस प्रकार के वोरोनोई आरेखों को प्रत्येक क्षेत्र के अंदर खींचते हैं, पतले और अधिक पारदर्शी रेखा के साथ, और पृष्ठभूमि को हटाते हैं, अधिकतम 3 पुनरावृत्ति गहराई के साथ, और हम प्राप्त करते हैं:

रिकर्सिव वोरोनोई

अब, हम केवल पीले भूरे रंग की पृष्ठभूमि जोड़ते हैं, और हम काम कर रहे हैं!

किया हुआ!

कोड:

कोड तीन वर्गों के होते हैं Main.java, VoronoiPoint.javaऔर Vector.java:

Main.java:

import java.awt.Desktop;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;

import javax.imageio.ImageIO;

public class Main {
    public static int WIDTH = 500;
    public static int HEIGHT = 500;
    public static int RECURSION_LEVELS = 3;
    public static int AMOUNT_OF_POINTS = 5;
    public static int ROTATION_RESOLUTION = 600;
    public static int ROTATION_SMOOTHNESS = 10;
    public static int BACKGROUND = 0xFFE0CBAD;

    public static Random RAND;

    public static void main(String[] args) {

        int seed = new Random().nextInt(65536);
        if (args.length == 1) {
            System.out.println(Arrays.toString(args));
            seed = Integer.parseInt(args[0]);
        } else {
            System.out.println("Generated seed: " + seed);
        }
        RAND = new Random(seed);

        ArrayList<Vector> points = new ArrayList<Vector>();
        for (int x = 0; x < WIDTH; x++) {
            for (int y = 0; y < HEIGHT; y++) {
                points.add(new Vector(x, y));
            }
        }
        BufferedImage soil = generateSoil(WIDTH, HEIGHT, seed, points, AMOUNT_OF_POINTS, RECURSION_LEVELS);

        BufferedImage background = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        for (int x = 0; x < background.getWidth(); x++) {
            for (int y = 0; y < background.getHeight(); y++) {
                background.setRGB(x, y, BACKGROUND ^ (RAND.nextInt(10) * 0x010101));
            }
        }

        Graphics g = background.getGraphics();
        g.drawImage(soil, 0, 0, null);
        g.dispose();

        String fileName = "soil";
        File output = new File(fileName + ".png");
        for (int i = 0; output.exists(); i++) {
            output = new File(fileName + i + ".png");
        }
        try {
            ImageIO.write(background, "png", output);
            Desktop.getDesktop().open(output);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Done. Saved as " + output);
    }

    private static BufferedImage generateSoil(int width, int height, int seed, ArrayList<Vector> drawPoints,
            int amountOfPoints, int recursionLevel) {

        BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        ArrayList<VoronoiPoint> points = new ArrayList<VoronoiPoint>();
        for (int i = 0; i < amountOfPoints; i++) {
            points.add(new VoronoiPoint(drawPoints.get(RAND.nextInt(drawPoints.size()))));
        }

        HashMap<Integer, ArrayList<Vector>> pointMaps = new HashMap<Integer, ArrayList<Vector>>();
        for (VoronoiPoint point : points) {
            pointMaps.put(point.hashCode(), new ArrayList<Vector>());
        }
        System.out.println(pointMaps);

        System.out.println(points);

        for (Vector v : drawPoints) {
            VoronoiPoint closest = null;
            VoronoiPoint secondClosest = null;

            for (VoronoiPoint point : points) {
                double distance = point.getMultiplicativeDistanceTo(v);
                if (closest == null || distance < closest.getMultiplicativeDistanceTo(v)) {
                    secondClosest = closest;
                    closest = point;
                } else if (secondClosest == null || distance < secondClosest.getMultiplicativeDistanceTo(v)) {
                    secondClosest = point;
                }
            }

            int col = 0;
            if (Math.abs(closest.getMultiplicativeDistanceTo(v)
                    - secondClosest.getMultiplicativeDistanceTo(v)) < (recursionLevel * 5 / RECURSION_LEVELS)) {
                col = 0x01000000 * (recursionLevel * 255 / RECURSION_LEVELS);
            } else {
                pointMaps.get(closest.hashCode()).add(v);
            }
            result.setRGB((int) v.getX(), (int) v.getY(), col);
        }
        Graphics g = result.getGraphics();
        if (recursionLevel > 0) {
            for (ArrayList<Vector> pixels : pointMaps.values()) {
                if (pixels.size() > 10) {
                    BufferedImage img = generateSoil(width, height, seed, pixels, amountOfPoints,
                            recursionLevel - 1);
                    g.drawImage(img, 0, 0, null);
                }
            }
        }
        g.dispose();

        return result;
    }

    public static int modInts(int a, int b) {
        return (int) mod(a, b);
    }

    public static double mod(double a, double b) {
        a = a % b;
        while (a < 0)
            a += b;
        return a;
    }
}

VoronoiPoint.java:

public class VoronoiPoint {

    private Vector pos;
    private double[] distances;

    public VoronoiPoint(Vector pos) {
        this.pos = pos;
        distances = new double[Main.ROTATION_RESOLUTION];
        for (int i = 0; i < distances.length; i++)
            distances[i] = Main.RAND.nextFloat() / 2 + 0.51;

        for (int iter = 0; iter < Main.ROTATION_SMOOTHNESS; iter++) {
            for (int i = 0; i < distances.length; i++) {
                distances[i] = (distances[Main.modInts(i - Main.RAND.nextInt(4) - 2, distances.length)] + distances[i]
                        + distances[Main.modInts(i + Main.RAND.nextInt(4) - 2, distances.length)]) / 3;
            }
        }
    }

    public Vector getPos() {
        return pos;
    }

    public double getRotationFromAngle(double radians) {
        return distances[(int) (Main.mod(Math.toDegrees(radians) / 360, 1) * distances.length)];
    }

    public double getRotationFromVector(Vector vec) {
        return getRotationFromAngle(Math.atan2(pos.getY() - vec.getY(), -(pos.getX() - vec.getX())));
    }

    public double getMultiplicativeDistanceTo(Vector other) {
        return pos.getLengthTo(other) * getRotationFromVector(other);
    }

    public String toString() {
        return "VoronoiPoint(pos=[" + pos.getX() + ", " + pos.getY() + "])";
    }

    public int hashCode() {
        return distances.hashCode() ^ pos.hashCode();
    }
}

Vector.java: (यह वर्ग मेरी एक अन्य परियोजना से कॉपी किया गया है, इसलिए इसमें कुछ अनावश्यक कोड हैं)

package com.loovjo.soil;

import java.util.ArrayList;
import java.util.Random;

public class Vector {
    private static final float SMALL = 1f / Float.MAX_EXPONENT * 100;
    private float x, y;

    public Vector(float x, float y) {
        this.setX(x);
        this.setY(y);
    }

    public Vector(int x, int y) {
        this.setX(x);
        this.setY(y);
    }

    public Vector(double x, double y) {
        this.setX((float) x);
        this.setY((float) y);
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    /*
     * Gets the length ^ 2 This is faster than getting the length.
     */
    public float getLengthToSqrd(float x, float y) {
        return (float) ((this.x - x) * (this.x - x) + (this.y - y) * (this.y - y));
    }

    public float getLengthToSqrd(Vector v) {
        return getLengthToSqrd(v.x, v.y);
    }

    public float getLengthSqrd() {
        return getLengthToSqrd(0, 0);
    }

    public float getLengthTo(float x, float y) {
        return (float) Math.sqrt(getLengthToSqrd(x, y));
    }

    public float getLengthTo(Vector v) {
        return getLengthTo(v.x, v.y);
    }

    public float getLength() {
        return getLengthTo(0, 0);
    }

    public Vector setLength(float setLength) {
        float length = getLength();
        x *= setLength / length;
        y *= setLength / length;
        return this;
    }

    public float getFastLengthTo(float x, float y) {
        return getFastLengthTo(new Vector(x, y));
    }

    public float getFastLengthTo(Vector v) {
        float taxiLength = getTaxiCabLengthTo(v);
        float chebyDist = getChebyshevDistanceTo(v);
        return Float.min(taxiLength * 0.7f, chebyDist);
    }

    public float getFastLength() {
        return getLengthTo(0, 0);
    }

    public Vector setFastLength(float setLength) {
        float length = getFastLength();
        x *= setLength / length;
        y *= setLength / length;
        return this;
    }

    public float getTaxiCabLengthTo(float x, float y) {
        return Math.abs(this.x - x) + Math.abs(this.y - y);
    }

    public float getTaxiCabLengthTo(Vector v) {
        return getTaxiCabLengthTo(v.x, v.y);
    }

    public float getTaxiCabLength() {
        return getTaxiCabLengthTo(0, 0);
    }

    public Vector setTaxiCabLength(float setLength) {
        float length = getTaxiCabLength();
        x *= setLength / length;
        y *= setLength / length;
        return this;
    }

    public Vector absIfBoth() {
        if (x < 0 && y < 0)
            return new Vector(-x, -y);
        return this;
    }

    public Vector abs() {
        return new Vector(x < 0 ? -x : x, y < 0 ? -y : y);
    }

    public float getChebyshevDistanceTo(float x, float y) {
        return Math.max(Math.abs(this.x - x), Math.abs(this.y - y));
    }

    public float getChebyshevDistanceTo(Vector v) {
        return getChebyshevDistanceTo(v.x, v.y);
    }

    public float getChebyshevDistance() {
        return getChebyshevDistanceTo(0, 0);
    }

    public Vector setChebyshevLength(float setLength) {
        float length = getChebyshevDistance();
        x *= setLength / length;
        y *= setLength / length;
        return this;
    }

    public Vector sub(Vector v) {
        return new Vector(this.x - v.getX(), this.y - v.getY());
    }

    public Vector add(Vector v) {
        return new Vector(this.x + v.getX(), this.y + v.getY());
    }

    public Vector mul(Vector v) {
        return new Vector(this.x * v.getX(), this.y * v.getY());
    }

    public Vector mul(float f) {
        return mul(new Vector(f, f));
    }

    public Vector div(Vector v) {
        return new Vector(this.x / v.getX(), this.y / v.getY());
    }

    public Vector div(float f) {
        return div(new Vector(f, f));
    }

    public Vector mod(Vector v) {
        return new Vector(this.x % v.getX(), this.y % v.getY());
    }

    public Vector mod(int a, int b) {
        return mod(new Vector(a, b));
    }

    public Vector mod(int a) {
        return mod(a, a);
    }

    public String toString() {
        return "Vector(" + getX() + ", " + getY() + ")";
    }

    /*
     * Returns a list with vectors, starting with this, ending with to, and each
     * one having length between them
     */
    public ArrayList<Vector> loop(Vector to, float length) {
        Vector delta = this.sub(to);
        float l = delta.getLength();
        ArrayList<Vector> loops = new ArrayList<Vector>();
        for (float i = length; i < l; i += length) {
            delta.setLength(i);
            loops.add(delta.add(to));
        }
        loops.add(this);

        return loops;
    }

    public boolean intersects(Vector pos, Vector size) {
        pos.sub(this);
        if (pos.getX() < getX())
            return false;
        if (pos.getY() < getY())
            return false;
        return true;
    }

    public Vector copy() {
        return new Vector(x, y);
    }

    public void distort(float d) {
        x += Math.random() * d - d / 2;
        y += Math.random() * d - d / 2;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Vector) {
            Vector v = (Vector) o;
            return getLengthToSquared(v) < SMALL * SMALL;
        }
        return false;
    }

    private float getLengthToSquared(Vector v) {
        return sub(v).getLengthSquared();
    }

    private float getLengthSquared() {
        return x * x + y * y;
    }

    public boolean kindaEquals(Vector o, int i) {
        if (o.x + i < x)
            return false;
        if (o.x - i > x)
            return false;
        if (o.y + i < y)
            return false;
        if (o.y - i > y)
            return false;
        return true;
    }
    /*
     * Gets the direction, from 0 to 8.
     */
    public int getDirection() {
        return (getDirectionInDegrees()) / (360 / 8);
    }
    /*
     * Gets the direction in degrees.
     */
    public int getDirectionInDegrees() {
        return (int) positize((float) Math.toDegrees(Math.atan2(x, -y)), 360f);
    }

    private float positize(float f, float base) {
        while (f < 0)
            f += base;
        return f;
    }
    // 0 = north,
            // 1 = northeast,
            // 2 = east,
            // 3 = southeast,
            // 4 = south,
            // 5 = southwest,
            // 6 = west,
            // 7 = northwest
    public Vector moveInDir(int d) {
        d = d % 8;
        d = (int) positize(d, 8);

        if (d == 0)
            return this.add(new Vector(0, -1));
        if (d == 1)
            return this.add(new Vector(1, -1));
        if (d == 2)
            return this.add(new Vector(1, 0));
        if (d == 3)
            return this.add(new Vector(1, 1));
        if (d == 4)
            return this.add(new Vector(0, 1));
        if (d == 5)
            return this.add(new Vector(-1, 1));
        if (d == 6)
            return this.add(new Vector(-1, 0));
        if (d == 7)
            return this.add(new Vector(-1, -1));
        return this;
    }
    /*
     * Gets the angle in degrees to o.
     */
    public float getRotationTo(Vector o) {
        float d = (float) Math.toDegrees((Math.atan2(y - o.y, -(x - o.x))));
        while (d < 0)
            d += 360;
        while (d > 360)
            d -= 360;
        return d;
    }
    public float getRotation() {
        return getRotationTo(new Vector(0, 0));
    }
    /*
     * In degrees
     */
    public Vector rotate(double n) {
        n = Math.toRadians(n);
        float rx = (float) ((this.x * Math.cos(n)) - (this.y * Math.sin(n)));
        float ry = (float) ((this.x * Math.sin(n)) + (this.y * Math.cos(n)));
        return new Vector(rx, ry);
    }

    public int hashCode() {
        int xx = (int) x ^ (int)(x * Integer.MAX_VALUE);
        int yy = (int) y ^ (int)(y * Integer.MAX_VALUE);
        return new Random(12665 * xx).nextInt() ^ new Random(5349 * yy).nextInt() + new Random((30513 * xx) ^ (19972 * yy)).nextInt();
    }

    public boolean isPositive() {
        return x >= 0 && y >= 0;
    }

    public Vector clone() {
        return new Vector(x, y);
    }
}

लेकिन मैं जावा वर्गों के एक समूह को संकलित नहीं करना चाहता!

यहाँ एक JAR फ़ाइल है जिसे आप इन चित्रों को स्वयं बनाने के लिए चला सकते हैं। इस रूप में चलाएं java -jar Soil.jar number, जहां numberबीज है (2 31 -1 तक कुछ भी हो सकता है ), या के रूप में चलाएं java -jar Soil.jar, और यह अपने आप बीज चुनता है। कुछ डिबग आउटपुट होगा।


किसी कारण से मैं उन छवियों को काफी यथार्थवादी और पूरी तरह से नकली दोनों पाता हूं। प्राकृतिक छाया की कमी मुझे खटक रही है।
घातक

यदि यह मदद करता है, तो आप पूर्ण आकार की छवियों को अपलोड कर सकते हैं और उन्हें चुनौती पोस्ट की तरह छोटे थंबनेल बना सकते हैं, या मध्यम छवियां जो कम ऊर्ध्वाधर स्थान लेने के लिए 2 भर में फिट होती हैं। चुनौती के स्रोत में आप देख सकते हैं कि कैसे imgur पते में "s" जोड़ने से चित्र छोटे हो जाते हैं, और आप माध्यम के लिए "m" का भी उपयोग कर सकते हैं। स्रोत यह भी दर्शाता है कि छोटे आकार को पूर्ण आकार की छवि के लिंक में कैसे बनाया जाए।
ट्राइकोप्लाक्स

2
मुझे लगता है कि रंग बहुत करीब हो सकते हैं - अधिक ग्रे, कम बेज। लेकिन अन्यथा अच्छा जवाब!
केल्विन के शौक

12

पायथन 3 (किवी लाइब्रेरी और जीएलएसएल का उपयोग करके)

पहले उत्पन्न छवि

यहाँ छवि विवरण दर्ज करें

पायथन कोड:

import os
os.environ['KIVY_NO_ARGS'] = '1'

from kivy.config import Config
Config.set('input','mouse','mouse,disable_multitouch')
Config.set('graphics', 'width', '500')
Config.set('graphics', 'height', '500')
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'borderless', '1')
Config.set('graphics', 'fbo', 'force-hardware')

from kivy.app import App
from kivy.graphics import RenderContext, Fbo, Color, Rectangle
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.factory import Factory
from kivy.core.window import Window

class ShaderSurface(FloatLayout):
    seed = 0.

    def __init__(self, **kwargs):
        self.canvas = RenderContext(use_parent_projection=True, use_parent_modelview=True)
        with self.canvas:
            self.fbo = Fbo(size=Window.size, use_parent_projection=True)

        with self.fbo:
            Color(0,0,0)
            Rectangle(size=Window.size)

        self.texture = self.fbo.texture

        super(ShaderSurface, self).__init__(**kwargs)
        self.keyboard = Window.request_keyboard(self.keyboard_closed, self)
        self.keyboard.bind(on_key_down=self.on_key_down)
        Clock.schedule_once(self.update_shader,-1)

    def keyboard_closed(self):
        self.keyboard.unbind(on_key_down=self.on_key_down)
        self.keyboard = None

    def update_shader(self, dt=0.):
        self.canvas['resolution'] = list(map(float, self.size))
        self.canvas['seed'] = self.seed
        self.canvas.ask_update()

    def on_key_down(self, keyboard, keycode, text, modifiers):
        if keycode[1] == 'spacebar':
            self.seed += 1.
            self.update_shader()
            Window.screenshot()

Factory.register('ShaderSurface', cls=ShaderSurface)

class RendererApp(App):
    def build(self):
        self.root.canvas.shader.source = 'cracks_sub.glsl'

if __name__ == '__main__':
    RendererApp().run()

KV फ़ाइल:

#:kivy 1.9

ShaderSurface:
    canvas:
        Color:
            rgb: 1, 1, 1
        Rectangle:
            size: self.size
            pos: self.pos
            texture: root.fbo.texture

GLSL कोड:

---VERTEX---
uniform vec2        resolution;
in vec2             vPosition;

void main()
{
    gl_Position = vec4(vPosition.xy-resolution/2., 0, 1);
}
---FRAGMENT---
#version 330
precision highp float;

out vec4 frag_color;

uniform vec2 resolution;
uniform float seed;

vec2 tr(vec2 p)
{
    p /= resolution.xy;
    p = -1.0+2.0*p;
    p.y *= resolution.y/resolution.x;
    return p;
}

float hash( float n ){
    return fract(sin(n)*43758.5453);
}

float noise( vec2 uv ){
    vec3 x = vec3(uv, 0);

    vec3 p = floor(x);
    vec3 f = fract(x);

    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;

    return mix(mix(mix( hash(n+0.0), hash(n+1.0),f.x),
                   mix( hash(n+57.0), hash(n+58.0),f.x),f.y),
               mix(mix( hash(n+113.0), hash(n+114.0),f.x),
                   mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

mat2 m = mat2(0.8,0.6,-0.6,0.8);

float fbm(vec2 p)
{
    float f = 0.0;
    f += 0.5000*noise( p ); p*=m*2.02;
    f += 0.2500*noise( p ); p*=m*2.03;
    f += 0.1250*noise( p ); p*=m*2.01;
    f += 0.0625*noise( p );
    f /= 0.9375;
    return f;
}

vec2 hash2( vec2 p )
{
    return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
}

float voronoi(vec2 x, out vec2 rt)
{
    vec2 p = floor(x);
    vec2 f = fract(x);

    vec2 mb, mr;

    float res = 8.0;
    for( int j=-1; j<=1; j++)
    for( int i=-1; i<=1; i++)
    {
        vec2 b = vec2(float(i),float(j));
        vec2 r = b+hash2(p+b)-f;
        float d = dot(r,r);

        if( d<res )
        {
            res = d;
            mr = r;
            mb = b;
            rt=r;
        }
    }


    res = 8.0;
    for( int j=-2; j<=2; j++ )
    for( int i=-2; i<=2; i++ )
    {
        vec2 b = mb + vec2(float(i),float(j));
        vec2 r = b + hash2(p+b)-f;
        float d = dot((res*res)*(mr+r),normalize(r-mr));

        res = min(res,d);
    }


    return res;
}

float crack(vec2 p)
{
    float g = mod(seed,65536./4.);
    p.x+=g;
    p.y-=seed-g;
    p.y*=1.3;
    p.x+=noise(p*4.)*.08;
    float k = 0.;
    vec2 rb = vec2(.0);
    k=voronoi(p*2.,rb);
    k=smoothstep(.0,.3,k*.05);
    float v = 0.;
    v=voronoi(rb*4.,rb);
    v=smoothstep(.0,.5,v*.05);
    k*=v;
    k-=fbm(p*128.)*.3;
    return k;
}

void main( void )
{
    vec2 fc = gl_FragCoord.xy;
    vec2 p = tr(fc);
    vec3 col = vec3(.39,.37,.25);

    vec3 abb = vec3(.14,.12,.10)/5.;

    p*=(1.+length(p)*.1);

    col.r*=crack(vec2(p.x+abb.x,p.y));
    col.g*=crack(vec2(p.x+abb.y,p.y));
    col.b*=crack(vec2(p.x+abb.z,p.y));

    col*=smoothstep(4.,1.2,dot(p,p));
    col*=exp(.66);

    //col=vec3(crack(p));
    frag_color = vec4(col,1.);
}

Voronoi GLSL कोड में समारोह Inigo Quílez से है। प्रत्येक वोरोनोई संबंधित गणना पूरी तरह से कुछ प्रक्रियात्मक शोर कार्यों के साथ स्पार्क बनाने के लिए और वोरोनोई पैटर्न की रेखाओं को थोड़ा परेशान करने के लिए पूरी तरह से टुकड़ा शेडर में होता है।

स्पेस दबाने से बीज में 1 की वृद्धि होगी और एक नई छवि उत्पन्न होगी और एक .pngफाइल के रूप में सहेजी जाएगी ।

अपडेट: जोड़ा गया विरूपण, विग्निटेटिंग और क्रोमैटिक एब्रेशन इसे और अधिक फोटो-यथार्थवादी बनाने के लिए। जोड़ा गया उप-वोरोनोई पैटर्न।


क्या यह बीज को इनपुट के रूप में भी ले सकता है?
त्रिकोप्लक्स

ShaderSurface वर्ग में एक वर्ग सदस्य है seed। यह एक समान फ्लोट वैरिएबल के रूप में शेडर को पाइप किया जाएगा। शेडर की दरार फ़ंक्शन में बीज का उपयोग बीज के मूल्य द्वारा बिंदु का अनुवाद करने के लिए किया जाता है।
गैबरे फेकटे

1

जावा

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

import javax.imageio.ImageIO;

public class CrackedSoil {
    static BufferedImage b;
    static Random rand;
    public static int distance(int col1,int col2){
        Color a=new Color(col1);
        Color b=new Color(col2);
        return (int)(Math.pow(a.getRed()-b.getRed(), 2)+Math.pow(a.getGreen()-b.getGreen(), 2)+Math.pow(a.getBlue()-b.getBlue(), 2));
    }
    public static void edge(){
        boolean[][] edges=new boolean[500][500];
        int threshold=125+rand.nextInt(55);
        for(int x=1;x<499;x++){
            for(int y=1;y<499;y++){
                int rgb=b.getRGB(x, y);
                int del=0;
                for(int i=-1;i<=1;i++){
                    for(int j=-1;i<=j;i++){
                        del+=distance(rgb,b.getRGB(x+i, y+j));
                    }
                }
                edges[x][y]=del>threshold;
            }
        }
        for(int x=0;x<500;x++){
            for(int y=0;y<500;y++){
                if(edges[x][y])b.setRGB(x, y,new Color(4+rand.nextInt(4),4+rand.nextInt(4),4+rand.nextInt(4)).getRGB());
            }
        }
    }
    public static void main(String[]arg) throws IOException{
        b=new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
        Scanner scanner=new Scanner(System.in);
        rand=new Random(scanner.nextInt());
        int numPoints=10+rand.nextInt(15);
        Color[]c=new Color[numPoints];
        int[][]ints=new int[numPoints][2];
        int[]weights=new int[numPoints];
        for(int i=0;i<numPoints;i++){
            switch(i%4){
            case 0:ints[i]=new int[]{251+rand.nextInt(240),7+rand.nextInt(240)};break;
            case 1:ints[i]=new int[]{7+rand.nextInt(240),7+rand.nextInt(240)};break;
            case 2:ints[i]=new int[]{7+rand.nextInt(240),251+rand.nextInt(240)};break;
            case 3:ints[i]=new int[]{251+rand.nextInt(240),251+rand.nextInt(240)};break;
            }

            c[i]=new Color(40+rand.nextInt(200),40+rand.nextInt(200),40+rand.nextInt(200));
            weights[i]=50+rand.nextInt(15);
        }
        for(int x=0;x<500;x++){
            for(int y=0;y<500;y++){
                double d=999999;
                Color col=Color.BLACK;
                for(int i=0;i<numPoints;i++){
                    double d2=weights[i]*Math.sqrt((x-ints[i][0])*(x-ints[i][0])+(y-ints[i][1])*(y-ints[i][1]));
                    if(d2<d){
                        d=d2;
                        col=c[i];
                    }
                }
                b.setRGB(x, y,col.getRGB());
            }
        }
        //ImageIO.write(b,"png",new File("voronoi1.png"));
        for(int i=0;i<numPoints/3;i++){
            ints[i]=new int[]{7+rand.nextInt(490),7+rand.nextInt(490)};
            c[i]=new Color(40+rand.nextInt(200),40+rand.nextInt(200),40+rand.nextInt(200));
            weights[i]=50+rand.nextInt(5);
        }
        for(int x=0;x<500;x++){
            for(int y=0;y<500;y++){
                double d=999999;
                Color col=Color.BLACK;
                for(int i=0;i<numPoints/3;i++){
                    double d2=weights[i]*Math.sqrt((x-ints[i][0])*(x-ints[i][0])+(y-ints[i][1])*(y-ints[i][1]));
                    if(d2<d){
                        d=d2;
                        col=c[i];
                    }
                }
                Color col3=new Color(b.getRGB(x, y));
                b.setRGB(x, y,new Color((col3.getRed()+col.getRed()*3)/4,(col3.getGreen()+col.getGreen()*3)/4,(col3.getBlue()+col.getBlue()*3)/4).getRGB());
            }
        }
        //ImageIO.write(b,"png",new File("voronoi2.png"));
        for(int i=2+rand.nextInt(3);i>0;i--)edge();
        //ImageIO.write(b,"png",new File("voronoi_edge.png"));
        for(int x=0;x<500;x++){
            for(int y=0;y<500;y++){
                Color col=new Color(b.getRGB(x, y));
                if(col.getRed()+col.getBlue()+col.getGreen()>50){
                    if(rand.nextDouble()<0.95){
                        b.setRGB(x, y,new Color(150+rand.nextInt(9),145+rand.nextInt(9),135+rand.nextInt(9)).getRGB());
                    }else{
                        b.setRGB(x, y,new Color(120+col.getRed()/7+rand.nextInt(12),115+col.getGreen()/7+rand.nextInt(12),105+col.getBlue()/7+rand.nextInt(12)).getRGB());
                    }
                }
            }
        }
        ImageIO.write(b,"png",new File("soil.png"));
    }
}

फिर दो यादृच्छिक आरेखों का एक संयोजन बनाता है जो फिर एक साधारण किनारे का पता लगाने के माध्यम से चलाया जाता है और अंत में अंतिम परिणाम में बदल जाता है।

कुछ आउटपुट:

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें

पिछले एक के लिए मध्यवर्ती चरणों में से कुछ:

यहाँ छवि विवरण दर्ज करें

(पहला वोरोनोई आरेख)

यहाँ छवि विवरण दर्ज करें

(दो वोरोनोई आरेखों का सम्मिश्रण)

यहाँ छवि विवरण दर्ज करें

(बढ़त का पता लगाने के चरण के बाद लेकिन अंतिम पुनरावृत्ति से पहले)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.