Drawing a line on an image - processing

I have stuck up in a problem. This question is with respect to processing. I have to draw a scratch on an image using this function
line(pmouseX, pmouseY, mouseX, mouseY);
How do I achieve this? I mean, wherever I draw a scratch, pixel corresponding to that image has to be updated.
Thanks for any assistance

I'm not sure what kind of effect do you want to achieve so here is basic usage of drawing line according to mouse position.
PImage img; //global variable for storing image
void setup(){
img = loadImage("image.jpg"); //loading image
size(img.width, img.height); //setting size of sketch
}
void draw(){
image(img, 0, 0); //each time redraw background with Image
line(pmouseX, pmouseY, mouseX, mouseY); //draw line acc to mouse
}
If you want to draw big line just move image() function into setup().
If you want more complicated lines you will have to use mouse events.

Related

How do I blur/unblur the picture according to the mouseY position - going down - blur, going up - unblur

It's like the blur is in never ending loop.
This is what I've wrote so far, it's currently always blurring it up again and again, and I can't make it un-blur.
void draw() {
filter(BLUR, blurRate/60);
nextY = mouseY-blurRate;
blurRate= nextY-mouseY;
}
It will help to split the problem into smaller subproblems.
(Kevin Workman's article is a great start)
The code you shared looks like you're trying to do two things at once:
map the mouse Y position to a blur value
apply the blur value to the blur filter
Let's start with mapping the value.
If you know what the minimum / maximum blur value you need you can make your life easier using Processing's map() function. It takes a value(mouseY in your case) and maps it from one range (mouseY's min/max range: 0 to height) to another range (blur's min/max value, let's say 0 to 6)
The mapping range above (from 0, height to 0, 6) is trivial because can simply divide height / 6 and get the mapped value, but map() is pretty useful and worth getting the hang of.
Here's a minimal mapping example:
void setup(){
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
background(0);
text("blurValue: " + blurValue, 5, height / 2);
}
The second part is applying the blur filter.
The catch here is avoiding this situation:
currently always blurring it up again and again,
This happens because you apply the blur filter in draw() multiple times per second to the content, so each pass blurs further.
It sounds like what you want is to apply the blur filter to the initial state of your image or graphics. The code you posted doesn't show what is it that you're trying to blur.
If using graphics rendered in processing, one option is to simply clear everything (using background()) and redrawing the graphics before applying the filter. With the filter applied in draw and nothing cleared/redrawn the effect is reapplied to the same (pre blurred) content continously.
Let's take this basic example:
void setup(){
}
void draw(){
line(mouseX, mouseY, pmouseX, pmouseY);
}
Notice that even draw we render a single tiny line, because the graphics aren't cleared (using background()) each tiny line accumulates to form a larger path.
Intuitively, adding blur will accumulate the effect:
void setup(){
}
void draw(){
line(mouseX, mouseY, pmouseX, pmouseY);
filter(BLUR, 0.6);
}
Another option, if you'd rather be more efficient and re-render the same graphics in draw(), you can get an image copy of what's been rendered so far which you could render continuously.
Let's say you're drawing something in setup().
You can easily call get()(with no arguments) to get a "snapshot" of what's been drawn so far a PImage.
Once you have that you can simply render it again and again in draw() as it was drawn in setup() using image().
Once image() is called you can then call filter() with be applied to the global Processing graphics, meaning only what's rendered (while the snapshot PImage will remain intact).
Here's an example illustrating the above:
PImage snapshot;
void setup(){
// draw something
background(0);
noFill();
strokeWeight(3);
for(int i = 0 ; i < 100; i++){
stroke(random(32, 128));
float size = random(3, 27);
ellipse(random(width), random(height), size, size);
}
// take a snapshot of the current graphics
snapshot = get();
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
// render the image snapshot
image(snapshot, 0, 0);
// blur it
filter(BLUR, blurValue);
// display blur value (should be unblurred)
text("blurValue: " + blurValue, 5, height / 2);
}
Your question doesn't specify, but if you are using PImage, then you need to apply blur to a copy of the image to avoid re-applying blur to an already blurred image. Here's a PImage tweaked version of the above:
PImage snapshot;
void setup(){
// draw something
background(0);
noFill();
strokeWeight(3);
for(int i = 0 ; i < 100; i++){
stroke(random(32, 128));
float size = random(3, 27);
ellipse(random(width), random(height), size, size);
}
// take a snapshot of the current graphics
snapshot = get();
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
// clone the original image via get()
PImage blurredImage = snapshot.get();
// blur the cloned image
blurredImage.filter(BLUR, blurValue);
// display the blurred image
image(blurredImage, 0, 0);
// display blur value (should be unblurred)
text("blurValue: " + blurValue, 5, height / 2);
}

How to draw a fading object trail? Without background manipulation

I have a simple ellipse, moving across the screen, is there any simple code I could implement to have this ellipse draw a trail behind it that has its alpha fade over time to a certain extent? I still want the trail visible in the end but less bright than the casting ellipse.
You could also do something like this:
let positions = [];
function draw(){
positions.push(mouseX);
positions.push(mouseY);
for(let i in positions){
let x = positions[i];
let y = positions[i + 1];
fill(255, 255 - i * 10); noStroke();
ellipse(mouseX, mouseY, x, y)
}
if(positions.length > 20){
positions.shift();
positions.shift();
}
}
Assuming the ellipse is the only thing being drawn then there is a simple solution which is to, instead of drawing a fully opaque background on each frame, draw a semi-transparent background:
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(0, 35);
ellipse(mouseX, mouseY, 20, 20);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
However, there are some caveats, namely that for certain colors/transparency levels you will be left with permanent "ghost" of the trails due to some weird alpha blending math anomalies.

