Creating a grid of dice representing an image

Hi, how would I go about creating a grid of random(); dice that respond to a PImage(); in 2D (like the image below) or a 3D (heightmap)?

1 Like

Now

  • start by loading the start image

  • Go through it pixel by pixel. The reference for pixels and image is your friend here. See below.

  • Then check the brightness for the pixel and use text (1 or 2 or 3....) in a grid corresponding to the image

  • Later you can replace the numbers by images of the dice

See pixels[] / Reference / Processing.org


The dice

(not by me)

/***  Constants  ***/
final int NUM_SIDES = 6;   //Sides on the dice
final int NUM_DICE = 11;    //The number of dices used


/***  Variables  ***/
int[] rolls = new int[NUM_DICE]; //array to store dice roll

void setup() {
  size(500, 500);
  message_draw("Click to roll");
  dice_roll();
}

void draw() {
  for (int diceIndex = 0; diceIndex < NUM_DICE; diceIndex++) {
    dice_draw( diceIndex, rolls[diceIndex] );
  }
}

// ---------------------------------------------------------------------------------------------------

void mousePressed() {
  dice_roll();
}

void message_draw(String message) {
  //Display the given message in the centre of the window.
  textSize(24);
  fill(0);
  text(message, (width-textWidth(message))/2, height/2);
}

void dice_roll() {
  for (int i=0; i < NUM_DICE; i++) {
    rolls[i]= 1 + int(random(NUM_SIDES));
  }
}

void dice_draw(int position, int value) {
  /* Draw one dice in the canvas.
   *   position - must be 0..NUM_DICE-1, indicating which dice is being drawn
   *   value - must be 1..6, the amount showing on that dice
   */
  final float X_SPACING = (float)width/NUM_DICE; //X spacing of the dice
  final float DIE_SIZE = X_SPACING*0.8; //width and height of one die
  final float X_LEFT_DIE = X_SPACING*0.1; //left side of the leftmost die
  final float Y_OFFSET = X_SPACING*0.15; //slight Y offset of the odd-numbered ones
  final float Y_POSITION = height-DIE_SIZE-Y_OFFSET; //Y coordinate of most dice
  final float PIP_OFFSET = DIE_SIZE/3.5; //Distance from centre to pips, and between pips
  final float PIP_DIAM = DIE_SIZE/5; //Diameter of the pips (dots)

  //From the constants above, and which dice it is, find its top left corner
  float dieX = X_LEFT_DIE+position*X_SPACING;
  float dieY = Y_POSITION-Y_OFFSET*(position%2);

  //1.Draw a red square with a black outline
  stroke(0); //Black outline
  fill(255, 0, 0); //Red fill
  rect(dieX, dieY, DIE_SIZE, DIE_SIZE);

  //2.Draw the pips (dots)
  fill(255); //White dots
  stroke(255); //White outline

  //The centre dot (if the value is odd, 1, 3, 5)
  if (1 == value%2) {
    ellipse(dieX+DIE_SIZE/2, dieY+DIE_SIZE/2, PIP_DIAM, PIP_DIAM);
  }

  //The top-left and bottom-right dots (if the value is more than 1)
  if (value>1) {
    ellipse(dieX+DIE_SIZE/2-PIP_OFFSET, 
      dieY+DIE_SIZE/2+PIP_OFFSET, PIP_DIAM, PIP_DIAM);
    ellipse(dieX+DIE_SIZE/2+PIP_OFFSET, 
      dieY+DIE_SIZE/2-PIP_OFFSET, PIP_DIAM, PIP_DIAM);
  }

  //The bottom-left and top-right dots (if the value is more than 3)
  if (value>3) {
    ellipse(dieX+DIE_SIZE/2+PIP_OFFSET, 
      dieY+DIE_SIZE/2+PIP_OFFSET, PIP_DIAM, PIP_DIAM);
    ellipse(dieX+DIE_SIZE/2-PIP_OFFSET, 
      dieY+DIE_SIZE/2-PIP_OFFSET, PIP_DIAM, PIP_DIAM);
  }

  //The left and right dots (only if the value is 6)
  if (value==6) {
    ellipse(dieX+DIE_SIZE/2-PIP_OFFSET, 
      dieY+DIE_SIZE/2, PIP_DIAM, PIP_DIAM);
    ellipse(dieX+DIE_SIZE/2+PIP_OFFSET, 
      dieY+DIE_SIZE/2, PIP_DIAM, PIP_DIAM);
  }
}
//

