Adds a tile glass effect on the original image.
The tile glass (or pixelated glass?) effect creative coding.
It's an image manipulation code that adds a tile glass effect on the original image. This code was written in the 'Processing' programming language.
I used the Worley noise method in this code and I calculated the pixel color with the distance from the nearest node like this.
float r = constrain(minDist / _range, 0.0, 1.0);
You can change this calculation formula and you'll get an interesting result.
float r = abs(cos(constrain(minDist / _range, 0.0, 1.0) * PI));
Reference.
Inspired by these cats.
Low Resolution Cats Behind Pixelated Glass Doors.
Worley Noise.
Worley Noise - Coding in the Cabana Challenge #4 · The Coding Train
A similar work using the Worley noise.
Break Up to Make Up : Adding a Cubism taste to the original image.
Looking Through A Stained Glass Darkly.
An example code of the 'Processing'.
This code does not display any images on the screen but generates image files in frames directory.
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.
/**
* These Eyes.
* Adds a tile glass effect on the original image.
* ref. https://www.sadanduseless.com/pixel-cat-windows-gallery/
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.12.23
*/
void setup() {
size(1080, 1080);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
smooth();
noLoop();
}
void draw() {
int caseWidth = 30;
int baseCanvas = width - caseWidth * 2;
PImage img = loadImage("your_photo.jpg");
float rateSize = baseCanvas * 1.0 / max(img.width, img.height);
img.resize(floor(img.width * rateSize), floor(img.height * rateSize));
translate((width - img.width) / 2, (height - img.height) / 2);
// squre mesh
background(0.0, 0.0, 90.0, 100.0);
drawWorley(img, getMesh(img, 40, 0.0), 50.0);
casing(caseWidth, img.width, img.height);
saveFrame("frames/te0001.png");
// with little randomness
background(0.0, 0.0, 90.0, 100.0);
drawWorley(img, getMesh(img, 40, 0.5), 80.0);
casing(caseWidth, img.width, img.height);
saveFrame("frames/te0002.png");
exit();
}
/**
* getMesh : locate Nodes on mesh with some randomness.
* @param _img : original image to get color.
* @param _step : mesh step.
* @param _rate : lack rate, 0.0 : no lack, 1.0 totally lack.
* @return ArrayList<Node> : holds nodes.
*/
public ArrayList<Node> getMesh(PImage _img, int _step, float _rate) {
int start = floor(_step * 0.5);
ArrayList<Node> nodes = new ArrayList<Node>();
_img.loadPixels();
for (int fX = start; fX < _img.width; fX += _step) {
for (int fY = start; fY < _img.height; fY += _step) {
if (random(1.0) >= _rate) {
// add node
int pixIndex = floor(fY * _img.width + fX);
nodes.add(new Node(
fX,
fY,
hue(_img.pixels[pixIndex]),
saturation(_img.pixels[pixIndex]),
brightness(_img.pixels[pixIndex])
));
}
}
}
return nodes;
}
/**
* drawWorley : draw
* @param _img : original image.
* @param _nodes : point's location and color.
* @param _range : distance range, lower value will make strong result.
*/
public void drawWorley(PImage _img, ArrayList<Node> _nodes, float _range) {
noFill();
strokeWeight(1.0);
float heighValue = _img.width + _img.height;
for (int iX = 0; iX < _img.width; iX++) {
for (int iY = 0; iY < _img.height; iY++) {
// get nearest node
int minIndx = 0;
float minDist = heighValue;
for (int i = 0; i < _nodes.size(); i++) {
float distance = dist(iX, iY, _nodes.get(i).x, _nodes.get(i).y);
if (minDist > distance) {
minIndx = i;
minDist = distance;
}
}
Node n = _nodes.get(minIndx);
float t = atan2(iY - n.y, iX - n.x);
float r = constrain(minDist / _range, 0.0, 1.0);
int nX = round(n.x + minDist * r * cos(t));
int nY = round(n.y + minDist * r * sin(t));
int nI = floor(nY * _img.width + nX);
float sHue = hue(_img.pixels[nI]);
float sSat = saturation(_img.pixels[nI]) * (1.0 + r) * 0.8;
float sBri = brightness(_img.pixels[nI]) * (1.2 - r * 0.3);
stroke(sHue, sSat, sBri, 100.0);
point(iX, iY);
}
}
}
/**
* casing : draw fancy casing
*/
public 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);
}
/**
* Node : draw and hold location and color.
*/
public class Node {
public int x, y; // location of point
// did not use this time.
private float hueVal; // hue value of point
private float satVal; // saturation value of point
private float briVal; // brightness value of point
Node(int _x, int _y, float _c, float _s, float _b) {
x = _x;
y = _y;
hueVal = _c;
satVal = _s;
briVal = _b;
}
}
/*
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/>
*/