Rendering rectangles through other rectangles

For some reason when I draw over another rectangle in my current processing sketch, it draws over all other rectangle fills, but does not appear to draw over other rectangle strokes. when I make another sketch this problem doesn't persist, but it happens consistently in this sketch.
Overlapping rectangles picture
[]
Example
Here's a simplified example which seems to recreate the issue
void setup(){
size(1000, 600 , P3D);
surface.setResizable(true);
//frameRate(120);
}
void draw(){
if(width < 100)
size(100,height,P3D);
if(height < 100)
size(width,100,P3D);
fill(10);
stroke(10);
strokeWeight(10);
rect(100,100,100,100);
fill(255);
stroke(100);
strokeWeight(10);
rect(0,0,300,300);
}
It's because you set size with the "P3D" argument. P3D is a 3D rendering mode. This result is likely due to some eccentricity of rendering the 2D rect() function in a 3D space.

Processing.js : how to draw() only parts of the canvas to reduce cpu usage

Right now I have an html page that renders 20 canvases each with its own instance of a processing.js script. To decrease CPU usage, I have mouseover/out events to loop()/noLoop() only the graph the mouse is hovering over.
But I need to take this even further. The canvas right now is 300x400 where there is a 300x300 space that needs to dynamically draw all the time but there's a rectangle with a legend that is the rest of the space which really doesn't need to be redrawn using the framerate() of the rest.
Does any know of a way to essentially specify to the draw() function which pixels to redraw?
I'm pretty sure a 100x300 blank area is not going to add significantly to the computations. But you can of course pass to draw something like:
if(frameCount==1) [draw legend code];
or using if(frameCount % 30 == 0)... for a continuous but less frequent rendering.
Edit:
void setup(){
size(400,400);
noStroke();
background(255);
}
void draw(){
fill(255,255,255,50);
rect(0, 150, width, height-150);
if(frameCount%50 == 1) {
fill(255);
rect(0, 0, width, 150);
fill(0);
text("frame " + frameCount, width/2, 75);
}
fill(255,0,0);
ellipse(random(0, width), random(150, height), 10, 10);
}

Move around an image in processing

Is it possible to move an image (or image object) without clearing the whole background?
I wish to create an app that allows the user to "paint", using a device that is not the mouse. I would like to have a cursor to follow the users movement with the input device, without having to clear the already painted picture.
Is this possible? And how?
It depends how you handle drawing.
I would suggest using PImage as a canvas to draw into and another PImage to store the pixels of your brush. The 'brush' can be a loaded image, or at the start of your sketch you could make the brush using drawing commands, then store those as a PImage using get().
You will need to clear everything because you want to draw your cursor, but you will also draw your canvas, and you'll store 'brush strokes' only when the mouse is pressed (or some device specific method) by using the copy() or the blend() function (depending on your brush PNG - with or without transparency, etc.)
Here's a quick sketch to illustrate this:
PImage canvas;
PImage brush;
void setup(){
size(800,800);
stroke(128);
smooth();
canvas = createImage(width,height,ARGB);
brush = loadImage("brush.png");
}
void draw(){
background(255);
image(canvas,0,0);
//draw cursor
line(mouseX-5,mouseY-5,mouseX+5,mouseY+5);
line(mouseX+5,mouseY-5,mouseX-5,mouseY+5);
//blend brush pixels into canvas if mouse is pressed
if(mousePressed) canvas.blend(brush, 0, 0, brush.width, brush.width, (int)(mouseX-brush.width*.5), (int)(mouseY-brush.height*.5), brush.width, brush.width,MULTIPLY);
}
Note that you need an image into your sketch's data folder.
You can try it here:
You can run a javascript version bellow:
var canvas;
var brush;
function setup(){
createCanvas(800,800);
stroke(128);strokeWeight(3);
smooth();
canvas = createImage(width,height);
brush = getGradientImg(64,64,random(360),random(100),85);
}
function draw(){
background(255);
image(canvas,0,0);
//draw cursor
line(mouseX-5,mouseY-5,mouseX+5,mouseY+5);
line(mouseX+5,mouseY-5,mouseX-5,mouseY+5);
//blend brush pixels into canvas if mouse is pressed
if(isMousePressed) canvas.blend(brush, 0, 0, brush.width, brush.width, (int)(mouseX-brush.width*.5), (int)(mouseY-brush.height*.5), brush.width, brush.width,MULTIPLY);
//image(brush,mouseX,mouseY);
}
//*
function getGradientImg(w,h,hue,satMax,brightness){
push();//isolate drawing styles such as color Mode
colorMode(HSB,360,100,100);
var gradient = createImage(w,h);//create an image with an alpha channel
var np = w * h;//total number of pixels
var np4 = np*4;
var cx = floor(gradient.width * 0.5);//center on x
var cy = floor(gradient.height * 0.5);//center on y
gradient.loadPixels();
for(var i = 0 ; i < np4; i+=4){//for each pixel
var id4 = floor(i * .25);
var x = id4%gradient.width;//compute x from pixel index
var y = floor(id4/gradient.width);//compute y from pixel index
var d = dist(x,y,cx,cy);//compute distance from centre to current pixel
//map the saturation and transparency based on the distance to centre
gradient.pixels[i] = hue;
gradient.pixels[i+1] = map(d,0,cx,satMax,0);
gradient.pixels[i+2] = brightness;
gradient.pixels[i+3] = map(d,0,cx,255,0);
}
gradient.updatePixels();//finally update all the pixels
pop();
console.log(gradient);
return gradient;
}
//*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>

Resources