3 Likes

Hello @asymmetric,

You have already done a lot of work from your other posts that you can reuse.

I always think this trough and mentally (or written as below) go through steps required and then consider what code (always lots of options) to use.

Steps I took in my first attempt at this:

  • Resize image. This makes it easy to extract a pixel and simplifies things… no need to get an average color of a section. Explore a more advanced approach later…

  • Create a grid that is the size (cells x cells) of the resized image; size of each cell will be larger.

  • Color each cell of the grid with the brightness (other options here) of the pixel.

  • Brightness is 0 to 255 and you can map this to 0 to 6; do the math or use the helper function.
    The result will be a float and only use the integer component of this.

  • You can then use 0 to 5 to get the dice image for brightness.
    It may not be an image and generated; I generated the face of each dice… this was just another grid (filtered the faces) for me.
    You have some options on how to do this part.
    I leave that with you… give it some thought.

At first I just colored the grid with 6 shades of gray:

I then replaced the 6 shades of gray with the face of a die:

:)

3 Likes

Thank you @glv! I now understand how to rasterize an image, but how do I control the placement of the dice circles within each pixel?

You mean a single dice? I’ve shown code above

Plus map() the brightness of each pixel to 1…6 and draw the dice number

int showDiceNumber = map( myBrightness,
   0,255,
   6, 1 );  // wild guess
1 Like

@Chrisir I mean like the image @glv created ( rasterized dice image).

I have the following code so far… the pixelated rasterized image (via Tim Rodenbroeker).

PImage img;

void setup(){
  size(700,700);
  img = loadImage("IMG_7741.jpeg");

}

void draw(){
  background(#f1f1f1);
  //noSrtoke();
  
  float tilesX = 120;
  float tilesY = tilesX;
  
  float tileW = width / tilesX;
  float tileH = height/ tilesY;
  
  translate(-30,-20);
  for (int x = 0; x < tilesX; x++){
    for (int y = 0; y < tilesY; y++){
      int px = int(x*tileW);
      int py = int(y*tileH);
      color c = img.get(px,py);
      
      fill(c);
      
      rect(x*tileW, y*tileH, tilesX, tilesY);
    }
  }
}
1 Like

That’s what I meant too

See above

@Chrisir I’m not sure how to weave your dice code in with my pixelated grid code?

After I add brightness, get pixel color, and map the pixels using the sides of the dice… what do I do next?

color c = img.get(pX, pY);
float b = brightness(c);

float s = map(b, 0, 255, 1, 6); // 1-6 dice sides

I also have the following dice program but I’m not sure how to weave the dice in as the image rasterization.

void setup()
{
  size(500,600);
  textAlign(CENTER);
  noLoop();
}

void draw()
{
  clear();
    int total = 0;
    for (int y = 0; y < 500; y = y + 50) {
      for ( int x = 0; x < 500; x = x + 50) {
        Die die = new Die( x, y);
        die.show();
        print( die.dots );
        total = total + die.dots;
      }
    }
    textSize(24);
    text("Sum : " + total, 250, 550); 
   
}

void mousePressed()
{
    redraw();
}
class Die
{
  //variable declarations here
  int dots;
  int myX;
  int myY;

  Die(int x, int y) //constructor
  {
    roll();
    myX = x;
    myY= y;
  }
  void roll()
  {
    if (random(6) <= 1)
    {
      dots = 1;
    } else if (random(6) <= 2)
    {
      dots = 2;
    } else if (random(6) <= 3)
    {
      dots = 3;
    } else if (random(6) <= 4)
    {
      dots = 4;
    } else if (random(6) <= 5)
    {
      dots = 5;
    } else if (random(6) <= 6)
    {
      dots = 6;
    }
  }
  void show()
  {
    fill(255,255,255);
    rect(myX, myY, 50, 50);
    fill(0, 0, 0);

    if (dots == 1)
    {
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 2)
    {
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 3)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 4)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 5)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 6)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+25, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+40, myY+25, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10);
    }
  }
}

That’s really simple

Instead of using random just pass the s you calculated with
map() to the class dice

like die.show(s);

So that’s the dots in the class

Try to integrate this inside of your nested for loop.
Before the dice part inside the for loop
increase pX and pY by 1

Make sure the for loop matches the number of pixel in your image

You are almost there

OR in the other code replace this

     fill(c);
      
      rect(x*tileW, y*tileH, tilesX, tilesY);

with the s= map… and dice stuff

Like this?

PImage img;

