# The 'Processing' code processes the image to the Vector Field.

The original image is the photo of the Gargano National Park.

## This creative coding process the image hard!

This is the creative coding of image processing. It was written in the 'Processing'.

It's a near relation work of 'Daydream'. It uses the Vector Field method to process the image. It starts the Vector Field from the points of edges in the image.

You can use your photo to process.

`PImage img = loadImage("your_photo.png");`

### The keys of this code.

One of the keys of this code is using nested 3D noise to calculate the Vector Field.

`noise(xPrev * _noiseDiv, yPrev * _noiseDiv, noise(yPrev * _noiseDiv * 3.0) * _uneven)`

Ordinary, I use 2D noise like 'noise(x, y)'.

And I found the interesting effect when I used nested 3D noise like 'noise(x, y, noise(x, y))'.

And the other key of this code is limiting the direction of the path of the Vector Field.

`cos(TWO_PI * round(nX * _curlMult * _angles) / _angles)`

An example image : no limitting.

An example image : limitting the direction.

## An example code that was written in 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.

``````
/**
* Picture This.
* The Vector field that starts from the edges of some photo.
*
* @author @deconbatch
* @version 0.1
* Processing 3.5.3
* 2020.11.19
*/

void setup() {

size(980, 980);
colorMode(HSB, 360, 100, 100, 100);
smooth();
noLoop();

}

void draw() {

int imgMax     = 3;
int initMax    = 5000;
int caseWidth  = 30;
int baseCanvas = width - caseWidth * 2;

float rateSize = baseCanvas * 1.0 / max(img.width, img.height);
img.resize(floor(img.width * rateSize), floor(img.height * rateSize));

// detect edges
ArrayList<PVector> edges = detectEdge(img, initMax);
float initHue = typicalHue(img, edges) + 120.0;

for (int imgCnt = 0; imgCnt < imgMax; imgCnt++) {

float curlMult = random(4.0,8.0);
float noiseDiv = 0.006 / curlMult;
float uneven   = random(5.0, 10.0);
float baseSiz  = 1.5;
initHue += 30.0;

// calculate the vector field
ArrayList<ArrayList<PVector>> paths = getPaths(edges, curlMult, noiseDiv, uneven, imgCnt * 2 + 5);

// draw background
pushMatrix();
translate((width - img.width) / 2, (height - img.height) / 2);
background(initHue % 360.0, 80.0, 60.0, 100);
noStroke();

blendMode(DARKEST);
for (ArrayList<PVector> path : paths) {
float xInit = path.get(0).x;
float yInit = path.get(0).y;
float xPoint = xInit;
float yPoint = yInit;
int pIdx = floor(yPoint * img.width + xPoint);
float baseHue = hue(img.pixels[pIdx]);
float baseBri = brightness(img.pixels[pIdx]);
for (int i = 0; i < path.size(); i++) {
PVector p = path.get(i);
float pRatio = i * 1.0 / path.size();
float eHue = baseHue + floor(((xInit * yInit) * 1.0) % 4.0) * 20.0;
float eBri = baseBri * sin(PI * pRatio) * (8.0 + floor(((xInit * yInit) * 20000.0) % 5.0)) / 30.0;
float eSiz = baseSiz * sin(PI * pRatio);
fill(eHue % 360.0, 100.0, eBri, 100);
translate(eSiz * 2.0, eSiz * 2.0);
ellipse(p.x, p.y, eSiz, eSiz);
translate(-eSiz * 2.0, -eSiz * 2.0);
}
}

// draw foreground
blendMode(LIGHTEST);
for (ArrayList<PVector> path : paths) {
float xInit = path.get(0).x;
float yInit = path.get(0).y;
float xPoint = xInit;
float yPoint = yInit;
int pIdx = floor(yPoint * img.width + xPoint);
float baseHue = hue(img.pixels[pIdx]);
float baseBri = brightness(img.pixels[pIdx]);
for (int i = 0; i < path.size(); i++) {
PVector p = path.get(i);
float pRatio = i * 1.0 / path.size();
float eHue = baseHue + floor(((xInit * yInit) * 1.0) % 4.0) * 20.0;
float eSat = map(sin(PI * pRatio), 0.0, 1.0, 70.0, 90.0) * (6.0 + floor(((xInit * yInit) * 30000.0) % 4.0)) / 9.0;
float eBri = baseBri * sin(PI * pRatio) * (8.0 + floor(((xInit * yInit) * 20000.0) % 5.0)) / 10.0;
float eSiz = baseSiz * sin(PI * pRatio);
fill(eHue % 360.0, eSat, eBri, 100.0);
ellipse(p.x, p.y, eSiz, eSiz);
}
}
popMatrix();

casing();
saveFrame("frames/" + String.format("%04d", imgCnt + 1) + ".png");

}

exit();

}

