Life Gameow

Applying Conway's Game of Life to photo images.

Image manipulation example with the image from
Orange And White Cat Closeup
http://www.photos-public-domain.com/2011/01/07/orange-and-white-cat-closeup/



Applying Conway's Game of Life to photo images.

Image manipulation example with the image from
Two Tabby Cats
http://www.photos-public-domain.com/2016/11/15/two-tabby-cats/


Description of this creative coding.

It's an image manipulation type creative coding example made with Processing.

I tried to apply Conway's Game of Life to photo images.
Hue, Brightness, Saturation, and Alpha. Brightness is easy to apply out of these, I think.

You can see stable patterns in it.
You can see the stable patterns of Conway's Game of Life.


At first,
    Alive cell : brightness = 80
    Dead cell : brightness = 20
It's not bad.
Applying Conway's Game of Life to photo images.


But I like this. You can see the result above.
    Alive cell : ++brightness
    Dead cell : --brightness

An important point of this code is 'How to find dead/alive border'.

You can use your own photo.
You can hard coding the path of your photo image file or you can give command line parameter like this.

/your_processing_installed_path/processing-java --force --sketch=/your_sketch_path/ --run /your_photo_file_path

Correction of my mistaken code.

Oh! I made a mistake.
I always do. But I realized it this time.

I had to apply Conway's Life Game rule to separate array.
My code influence the rule from the left upper to right lower.

Then
conwaysLifeGame()
 ↓
notConwaysLifeGame()
Fixed! ;-)

Example code of Processing.

Please feel free to use this code, if you like it.
To see another works based on my code is my pleasure. And my honor.


// LifeGameow.
// @author @deconbatch
// @version 0.2
// Processing 3.2.1
// 0.1 2018.01.14
// 0.2 2018.12.23

/* ---------------------------------------------------------------------- */

float canvasW, canvasH;
float rateSize;

void setup() {
  size(1000, 1000);
  
  colorMode(HSB, 360, 100, 100, 100);
  noStroke();
  smooth(8);
  noLoop();

}

void draw() {

  PImage imgInit, imgWork;

  float baseWH        = 900;
  float maxBrightness = 0.0;
  int   borderRatio   = 40; // percentage

  if (args == null) {
    // you can use your photo in ./data/your_image.jpg
    imgInit = loadImage("your_image.jpg");
  } else {
    // args[0] must be image path
    imgInit = loadImage(args[0]);
  }

  // fit to canvas size
  rateSize = baseWH / max(imgInit.width, imgInit.height);
  canvasW  = imgInit.width * rateSize;
  canvasH  = imgInit.height * rateSize;
  imgInit.resize(int(canvasW), int(canvasH));
  imgInit.loadPixels();
  
  float[] calcArray = new float[imgInit.pixels.length]; // for life game calculation
  int[]   briArray  = new int[101]; // pixel count per brightness 0-100
  for (int idxW = 1; idxW < imgInit.width - 1; ++idxW) {  
    for (int idxH = 1; idxH < imgInit.height - 1; ++idxH) {
      int idxPoint = idxH * imgInit.width + idxW;
      calcArray[idxPoint] = brightness(imgInit.pixels[idxPoint]);
      ++briArray[int(brightness(imgInit.pixels[idxPoint]))];
    }
  }

  // life game dead or alive border brightness value
  int borderBrightness = 0;
  int countPixels      = 0;
  int noPixels         = int(canvasW * canvasH);
  for (borderBrightness = 100; borderBrightness > 0; --borderBrightness) {
    countPixels += briArray[borderBrightness];
    if (100 * countPixels / noPixels >= borderRatio) {
      break;
    }      
  }

  blendMode(SCREEN);
  background(0, 0, maxBrightness);
  translate((width - canvasW) / 2, (height - canvasH) / 2);

  imgWork = notConwaysLifeGame(imgInit.copy(), calcArray.clone(), 300, 0.1, borderBrightness);
  image(imgWork, 0.0, 0.0);

  imgWork = notConwaysLifeGame(imgInit.copy(), calcArray.clone(), 120, 0.6, borderBrightness);
  image(imgWork, 0.0, 0.0);

  imgWork = notConwaysLifeGame(imgInit.copy(), calcArray.clone(), 30, 10.0, borderBrightness);
  image(imgWork, 0.0, 0.0);


  saveFrame("frames/####.png");
  exit();

}

/* ---------------------------------------------------------------------- */

PImage notConwaysLifeGame(PImage pImg, float[] pCalcArray, int pCicleNoMax, float pDivLife, int pBorder) {

  float borderAlive = pBorder * 1.0;
  
  for (int cicleNo = 1; cicleNo < pCicleNoMax; ++cicleNo) {
 
    for (int idxW = 1; idxW < pImg.width - 1; ++idxW) {  
      for (int idxH = 1; idxH < pImg.height - 1; ++idxH) {

        int aliveNum = 0;
        int idxPoint = idxH * pImg.width + idxW;
        aliveNum += deadOrAlive(pCalcArray[idxPoint - 1], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint + 1], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint - pImg.width], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint - pImg.width - 1], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint - pImg.width + 1], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint + pImg.width], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint + pImg.width - 1], borderAlive);
        aliveNum += deadOrAlive(pCalcArray[idxPoint + pImg.width + 1], borderAlive);
        
        color cPoint = pImg.pixels[idxPoint];
        float valHue = hue(cPoint);
        float valSat = saturation(cPoint);
        float valBri = brightness(cPoint);
        float valAlp = 100.0;

        // birth
        if (aliveNum == 3) {
          valBri += pDivLife;
          valSat += pDivLife / 2.0;
          pCalcArray[idxPoint] = 100.0;
        }
        // die
        if (aliveNum <= 1 || aliveNum >= 4) {
          valBri -= pDivLife;
          valSat -= pDivLife / 2.0;
          pCalcArray[idxPoint] = 0.0;
        }

        valSat = withinRange(valSat);
        valBri = withinRange(valBri);

        pImg.pixels[idxPoint] = color(valHue, valSat, valBri, valAlp);

      }
    }

  }

  pImg.updatePixels();
  return pImg;

}

int deadOrAlive(float pVal, float pBorder) {
  if (pVal > pBorder) {
    return 1;
  }
  return 0;
}

float withinRange(float val) {
  return max(3.0, min(100.0, val));
}


/*
Copyright (C) 2018- deconbatch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see 
*/





No comments :

Post a Comment