Image manipulation to try to draw with colors that do not exist there

An example result of 'DoMewno' code.
Close-Up Photography of Tabby Cat · Free Stock Photo

 

Description of this image manipulation code.

It's a creative coding image manipulation code made with the 'Processing'.

I tried to draw an image without the color in the original image.
I did not use primary color like RGB nor CMY, I used a +-45 degree phase difference color from the original color.
You can enjoy these results in 3 or 4 meters distance.







 

The 'Processing' example code.

Please feel free to use this Processing example code under the terms of the GPL.
To see other works based on my code is my pleasure. And my honor.


/**
 * DoMewno.
 * Draw original color image WITHOUT original color.
 * run : processing-java --force --sketch=/path/to/DoMewno/ --run "image path"
 * 
 * @author @deconbatch
 * @version 0.1
 * Processing 3.2.1
 * 2019.03.21
 */

/**
 * main
 */
void setup() {

  size(1080, 1080);
  colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
  //  rectMode(CENTER);
  smooth();
  noLoop();
  noStroke();

}

void draw() {

  int caseWidth  = 30;
  int baseCanvas = width - caseWidth * 2;

  // I brought domino pattern parameters in class.
  DominoParams bp = new BackgroundParams();
  DominoParams ep = new EdgeParams();

  ImageLoader imgLoader = new ImageLoader(baseCanvas);
  PImage img = imgLoader.load();

  // edge detection
  int edgeAry[][] = detectEdge(img);
    
  translate((width - img.width) / 2, (height - img.height) / 2);
  background(0.0, 0.0, 90.0, 100.0);

  // draw domino pattern
  putDominos(bp, img, edgeAry);
  putDominos(ep, img, edgeAry);
  
  casing(caseWidth, img.width, img.height);
  saveFrame("frames/0001.png");

  exit();

}

/**
 * putDominos : draw pattern like domino.
 * @param  _dp       : domino pattern parameters class.
 * @param  _img      : origimal photo image.
 * @param  _edge     : detented edge information.
 */
private void putDominos(DominoParams _dp, PImage _img, int[][] _edge) {

  int   initDiv    = _dp.initDiv();

  float colorDiff = 45.0;
  int   halfDiv  = round(initDiv * 0.5);
  
  for (int xInit = 0; xInit < _img.width; xInit += initDiv) {
    for (int yInit = 0; yInit < _img.height; yInit += initDiv) {
      if (_dp.isTarget(_edge, xInit, yInit)) {

        // I want to draw diffrent color like this
        // ---------
        // | - | + |
        // ---------
        // | + | - |
        // ---------
        int xW = constrain(xInit, 0, _img.width - 1);
        int xE = constrain(xInit + halfDiv, 0, _img.width - 1);
        int yN = constrain(yInit, 0, _img.height - 1);
        int yS = constrain(yInit + halfDiv, 0, _img.height - 1);

        paintDiffCol(_img, xW, yN, halfDiv, -colorDiff); // West-North
        paintDiffCol(_img, xW, yS, halfDiv, +colorDiff); // West-South
        paintDiffCol(_img, xE, yN, halfDiv, +colorDiff); // East-North
        paintDiffCol(_img, xE, yS, halfDiv, -colorDiff); // East-South
        
      }
    }
  }
}
        
/**
 * paintDiffCol : paint rect and ellipse with different color.
 * @param  _img               : origimal photo image.
 * @param  _xCorner, _yCorner : West-North point of rect to draw.
 * @param  _size              : width and height of rect to draw.
 * @param  _colorDiff         : phase differenct of color in HSB(360).
 */
private void paintDiffCol(PImage _img, int _xCorner, int _yCorner, int _size, float _colorDiff) {

  int xTo = constrain(_xCorner + _size, 0, _img.width - 1);
  int yTo = constrain(_yCorner + _size, 0, _img.height - 1);
  
  // using RGB to calculate the average hue
  colorMode(RGB);
  int   sumCnt = 0;
  float sumRed = 0.0;
  float sumGre = 0.0;
  float sumBlu = 0.0;
  for (int sumX = _xCorner; sumX < xTo; ++sumX) {
    for (int sumY = _yCorner; sumY < yTo; ++sumY) {
      color pix = _img.pixels[sumY * _img.width + sumX];
      sumRed += red(pix);
      sumGre += green(pix);
      sumBlu += blue(pix);
      ++sumCnt;
    }
  }
  float eHue  = hue(color(sumRed / sumCnt, sumGre / sumCnt, sumBlu / sumCnt));

  // using HSB to calculate the average saturation and brightness
  // Q. Why I do not keep using RGB?
  // A. I need to calculate _colorDiff different hue value. And I don't know how to do it with RGB.
  colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
  sumCnt = 0;
  float sumSat = 0.0;
  float sumBri = 0.0;
  for (int sumX = _xCorner; sumX < xTo; ++sumX) {
    for (int sumY = _yCorner; sumY < yTo; ++sumY) {
      color pix = _img.pixels[sumY * _img.width + sumX];
      sumSat += saturation(pix);
      sumBri += brightness(pix);
      ++sumCnt;
    }
  }
  float eSat = sumSat * 1.1 / sumCnt;
  float eBri = sumBri / sumCnt;
  float eAlp = 100.0;

  fill((eHue + 360 + _colorDiff) % 360.0, eSat, eBri, eAlp);
  rect(_xCorner, _yCorner, _size, _size);
  fill((eHue + 360 - _colorDiff) % 360.0, eSat, eBri, eAlp);
  ellipse(_xCorner + _size * 0.5, _yCorner + _size * 0.5, _size * 0.65, _size * 0.65);

      
}

