Rasterize Image/ Flowfield with Noise values from image

Hi, how can I change the code below to shift lines that respond to the image file?


Via Coding Challenge #24: Perlin Noise Flow Field

PImage img;

void setup(){
  size(900, 900, P3D);
  img = loadImage("Jan24.jpg");
  img.resize(900,900);
  
}

void draw() {
  background(#f1f1f1);
  fill(0);
  noStroke();
  sphereDetail(3);
  
  float tiles = 100;
  float tileSize = width/tiles;
  
  push();
  translate(width/2,height/2);
  
  for (int x = 0; x < tiles; x++) {
    for (int y = 0; y < tiles; y++) {
      
    color c = img.get(int(x*tileSize),int(y*tileSize));
    float b = map(brightness(c),0,255,01,0); 
    
    float z = map(b,0,1,-100,100);
    
    push();
    translate(x*tileSize - width/2,y*tileSize- height/2, z);
    sphere(tileSize*b);
    pop();
    
    
    }
    
  }
    
}

Via Tim Rodenbröker

Hello @asymmetric ,

You need to map the brightness to an angle:

float b = map(brightness(c), 0, 255, 0, PI); // angle in radians

Replace the sphere with a line and translate and rotate it in this order:

  • translate()
  • rotate()
  • line() < Draw a line passing through (0, 0) if you are translating the same way you are translating sphere.

I was able to generate this with some modifications to your code:

Same image with color added to line:

:)

1 Like

Thank you @glv! That’s exactly what I am looking for! I tried replacing the sphere(); with line(); and received compiler errors.

PImage img;

void setup(){
  size(900, 900, P3D);
  img = loadImage("Jan24.jpg");
  img.resize(900,900);
  
}

void draw() {
  background(#f1f1f1);
  fill(0);
  noStroke();
  line(0,0);
  //sphereDetail(3);
  //ellipse(mouseX,mouseY,40,40);
  
  float tiles = 100;
  float tileSize = width/tiles;
  
  push();
  rotateY(radians(frameCount) );
  translate(width/2,height/2);
  
  for (int x = 0; x < tiles; x++) {
    for (int y = 0; y < tiles; y++) {
      
    color c = img.get(int(x*tileSize),int(y*tileSize));
    float b = map(brightness(c),0,255,0,PI); 
    
    float z = map(b,0,1,-100,100);
    
    push();
    translate(x*tileSize - width/2,y*tileSize- height/2, z);
    line(tileSize*b);
    pop();
    
    
    }
    
  }
    
}

That will happen when you use the methods incorrectly.

I suggest you look up the reference for line().

:)

Hi @glv ,

I can’t figure out how to change the direction of the lines to match the flow lines like the example image that you shared. What do I need to change? Please help :pray:

PImage img;

void setup(){
  size(1000, 1000, P3D);
  img = loadImage("Jan24.jpg");
  img.resize(1000,1000);
  
}