void setup(){
  size(700,700);
  img = loadImage("IMG_7741.jpeg");

}

void draw(){
  background(#f1f1f1);
  //noSrtoke();
  
  float tilesX = 80;
  float tilesY = tilesX;
  
  float tileW = width / tilesX;
  float tileH = height/ tilesY;
  
  translate(-30,-20);
  for (int x = 0; x < tilesX; x++){
    for (int y = 0; y < tilesY; y++){
      int px = int(x*tileW);
      int py = int(y*tileH);
      color c = img.get(px,py);
      
      fill(c);
      
      float b = brightness(c);

      float s = map(b, 0, 255, 1, 6); // 1-6 dice sides
      
      rect(x*tileW, y*tileH, tilesX, tilesY);
      
        Die die = new Die( x, y);
        die.show(s);
        print( die.dots );
        total = total + die.dots;
      }
    }
    }
class Die
{
  //variable declarations here
  int dots;
  int myX;
  int myY;

  Die(int x, int y) //constructor
  {
    roll();
    myX = x;
    myY= y;
  }
  void roll()
  {
    if (s(6) <= 1)
    {
      dots = 1;
    } else if (random(6) <= 2)
    {
      dots = 2;
    } else if (random(6) <= 3)
    {
      dots = 3;
    } else if (random(6) <= 4)
    {
      dots = 4;
    } else if (random(6) <= 5)
    {
      dots = 5;
    } else if (random(6) <= 6)
    {
      dots = 6;
    }
  }
  void show()
  {
    fill(255,255,255);
    rect(myX, myY, 50, 50);
    fill(0, 0, 0);

    if (dots == 1)
    {
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 2)
    {
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 3)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 4)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 5)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 6)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+25, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+40, myY+25, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10);
    }
  }
}

Get rid of this

AND

For Dice use x*tileW, y*tileH

I think x and y will be enough here

Like this? I’m still receiving compiler errors from processing. Thank you for your help!

PImage img;

void setup(){
  size(700,700);
  img = loadImage("IMG_7741.jpeg");

}

void draw(){
  background(#f1f1f1);
  //noSrtoke();
  
  float tilesX = 80;
  float tilesY = tilesX;
  
  float tileW = width / tilesX;
  float tileH = height/ tilesY;
  
  translate(-30,-20);
  for (int x = 0; x < tilesX; x++){
    for (int y = 0; y < tilesY; y++){
      Die die = new Die(x*tileW, y*tileH );
      die.show(s);
      //total = total + die.dots;
      
      int px = int(x);
      int py = int(y);
      color c = img.get(px,py);
      
      fill(c);
      
      float b = brightness(c);

      float s = map(b, 0, 255, 1, 6); // 1-6 dice sides
      
      //rect(x*tileW, y*tileH, tilesX, tilesY);
      
        
      }
   }
}
class Die
{
  //variable declarations here
  int dots;
  int myX;
  int myY;

  Die(float x, float y) //constructor
  {
    roll();
    myX = x;
    myY= y;
  }
  void roll()
  {
    if (s(6) <= 1)
    {
      dots = 1;
    } else if (random(6) <= 2)
    {
      dots = 2;
    } else if (random(6) <= 3)
    {
      dots = 3;
    } else if (random(6) <= 4)
    {
      dots = 4;
    } else if (random(6) <= 5)
    {
      dots = 5;
    } else if (random(6) <= 6)
    {
      dots = 6;
    }
  }
  void show()
  {
    fill(255,255,255);
    rect(myX, myY, 50, 50);
    fill(0, 0, 0);

    if (dots == 1)
    {
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 2)
    {
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 3)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 4)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10);
    } else if (dots == 5)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+25, myY+25, 10, 10);
    } else if (dots == 6)
    { 
      ellipse(myX+10, myY+40, 10, 10); 
      ellipse(myX+10, myY+25, 10, 10); 
      ellipse(myX+10, myY+10, 10, 10); 
      ellipse(myX+40, myY+10, 10, 10); 
      ellipse(myX+40, myY+25, 10, 10); 
      ellipse(myX+40, myY+40, 10, 10);
    }
  }
}

1 Like

This belongs after the line where you define s

Also since you read the source image
in the for loops, they must not exceed width and height of the image (is your image 80x80??)

When you draw on the screen you can use the multiply by tileW …

Please debug your code

Please tell us the errors you get

You are almost there

You forgot to implement your s here -

int s in brackets () and

dots=s;

Delete this please

Thank you