/**
 * casing : draw fancy casing
 */
private void casing(int _casing, float _w, float _h) {
  fill(0.0, 0.0, 0.0, 0.0);
  strokeWeight(_casing + 4.0);
  stroke(0.0, 0.0, 30.0, 100.0);
  rect(-_casing * 0.5, -_casing * 0.5, _w + _casing, _h + _casing);
  strokeWeight(_casing);
  stroke(0.0, 0.0, 100.0, 100.0);
  rect(-_casing * 0.5, -_casing * 0.5, _w + _casing, _h + _casing);
  noStroke();
  noFill();
}

/**
 * detectEdge : detect edge of photo image.
 * @param  _img      : detect edge of thid image.
 * @return int[x][y] : 2 dimmension array. it holds 0 or 1, 1 = edge
 */
private int[][] detectEdge(PImage _img) {

  int edgeAry[][] = new int[_img.width][_img.height];
  for (int idxW = 0; idxW < _img.width; ++idxW) {  
    for (int idxH = 0; idxH < _img.height; ++idxH) {
      edgeAry[idxW][idxH] = 0;
    }
  }
    
  _img.loadPixels();
  for (int idxW = 1; idxW < _img.width - 1; ++idxW) {  
    for (int idxH = 1; idxH < _img.height - 1; ++idxH) {

      int pixIndex = idxH * _img.width + idxW;

      // saturation difference
      float satCenter = saturation(_img.pixels[pixIndex]);
      float satNorth  = saturation(_img.pixels[pixIndex - _img.width]);
      float satWest   = saturation(_img.pixels[pixIndex - 1]);
      float satEast   = saturation(_img.pixels[pixIndex + 1]);
      float satSouth  = saturation(_img.pixels[pixIndex + _img.width]);
      float lapSat = pow(
                         - satCenter * 4.0
                         + satNorth
                         + satWest
                         + satSouth
                         + satEast
                         , 2);

      // brightness difference
      float briCenter = brightness(_img.pixels[pixIndex]);
      float briNorth  = brightness(_img.pixels[pixIndex - _img.width]);
      float briWest   = brightness(_img.pixels[pixIndex - 1]);
      float briEast   = brightness(_img.pixels[pixIndex + 1]);
      float briSouth  = brightness(_img.pixels[pixIndex + _img.width]);
      float lapBri = pow(
                         - briCenter * 4.0
                         + briNorth
                         + briWest
                         + briSouth
                         + briEast
                         , 2);

      // hue difference
      float hueCenter = hue(_img.pixels[pixIndex]);
      float hueNorth  = hue(_img.pixels[pixIndex - _img.width]);
      float hueWest   = hue(_img.pixels[pixIndex - 1]);
      float hueEast   = hue(_img.pixels[pixIndex + 1]);
      float hueSouth  = hue(_img.pixels[pixIndex + _img.width]);
      float lapHue = pow(
                         - hueCenter * 4.0
                         + hueNorth
                         + hueWest
                         + hueSouth
                         + hueEast
                         , 2);

      // bright and saturation difference
      if (
          brightness(_img.pixels[pixIndex]) > 30.0
          && lapSat > 20.0
          ) edgeAry[idxW][idxH] = 1;

      // bright and some saturation and hue difference
      if (
          brightness(_img.pixels[pixIndex]) > 30.0
          && saturation(_img.pixels[pixIndex]) > 10.0
          && lapHue > 100.0
          ) edgeAry[idxW][idxH] = 1;

      // just brightness difference
      if (lapBri > 100.0) edgeAry[idxW][idxH] = 1;

    }
  }

  return edgeAry;
}

/**
 * ImageLoader : load and resize image
 */
public class ImageLoader {

  PImage imgInit;
  String imgPass;

  ImageLoader(int baseCanvas) {

    if (args == null) {
      // you can use your photo in ./data/your_image.jpg
      imgPass = "your_image.jpg";
    } else {
      // args[0] must be image path
      imgPass = args[0];
    }    
    imgInit = loadImage(imgPass);
      
    float rateSize = baseCanvas * 1.0 / max(imgInit.width, imgInit.height);
    imgInit.resize(floor(imgInit.width * rateSize), floor(imgInit.height * rateSize));

    println(int(imgInit.width)); // Image width
    println(int(imgInit.height)); // Image height

  }

  /**
   * load : return loaded image
   */
  public PImage load() {
    return imgInit;
  }

}

/**
 * DominoParams : holding domino pattern parameters.
 */
interface DominoParams {

  /**
   * isTarget : is this point(x, y) drawing target?
   * @return true : draw target
   */
  Boolean isTarget(int _points[][], int _x, int _y);

  /**
   * just returns parameter value
   */
  int   initDiv();

}

public class BackgroundParams implements DominoParams {
  
  public Boolean isTarget(int _points[][], int _x, int _y) {
    // every point
    return true;
  }

  public int initDiv() {
    return 40;
  }

}

public class EdgeParams implements DominoParams {

  public Boolean isTarget(int _points[][], int _x, int _y) {
    // only edge is target
    if (_points[_x][_y] == 1) {
      return true;
    }
    return false;
  }

  public int initDiv() {
    return 20;
  }
  
}

/*
Copyright (C) 2019- 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 <http://www.gnu.org/licenses/>
*/


 

Yet another example result of this image manipulation.

An example result of 'DoMewno' code.

 

Next Post Previous Post
No Comment
Add Comment
comment url