Hi,
How can I import a black an white image and apply a patter like the image that I attached in this message?
Hope someone can help,
Thanks !
Hi,
How can I import a black an white image and apply a patter like the image that I attached in this message?
Hope someone can help,
Thanks !
HI @josephh
Exactly ! I followed that tutorial and now Iām trying to import an image and to apply the reaction diffusion,
Cheers
Glad to see that itās what you were looking for, donāt hesitate to post your solution
Hi @alice ā were you able to get the tutorial working?
Hi !
still working on It
If you have code in progress that you would like to share with more specific questions, feel free to do that here.
Hi @jeremydouglass , thanks, I managed to have the code and Iām sharing with you It!
Now I have the Reaction Diffusion based on points, what I want to do now is to add a black and white image inside the code and in the ācondition loopā I want to apply the reaction diffusion only where the color is blackā¦ Do you have any idea how to do It ?
Iām sending you the code and a reference image ( the image can be any in black and white)
import java.awt.Color;
Cell[][] grid;
Cell[][] prev;
void setup() {
size(300, 300);
grid = new Cell[width][height];
prev = new Cell[width][height];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j ++) {
float a = 1;
float b = 0;
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
for (int n = 0; n < 50; n++) {
int startx = int(random(20, width-20));
int starty = int(random(20, height-20));
for (int i = startx; i < startx+10; i++) {
for (int j = starty; j < starty+10; j ++) {
float a = 5;
float b = 5;
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
}
}
float dA = 1.0;
float dB = 0.5;
float feed = 0.08;
float k = 0.06;
class Cell {
float a;
float b;
Cell(float a_, float b_) {
a = a_;
b = b_;
}
}
void update() {
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = prev[i][j];
Cell newspot = grid[i][j];
float a = spot.a;
float b = spot.b;
float laplaceA = 0;
laplaceA += a*-1;
laplaceA += prev[i+1][j].a*0.2;
laplaceA += prev[i-1][j].a*0.2;
laplaceA += prev[i][j+1].a*0.2;
laplaceA += prev[i][j-1].a*0.2;
laplaceA += prev[i-1][j-1].a*0.05;
laplaceA += prev[i+1][j-1].a*0.05;
laplaceA += prev[i-1][j+1].a*0.05;
laplaceA += prev[i+1][j+1].a*0.05;
float laplaceB = 0;
laplaceB += b*-1;
laplaceB += prev[i+1][j].b*0.2;
laplaceB += prev[i-1][j].b*0.2;
laplaceB += prev[i][j+1].b*0.2;
laplaceB += prev[i][j-1].b*0.2;
laplaceB += prev[i-1][j-1].b*0.05;
laplaceB += prev[i+1][j-1].b*0.05;
laplaceB += prev[i-1][j+1].b*0.05;
laplaceB += prev[i+1][j+1].b*0.05;
newspot.a = a + (dA*laplaceA - a*b*b + feed*(1-a))*1;
newspot.b = b + (dB*laplaceB + a*b*b - (k+feed)*b)*1;
newspot.a = constrain(newspot.a, 0, 1);
newspot.b = constrain(newspot.b, 0, 1);
}
}
}
void swap() {
Cell[][] temp = prev;
prev = grid;
grid = temp;
}
void draw() {
//println(frameRate);
for (int i = 0; i < 1; i++) {
update();
swap();
}
loadPixels();
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = grid[i][j];
float a = spot.a;
float b = spot.b;
int pos = i + j * width;
//pixels[pos] = color((a-b)*255);
color aColor = color (0, 0, 0);
color bColor = color (255, 255, 255);
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
Iām trying to follow some tutorials online to undertstand how to do It, If you have any tricks please share !
Thanks!
Sure. Just load a PImage, then copy its darkest pixels into your Cells. Thatās it!
Add this line to your header:
PImage img;
This to the top of your setup loop:
void setup(){
size(512, 512); // match image size here -- then use that to make Cells
img = loadImage("https://processing.org/img/processing3-logo.png");
img.loadPixels();
and in your Cell initialization loop, change a=1; b=0; to this:
if(brightness(img.get(i,j))>16){ // values lighter than 16 are not drawn
a = 1;
b = 0;
} else {
a = 5;
b = 5;
}
You can delete the second (random dot creation) loop entirely, now that you have image data instead.
Here is the modified sketch:
// reaction diffusion -- add image
// https://discourse.processing.org/t/import-image-and-apply-pattern/12229/8
import java.awt.Color;
PImage img;
Cell[][] grid;
Cell[][] prev;
void setup() {
size(512, 512);
grid = new Cell[width][height];
prev = new Cell[width][height];
img = loadImage("https://processing.org/img/processing3-logo.png");
img.loadPixels();
float a = 1;
float b = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j ++) {
if (brightness(img.get(i, j))>16) {
a = 1;
b = 0;
} else {
a = 5;
b = 5;
}
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
}
float dA = 1.0;
float dB = 0.5;
float feed = 0.08;
float k = 0.06;
class Cell {
float a;
float b;
Cell(float a_, float b_) {
a = a_;
b = b_;
}
}
void update() {
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = prev[i][j];
Cell newspot = grid[i][j];
float a = spot.a;
float b = spot.b;
float laplaceA = 0;
laplaceA += a*-1;
laplaceA += prev[i+1][j].a*0.2;
laplaceA += prev[i-1][j].a*0.2;
laplaceA += prev[i][j+1].a*0.2;
laplaceA += prev[i][j-1].a*0.2;
laplaceA += prev[i-1][j-1].a*0.05;
laplaceA += prev[i+1][j-1].a*0.05;
laplaceA += prev[i-1][j+1].a*0.05;
laplaceA += prev[i+1][j+1].a*0.05;
float laplaceB = 0;
laplaceB += b*-1;
laplaceB += prev[i+1][j].b*0.2;
laplaceB += prev[i-1][j].b*0.2;
laplaceB += prev[i][j+1].b*0.2;
laplaceB += prev[i][j-1].b*0.2;
laplaceB += prev[i-1][j-1].b*0.05;
laplaceB += prev[i+1][j-1].b*0.05;
laplaceB += prev[i-1][j+1].b*0.05;
laplaceB += prev[i+1][j+1].b*0.05;
newspot.a = a + (dA*laplaceA - a*b*b + feed*(1-a))*1;
newspot.b = b + (dB*laplaceB + a*b*b - (k+feed)*b)*1;
newspot.a = constrain(newspot.a, 0, 1);
newspot.b = constrain(newspot.b, 0, 1);
}
}
}
void swap() {
Cell[][] temp = prev;
prev = grid;
grid = temp;
}
void draw() {
//println(frameRate);
for (int i = 0; i < 1; i++) {
update();
swap();
}
loadPixels();
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = grid[i][j];
float a = spot.a;
float b = spot.b;
int pos = i + j * width;
//pixels[pos] = color((a-b)*255);
color aColor = color (0, 0, 0);
color bColor = color (255, 255, 255);
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
The following are suggestions on style that wonāt affect what your code draws:
Your Cell class is good but not strictly necessary. Processing already has a built in class for holding two floats that you could use insteadāit is PVector, and you can store your floats in vec.x, vec.y rather than cell.a, cell.b if you wish.
You could also move aColor, bColor to the header and define them in setup ā no need to declare repeatedly in an inner loop.
Likewise, no need to shuffle spot.a and spot.b variables around into other variables āaā ābā ā just use them directly.
{
Cell spot = grid[i][j];
pixels[i + j * width] = lerpColor(aColor, bColor, (spot.a-spot.b));
}
Hi @jeremydouglass ! THANK YOU !!
I actually donāt know how to use PVector as you explainedā¦If you donāt mind can you please show me how do It in my code , Iām curious to see how you do It and to learn to do It,
Anyway thanks a lot for your help !!
Just replace āCellā with āPVectorā and .a .b with .x .y. Thatās it, really.
However, you donāt gain anything by this in your current sketch. If in the future you wanted to do other things to your cell values ā like scale them all at the same time, for example ā then PVector has lots of pre-built-in methods to help you loop over your cells and do a/b math to them. If you go in a different direction, then having Cell is convenient for simply adding your own methods.
Hi @jeremydouglass , Thanks a lot for your help !
Iāll try for sure !
You have been so helpful, I appreciate It !
Thanks again
Thanks everybody for your precious help, so far Iām playing with the code to have different results.
What Iām trying to do now is to apply the reaction diffusion only in one part of the grid ( example right or left ) , something like the image that I uploaded ,
PS: Do you think the coefficent Time can help to have the pattern only in some parts ?
This is the image that I have imported in the code :
import java.awt.Color;
PImage img;
Cell[][] grid;
Cell[][] prev;
void setup() {
size(305, 305);
grid = new Cell[width][height];
prev = new Cell[width][height];
img = loadImage("2.PNG");
img.loadPixels();
float a = 1;
float b = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j ++) {
if (brightness(img.get(i, j))>16) {
a = 1;
b = 0;
} else {
a = 5;
b = 5;
}
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
}
float dA = 1.0;
float dB = 0.5;
float feed = 0.08;
float k = 0.06;
class Cell {
float a;
float b;
Cell(float a_, float b_) {
a = a_;
b = b_;
}
}
void update() {
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = prev[i][j];
Cell newspot = grid[i][j];
float a = spot.a;
float b = spot.b;
float laplaceA = 0;
laplaceA += a*-1;
laplaceA += prev[i+1][j].a*0.2;
laplaceA += prev[i-1][j].a*0.2;
laplaceA += prev[i][j+1].a*0.2;
laplaceA += prev[i][j-1].a*0.2;
laplaceA += prev[i-1][j-1].a*0.05;
laplaceA += prev[i+1][j-1].a*0.05;
laplaceA += prev[i-1][j+1].a*0.05;
laplaceA += prev[i+1][j+1].a*0.05;
float laplaceB = 0;
laplaceB += b*-1;
laplaceB += prev[i+1][j].b*0.2;
laplaceB += prev[i-1][j].b*0.2;
laplaceB += prev[i][j+1].b*0.2;
laplaceB += prev[i][j-1].b*0.2;
laplaceB += prev[i-1][j-1].b*0.05;
laplaceB += prev[i+1][j-1].b*0.05;
laplaceB += prev[i-1][j+1].b*0.05;
laplaceB += prev[i+1][j+1].b*0.05;
newspot.a = a + (dA*laplaceA - a*b*b + feed*(1-a))*1;
newspot.b = b + (dB*laplaceB + a*b*b - (k+feed)*b)*1;
newspot.a = constrain(newspot.a, 0, 1);
newspot.b = constrain(newspot.b, 0, 1);
}
}
}
void swap() {
Cell[][] temp = prev;
prev = grid;
grid = temp;
}
void draw() {
//println(frameRate);
for (int i = 0; i < 1; i++) {
update();
swap();
}
loadPixels();
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = grid[i][j];
float a = spot.a;
float b = spot.b;
int pos = i + j * width;
//pixels[pos] = color((a-b)*255);
color aColor = color (0, 0, 0);
color bColor = color (255, 255, 255);
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
please format your forum code with the </> button, or with three ticks ``` ā not < and >
Here is where you are currently copying your reaction diffusion onto the visible canvas.
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
// ...
pixels[pos] = lerpColor(aColor, bColor, (a-b));
It sounds like you only want to do that pixel copy if (i, j) is inside one or more defined rectangles. You could use point-rect collision detection to check whether this is true.
You could calculate this each time for each pixel ā is the pixel inside the rectangle? If so, copy the value to the canvas.
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
if(pointRect(i, j, rx, ry, rw, rh){
// ...
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
Or, to manage complex regions like in your right-hand example (multiple rectanges, triangles, circles, etc.) you could use a mask image. Then you will be computing the whole image every time, but only showing part of it through the mask onto the canvas.
A third approach is manual masking. Create a PGraphics, and draw some black on it (rectangles, triangles, whatever). Then compute and copy your reaction diffusion pixel to the canvas ONLY if the corresponding pixel on your PGraphics is marked. This means you neednāt bother computing any pixel that isnāt marked on your manual mask.
if(myMask.get(i,j) != emptypixel){
// ...
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
HI @jeremydouglass , thanks again for your quick reply, I have tried the third approch with mask : I made 2 images with the same size and I imported both inside the code , one as a image and one as a mask, I got the error that āemptyPixels cannot be resolved to a variableā , this is how I changed the code :
import java.awt.Color;
PImage img, maskImage;
Cell[][] grid;
Cell[][] prev;
void setup() {
size(364, 364);
grid = new Cell[width][height];
prev = new Cell[width][height];
img = loadImage("1.png");
img.loadPixels();
maskImage = loadImage("mask.png");
img.mask(maskImage);
float a = 1;
float b = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j ++) {
if (brightness(img.get(i, j))>16) {
a = 1;
b = 0;
} else {
a = 5;
b = 5;
}
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
}
float dA = 1.0;
float dB = 0.5;
float feed = 0.08;
float k = 0.06;
class Cell {
float a;
float b;
Cell(float a_, float b_) {
a = a_;
b = b_;
}
}
void update() {
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = prev[i][j];
Cell newspot = grid[i][j];
float a = spot.a;
float b = spot.b;
float laplaceA = 0;
laplaceA += a*-1;
laplaceA += prev[i+1][j].a*0.2;
laplaceA += prev[i-1][j].a*0.2;
laplaceA += prev[i][j+1].a*0.2;
laplaceA += prev[i][j-1].a*0.2;
laplaceA += prev[i-1][j-1].a*0.05;
laplaceA += prev[i+1][j-1].a*0.05;
laplaceA += prev[i-1][j+1].a*0.05;
laplaceA += prev[i+1][j+1].a*0.05;
float laplaceB = 0;
laplaceB += b*-1;
laplaceB += prev[i+1][j].b*0.2;
laplaceB += prev[i-1][j].b*0.2;
laplaceB += prev[i][j+1].b*0.2;
laplaceB += prev[i][j-1].b*0.2;
laplaceB += prev[i-1][j-1].b*0.05;
laplaceB += prev[i+1][j-1].b*0.05;
laplaceB += prev[i-1][j+1].b*0.05;
laplaceB += prev[i+1][j+1].b*0.05;
newspot.a = a + (dA*laplaceA - a*b*b + feed*(1-a))*1;
newspot.b = b + (dB*laplaceB + a*b*b - (k+feed)*b)*1;
newspot.a = constrain(newspot.a, 0, 1);
newspot.b = constrain(newspot.b, 0, 1);
}
}
}
void swap() {
Cell[][] temp = prev;
prev = grid;
grid = temp;
}
void draw() {
//println(frameRate);
for (int i = 0; i < 1; i++) {
update();
swap();
}
loadPixels();
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
if (maskImage.get(i, j) != emptypixel) {
Cell spot = grid[i][j];
float a = spot.a;
float b = spot.b;
int pos = i + j * width;
//pixels[pos] = color((a-b)*255);
color aColor = color (0, 0, 0);
color bColor = color (255, 255, 255);
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
}
these 2 images are my mask ( black rectangle) and the image :
You are mixing the second and third approach. If you want the manual approach, then you donāt need to apply your mask() ā as you will be doing that manually.
First, create a global color variable ā that isnāt a processing built-in, it is just a normal integer where you are keeping the color value that you intend to ignore in your manual mask.
color emptypixel;
Now define what color on your mask means empty:
maskImage = loadImage("mask.png");
//img.mask(maskImage);
maskImage.loadPixels();
emptypixel = maskImage.get(3,3); // define what an empty pixel is
Now the rest of your code will work. If the mask color is white, donāt bother to compute the Cell.
However, your example images arenāt going to do anything because your input image (two black and white halves isnāt reactive. Make sure there is texture within your active zones.
import java.awt.Color;
PImage img, maskImage;
Cell[][] grid;
Cell[][] prev;
color emptypixel;
void setup() {
size(364, 364);
grid = new Cell[width][height];
prev = new Cell[width][height];
img = loadImage("https://processing.org/img/processing3-logo.png");
img.resize(width, height);
img.loadPixels();
maskImage = loadImage("mask.png");
//img.mask(maskImage);
maskImage.loadPixels();
emptypixel = maskImage.get(10,10); // define what an empty pixel is
float a = 1;
float b = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j ++) {
if (brightness(img.get(i, j))>16) {
a = 1;
b = 0;
} else {
a = 5;
b = 5;
}
grid[i][j] = new Cell(a, b);
prev[i][j] = new Cell(a, b);
}
}
}
float dA = 1.0;
float dB = 0.5;
float feed = 0.08;
float k = 0.06;
class Cell {
float a;
float b;
Cell(float a_, float b_) {
a = a_;
b = b_;
}
}
void update() {
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
Cell spot = prev[i][j];
Cell newspot = grid[i][j];
float a = spot.a;
float b = spot.b;
float laplaceA = 0;
laplaceA += a*-1;
laplaceA += prev[i+1][j].a*0.2;
laplaceA += prev[i-1][j].a*0.2;
laplaceA += prev[i][j+1].a*0.2;
laplaceA += prev[i][j-1].a*0.2;
laplaceA += prev[i-1][j-1].a*0.05;
laplaceA += prev[i+1][j-1].a*0.05;
laplaceA += prev[i-1][j+1].a*0.05;
laplaceA += prev[i+1][j+1].a*0.05;
float laplaceB = 0;
laplaceB += b*-1;
laplaceB += prev[i+1][j].b*0.2;
laplaceB += prev[i-1][j].b*0.2;
laplaceB += prev[i][j+1].b*0.2;
laplaceB += prev[i][j-1].b*0.2;
laplaceB += prev[i-1][j-1].b*0.05;
laplaceB += prev[i+1][j-1].b*0.05;
laplaceB += prev[i-1][j+1].b*0.05;
laplaceB += prev[i+1][j+1].b*0.05;
newspot.a = a + (dA*laplaceA - a*b*b + feed*(1-a))*1;
newspot.b = b + (dB*laplaceB + a*b*b - (k+feed)*b)*1;
newspot.a = constrain(newspot.a, 0, 1);
newspot.b = constrain(newspot.b, 0, 1);
}
}
}
void swap() {
Cell[][] temp = prev;
prev = grid;
grid = temp;
}
void draw() {
//println(frameRate);
for (int i = 0; i < 1; i++) {
update();
swap();
}
loadPixels();
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j ++) {
if (maskImage.get(i, j) != emptypixel) {
Cell spot = grid[i][j];
float a = spot.a;
float b = spot.b;
int pos = i + j * width;
//pixels[pos] = color((a-b)*255);
color aColor = color (0, 0, 0);
color bColor = color (255, 255, 255);
pixels[pos] = lerpColor(aColor, bColor, (a-b));
}
}
updatePixels();
}
}
ā¦or maybe I misunderstood, and you wanted the two halves to be the mask, and the little shapes to be the image. That would work.
Note also that with EDIT your diffusion is evolving the same way underneath, in update(), but being copied selectively. If you used the mask code in update instead, multiple small windows it mayevolve differently than if you were computing the diffusion across the whole grid and then only revealing part of it as in approach 2. Instead, you would be computing a bunch of small diffusions that are never developing beyond their own edges ā and thus never interacting with each other. On the other hand, that is much faster if you are only computing the pixels that you show.
HI @jeremydouglass ,
I just realised that with the black and white mask I canāt have a gradual change of the pattern, please have a look at this image to show you what Iām trying to do :
Looks like I need to have a gradient colour as a mask to have that result ? I actually want to see the black rectangles on the left and slowly when I go on the right there is a gradual born of the pattern when the rectangles are blackā¦
mmm Iām trying again ,
Thanks!