void draw() {
  background(#f1f1f1);
  stroke(0);
  strokeWeight(2);
  
  float tiles = 150;
  float tileSize = width/tiles;
  
  push();
  translate(width/2,height/2);
  
  for (int x = 0; x < tiles; x++) {
    for (int y = 0; y < tiles; y++) {
      
    color c = img.get(int(x*tileSize),int(y*tileSize));
    float b = map(brightness(c),0,255,0,PI/180);
    
    float z = map(b,0,1,-100,100);
    

    stroke(c);
    
    
    push();
    translate(x*tileSize - width/2,y*tileSize- height/2, z);
    line(x,y,x+tileSize,y+tileSize);
    pop();
    
    
    }
    
  }
    
}

This is my result when I use the code provided above. And I would like my image to look like the black and white image of the frog that you shared.

I tried the following code provided by Daniel Shiffman, but it isn’t working for some reason.

https://github.com/nature-of-code/noc-examples-processing/tree/master/chp06_agents/FlowfieldImage

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// Flow Field Following

class FlowField {

  // A flow field is a two dimensional array of PVectors
  PVector[][] field;
  int cols, rows; // Columns and Rows
  int resolution; // How large is each "cell" of the flow field

  FlowField(int r) {
    resolution = r;
    // Determine the number of columns and rows based on sketch's width and height
    cols = width/resolution;
    rows = height/resolution;
    field = new PVector[cols][rows];
    init();
  }

  void init() {
    for (int i = 0; i < cols; i++) {
      for (int j = 0; j < rows; j++) {
        field[i][j] = new PVector(width/2-i*resolution,height/2-j*resolution);
        field[i][j].normalize();
      }
    }

    // Reseed noise so we get a new flow field every time
    for (int i = 1; i < cols-1; i++) {
      for (int j = 1; j < rows-1; j++) {

        int x = i*resolution;
        int y = j*resolution;
        int c = img.pixels[x + y * img.width];

        // Map brightness to an angle
        float theta = map(brightness(c), 0, 255, 0, TWO_PI);
        // Polar to cartesian coordinate transformation to get x and y components of the vector
        field[i][j] = PVector.fromAngle(theta);
        field[i][j].normalize();
      }
    }
  }

  // Draw every vector
  void display() {
    for (int i = 0; i < cols; i++) {
      for (int j = 0; j < rows; j++) {
        drawVector(field[i][j], i*resolution, j*resolution, resolution-2);
      }
    }
  }

  // Renders a vector object 'v' as an arrow and a position 'x,y'
  void drawVector(PVector v, float x, float y, float scayl) {
    pushMatrix();
    // Translate to position to render vector
    translate(x, y);
    strokeWeight(2);
    stroke(255, 0, 0);
    // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
    rotate(v.heading());
    // Calculate length of vector & scale it to be bigger or smaller if necessary
    float len = v.mag()*scayl;
    // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
    line(0, 0, len, 0);
    //line(len,0,len-arrowsize,+arrowsize/2);
    //line(len,0,len-arrowsize,-arrowsize/2);
    popMatrix();
  }

  PVector lookup(PVector lookup) {
    int column = int(constrain(lookup.x/resolution, 0, cols-1));
    int row = int(constrain(lookup.y/resolution, 0, rows-1));
    return field[column][row].copy();
  }
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// Flow Field Following
// Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html

// Using this variable to decide whether to draw all the stuff
boolean debug = true;

PImage img;

// Flowfield object
FlowField flowfield;
// An ArrayList of vehicles
ArrayList<Vehicle> vehicles;

void setup() {
  size(500, 500);
  img = loadImage("Jan24.jpg");
  // Make a new flow field with "resolution" of 16
  flowfield = new FlowField(16);
  vehicles = new ArrayList<Vehicle>();
  // Make a whole bunch of vehicles with random maxspeed and maxforce values
}

void draw() {
  background(255);
  image(img, 0, 0);
  // Display the flowfield in "debug" mode
  if (debug) flowfield.display();
  // Tell all the vehicles to follow the flow field
  for (Vehicle v : vehicles) {
    v.follow(flowfield);
    v.run();
  }

  // Instructions
  fill(0);
  text("Hit space bar to toggle debugging lines.\nClick the mouse to generate a new flow field.", 10, height-20);
}


void keyPressed() {
  if (key == ' ') {
    debug = !debug;
  }
}

void mouseDragged() {
  vehicles.add(new Vehicle(new PVector(mouseX, mouseY), 3, 0.3));
}


Go to the Contribution Manager in the Processing IDE and download the examples:

They will then be available to you:

The example works:

Or download the code from here:
https://github.com/nature-of-code/noc-examples-processing

Look for this on the page:
image

:)


I was able to get to the result that I have been striving for via modifying the example code!! Thank you @glv !!!

1 Like

One more question, @glv! How do I remove the vehicle from the example code? I would like to simplify the code in order to understand it better.

Scrutinize the code.

Try commenting out code to see what it does.

:)

1 Like

I just worked through this with some “students” (young programming enthusiasts) here that I code with using the general instructions I provided you.

This is now a 2D mapping and you will not need the z component; make it zero.

    float b = map(brightness(c), 0, 255, 0, TWO_PI); // angle in radians

    push();
    translate(x*tileSize - width/2, y*tileSize - height/2, z);
    rotate(?);           // What is the angle?
    strokeWeight(3);
    stroke(255, 0, 0);   // Red 
    line(?);             // Simple enough to do...
    pop();

And the end result:

:)

1 Like