It draws an image like a multi-point perspective drawing with random walking.
http://www.photos-public-domain.com/2016/11/15/two-tabby-cats/
Multi-point perspective drawing with random walking of three primary colors.
It's a Image Manipulation type creative coding made with Processing. It draws an image like a multi point perspective drawing with random walking of three primary colors.
The beginShape(QUAD_STRIP) and the beginShape(LINES) creates this perspective drawing feeling.
The blendMode(SUBTRACT) reproduces the original image with three primary colors. And I found that these three primary colors (I called so) are any three hue values with a 120-degree difference each other!
You can use your photo with this code.
example : if your photo file is './data/your_photo.jpg'.
PImage img = loadImage("your_photo.jpg");
An example source code of Processing.
This code does not display any images on the screen but generates image files in frames directory.
You can make an animation with these files.
Please feel free to use this example code under the terms of the GPL.
To see other works based on my code is my pleasure. And my honor.
/**
* Purrspective.
* It draws an image like a multi point perspective drawing with random walking of three primary colors.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.09.26
*/
void setup() {
size(980, 980, P2D);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
strokeJoin(ROUND);
strokeCap(PROJECT);
noLoop();
}
void draw() {
PImage img = loadImage("your_photo.jpg");
int caseWidth = 36;
int baseCanvas = max(width, height) - caseWidth * 2;
float rateSize = baseCanvas * 1.0 / max(img.width, img.height);
img.resize(floor(img.width * rateSize), floor(img.height * rateSize));
img.loadPixels();
int iW = img.width;
int iH = img.height;
int steps = iW * iH / 3600;
float slant = PI * 0.25 * floor(random(2.0));
float hueDiv = random(360.0);
pushMatrix();
translate((width - iW) / 2, (height - iH) / 2);
ArrayList<ArrayList<PVector>> paths = new ArrayList<ArrayList<PVector>>();
// draw first primary color
paths.clear();
paths = getPaths(iW, iH, 75, 10, steps * 6, slant);
blendMode(BLEND);
background(0.0, 0.0, 90.0, 100.0);
blendMode(SUBTRACT);
drawPath(paths, img, iW, (0.0 + hueDiv) % 360.0);
blendMode(BLEND);
casing(iW, iH, caseWidth);
saveFrame("frames/pp0001.png");
// draw second primary color
paths.clear();
paths = getPaths(iW, iH, 100, 20, steps * 6, slant);
blendMode(BLEND);
background(0.0, 0.0, 90.0, 100.0);
blendMode(SUBTRACT);
drawPath(paths, img, iW, (120.0 + hueDiv) % 360.0);
blendMode(BLEND);
casing(iW, iH, caseWidth);
saveFrame("frames/pp0002.png");
// draw third primary color
paths.clear();
paths = getPaths(iW, iH, 50, 5, steps * 6, slant);
blendMode(BLEND);
background(0.0, 0.0, 90.0, 100.0);
blendMode(SUBTRACT);
drawPath(paths, img, iW, (240.0 + hueDiv) % 360.0);
blendMode(BLEND);
casing(iW, iH, caseWidth);
saveFrame("frames/pp0003.png");
// draw with three primary colors
paths.clear();
paths.addAll(getPaths(iW, iH, 75, 10, steps, slant));
paths.addAll(getPaths(iW, iH, 100, 20, steps, slant));
paths.addAll(getPaths(iW, iH, 50, 5, steps, slant));
blendMode(BLEND);
background(0.0, 0.0, 90.0, 100.0);
blendMode(SUBTRACT);
drawPath(paths, img, iW, (0.0 + hueDiv) % 360.0);
drawPath(paths, img, iW, (120.0 + hueDiv) % 360.0);
drawPath(paths, img, iW, (240.0 + hueDiv) % 360.0);
blendMode(BLEND);
casing(iW, iH, caseWidth);
saveFrame("frames/pp0004.png");
popMatrix();
exit();
}
/**
* getPaths : calculate the random walking paths.
* @param _xMax, _yMax : width and height of walking area.
* @param _pathMax : path number.
* @param _locateDiv : minimum distance of path start locations.
* @param _stepMax : step number of each path.
* @param _slant : slant of walking.
*/
ArrayList<ArrayList<PVector>> getPaths(int _xMax, int _yMax, int _pathMax, int _locateDiv, int _stepMax, float _slant) {
ArrayList<ArrayList<PVector>> paths = new ArrayList<ArrayList<PVector>>();
for (int pathCnt = 0; pathCnt < _pathMax; pathCnt++) {
ArrayList<PVector> path = new ArrayList<PVector>();
// path start location
int x = floor(random(_xMax * 1.0 / _locateDiv)) * _locateDiv;
int y = floor(random(_yMax * 1.0 / _locateDiv)) * _locateDiv;
float slant = (sin(_slant) == 0.0) ? HALF_PI : _slant; // avoid 0 divide
float stepDiv = 25.0 / sin(slant); //20.0 ... 30.0 may be good
for (int stepCnt = 0; stepCnt < _stepMax; stepCnt++) {
float theta = slant + TWO_PI * floor(random(4.0)) / 4.0;
x += round(stepDiv * cos(theta));
y += round(stepDiv * sin(theta));
if (x >= _xMax || x <= 0 || y >= _yMax || y <= 0) {
break;
}
path.add(new PVector(x, y));
}
paths.add(path);
}
return paths;
}
/**
* drawPath : draw perspective drawing.
* tuning alpha value with distance from drawing primary color.
* @param _paths : array of path. it must be nest for vertex.
* @param _img : original image.
* @param _iW : original image's width. for calculating pixel location.
* @param _hueVal : drawing primary color.
*/
void drawPath(ArrayList<ArrayList<PVector>> _paths, PImage _img, int iW, float _hueVal) {
for (ArrayList<PVector> path : _paths) {
noStroke();
beginShape(QUAD_STRIP);
for (PVector p : path) {
int pIdx = floor(p.y * iW + p.x);
float hueDiv = abs(hue(_img.pixels[pIdx]) - _hueVal);
float pAlp = (hueDiv > 180 ? 360.0 - hueDiv : hueDiv) / 180.0;
fill(
_hueVal,
100.0 - saturation(_img.pixels[pIdx]),
100.0 - brightness(_img.pixels[pIdx]),
10.0 * pAlp
);
vertex(p.x, p.y);
}
endShape();
noFill();
strokeWeight(floor(random(1.0, 3.0)));
beginShape(LINES);
for (PVector p : path) {
int pIdx = floor(p.y * iW + p.x);
float hueDiv = abs(hue(_img.pixels[pIdx]) - _hueVal);
float pAlp = (hueDiv > 180 ? 360.0 - hueDiv : hueDiv) / 180.0;
stroke(
_hueVal,
100.0 - saturation(_img.pixels[pIdx]),
100.0 - brightness(_img.pixels[pIdx]),
100.0 * pAlp
);
vertex(p.x, p.y);
}
endShape();
}
}
/**
* casing : draw fancy casing
* @param _w, _h : width and height of drawing area.
* @param _caseWidth : border width of the case.
*/
public void casing(float _w, float _h, float _caseWidth) {
pushMatrix();
translate(_w * 0.5, _h * 0.5);
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(_caseWidth * 0.85);
stroke(0.0, 0.0, 30.0, 100.0);
rect(0.0, 0.0, _w + _caseWidth * 1.25, _h + _caseWidth * 1.25);
strokeWeight(_caseWidth * 0.75);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, _w + _caseWidth * 1.25, _h + _caseWidth * 1.25);
noStroke();
noFill();
popMatrix();
}
/*
Copyright (C) 2020- 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 image.
With the image fromOrange And White Cat Closeup
http://www.photos-public-domain.com/2011/01/07/orange-and-white-cat-closeup/