/**
* casing : draw fancy casing
*/
private void casing() {
blendMode(BLEND);
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(60.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(50.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
noStroke();
noFill();
}

/**
* getPaths : calculate the Vector Field paths.
* @param _pvs      : start points coordinate of the Vector Field.
* @param _curlMult : curl ratio of the path.
* @param _noiseDiv : noise parameter step ratio.
* @param _uneven   : make uneven the Vector Field with 3rd parameter of the noise.
* @param _angles   : slant of the path.
* @return array of the Vector Field path, path is the array of the PVector coordinates.
*/
private ArrayList<ArrayList<PVector>> getPaths(ArrayList<PVector> _pvs, float _curlMult, float _noiseDiv, float _uneven, int _angles) {

int   plotMax = 2000;
float plotDiv = 0.2;
ArrayList<ArrayList<PVector>> paths = new ArrayList<ArrayList<PVector>>();

for (PVector p : _pvs) {

ArrayList<PVector> path = new ArrayList<PVector>();

float xInit = p.x;
float yInit = p.y;
float xPoint = xInit;
float yPoint = yInit;

for (int plotCnt = 0; plotCnt < plotMax; ++plotCnt) {
float xPrev = xPoint;
float yPrev = yPoint;
float nX = noise(xPrev * _noiseDiv, yPrev * _noiseDiv, noise(yPrev * _noiseDiv * 3.0) * _uneven);
float nY = noise(yPrev * _noiseDiv, xPrev * _noiseDiv, noise(xPrev * _noiseDiv * 3.0) * _uneven);
xPoint += plotDiv * cos(TWO_PI * round(nX * _curlMult * _angles) / _angles);
yPoint += plotDiv * sin(TWO_PI * round(nY * _curlMult * _angles) / _angles);
}
if (dist(path.get(0).x, path.get(0).y, path.get(path.size() - 1).x, path.get(path.size() - 1).y) > 20.0) {
}
}
return paths;
}

/**
* detectEdge : detect edges of photo image.
* @param  _img     : detect edges of this image.
* @param  _edgeNum : return edge points number.
* @return array of the edges locations.
*/
private ArrayList<PVector> detectEdge(PImage _img, int _edgeNum) {

ArrayList<PVector> edges = new ArrayList<PVector>();

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]) > 40.0
&& lapSat > 30.0

// bright and some saturation and hue difference
if (
brightness(_img.pixels[pixIndex]) > 40.0
&& saturation(_img.pixels[pixIndex]) > 20.0
&& lapHue > 100.0

// just brightness difference
if (
lapBri > 100.0

}
}

int removeCnt = edges.size() - _edgeNum;
for (int i = 0; i < removeCnt; i++) {
edges.remove(floor(random(edges.size())));
}

return edges;

}

/**
* typicalHue : detect typical hue value.
* @param  _img : pick up hue value from this image.
* @param  _pvs : coordinates in _img.
* @return hue value.
*/
private float typicalHue(PImage _img, ArrayList<PVector> _pvs) {

int[] cnt = new int[12];
for (int i : cnt) {
i = 0;
}

for (PVector p : _pvs) {
int pIdx = floor(p.y * _img.width + p.x);
cnt[floor(hue(_img.pixels[pIdx]) / 30.0)]++;
}

int hueValue = 0;
int maxNum   = 0;
for (int i = 0; i < 12; i++) {
if (cnt[i] > maxNum) {
hueValue = i;
maxNum = cnt[i];
}
}

return hueValue * 30.0;

}

/*

This program is free software: you can redistribute it and/or modify
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/>
*/
```
```