Processing - creating circles from current pixels - animation

I'm using processing, and I'm trying to create a circle from the pixels i have on my display.
I managed to pull the pixels on screen and create a growing circle from them.
However i'm looking for something much more sophisticated, I want to make it seem as if the pixels on the display are moving from their current location and forming a turning circle or something like this.
This is what i have for now:
int c = 0;
int radius = 30;
allPixels = removeBlackP();
void draw {
loadPixels();
for (int alpha = 0; alpha < 360; alpha++)
{
float xf = 350 + radius*cos(alpha);
float yf = 350 + radius*sin(alpha);
int x = (int) xf;
int y = (int) yf;
if (radius > 200) {radius =30;break;}
if (c> allPixels.length) {c= 0;}
pixels[y*700 +x] = allPixels[c];
updatePixels();
}
radius++;
c++;
}
the function removeBlackP return an array with all the pixels except for the black ones.
This code works for me. There is an issue that the circle only has the numbers as int so it seems like some pixels inside the circle won't fill, i can live with that. I'm looking for something a bit more complex like I explained.
Thanks!

Fill all pixels of scanlines belonging to the circle. Using this approach, you will paint all places inside the circle. For every line calculate start coordinate (end one is symmetric). Pseudocode:
for y = center_y - radius; y <= center_y + radius; y++
dx = Sqrt(radius * radius - y * y)
for x = center_x - dx; x <= center_x + dx; x++
fill a[y, x]
When you find places for all pixels, you can make correlation between initial pixels places and calculated ones and move them step-by-step.
For example, if initial coordinates relative to center point for k-th pixel are (x0, y0) and final coordinates are (x1,y1), and you want to make M steps, moving pixel by spiral, calculate intermediate coordinates:
calc values once:
r0 = Sqrt(x0*x0 + y0*y0) //Math.Hypot if available
r1 = Sqrt(x1*x1 + y1*y1)
fi0 = Math.Atan2(y0, x0)
fi1 = Math.Atan2(y1, x1)
if fi1 < fi0 then
fi1 = fi1 + 2 * Pi;
for i = 1; i <=M ; i++
x = (r0 + i / M * (r1 - r0)) * Cos(fi0 + i / M * (fi1 - fi0))
y = (r0 + i / M * (r1 - r0)) * Sin(fi0 + i / M * (fi1 - fi0))
shift by center coordinates

The way you go about drawing circles in Processing looks a little convoluted.
The simplest way is to use the ellipse() function, no pixels involved though:
If you do need to draw an ellipse and use pixels, you can make use of PGraphics which is similar to using a separate buffer/"layer" to draw into using Processing drawing commands but it also has pixels[] you can access.
Let's say you want to draw a low-res pixel circle circle, you can create a small PGraphics, disable smoothing, draw the circle, then render the circle at a higher resolution. The only catch is these drawing commands must be placed within beginDraw()/endDraw() calls:
PGraphics buffer;
void setup(){
//disable sketch's aliasing
noSmooth();
buffer = createGraphics(25,25);
buffer.beginDraw();
//disable buffer's aliasing
buffer.noSmooth();
buffer.noFill();
buffer.stroke(255);
buffer.endDraw();
}
void draw(){
background(255);
//draw small circle
float circleSize = map(sin(frameCount * .01),-1.0,1.0,0.0,20.0);
buffer.beginDraw();
buffer.background(0);
buffer.ellipse(buffer.width / 2,buffer.height / 2, circleSize,circleSize);
buffer.endDraw();
//render small circle at higher resolution (blocky - no aliasing)
image(buffer,0,0,width,height);
}
If you want to manually draw a circle using pixels[] you are on the right using the polar to cartesian conversion formula (x = cos(angle) * radius, y = sin(angle) * radius).Even though it's focusing on drawing a radial gradient, you can find an example of drawing a circle(a lot actually) using pixels in this answer

Related

Generating a pixel-based spiral gradient

I have a program that creates pixel-based gradients (meaning it calculates the step in the gradient for each pixel, then calculates the colour at that step, then gives the pixel that colour).
I'd like to implement spiral gradients (such as below).
My program can create conic gradients (as below), where each pixel is assigned a step in the gradient according to the angle between it and the midpoint (effectively mapping the midpoint-pixel angle [0...2PI] to [0...1]).
It would seem to me that a spiral gradient is a conic gradient with some additional function applied to it, where the gradient step for a given pixel depends not only on the angle, but on some additional non-linear function applied to the euclidean distance between the midpoint and pixel.
I envisage that a solution would take the original (x, y) pixel coordinate and displace it by some amounts in the x and y axes resulting in a new coordinate (x2, y2). Then, for each pixel, I'd simply calculate the angle between the midPoint and its new displaced coordinate (x2, y2) and use this angle as the gradient step for that pixel. But it's this displacement function that I need help with... of course, there may be other, better ways.
Below is a simple white-to-black conic gradient. I show how I imagine the displacement would work, but its the specifics about this function (the non-linearity), that I'm unable to implement.
My code for conic gradient:
public void conicGradient(Gradient gradient, PVector midPoint, float angle) {
float rise, run;
double t = 0;
for (int y = 0, x; y < imageHeight; ++y) {
rise = midPoint.y - y;
run = midPoint.x;
for (x = 0; x < imageWidth; ++x) {
t = Functions.fastAtan2(rise, run) + Math.PI - angle;
// Ensure a positive value if angle is negative.
t = Functions.floorMod(t, PConstants.TWO_PI);
// Divide by TWO_PI to get value in range 0...1
step = t *= INV_TWO_PI;
pixels[imageWidth * y + x] = gradient.ColorAt(step); // pixels is 1D pixel array
run -= 1;
}
}
}
By eye, it looks like after t = ... fastAtan2..., you just need:
t += PConstants.TWO_PI * Math.sqrt( (rise*rise + run*run) / (imageWidth * imageWidth + imageHeight * imageHeight) )
This just adds the distance from the center to the angle, with appropriate scaling.

Calculating and storing pixelated ellipse

I was wondering if it is possible to create a function (arbitrary of language) that has as input a width and height.
This function would then calculate the biggest ellipse that would fit inside of the dimensions that it is given, and store this in a matrix such as these two examples;
In the left example, the width is 14 and height is 27, where the white part is the ellipse.
In the right example, the width is 38 and height is 21, where, once again, the white part is the ellipse.
Of course, the black and white parts can be seen as true/false values if they are part of the ellipse or not.
Yes it is possible. The process is called ellipse rasterization. Here few methods to do so:
let our image has xs,ys resolution so center (x0,y0) and semiaxises a,b are:
x0=xs/2
y0=y2/2
a =x0-1
b =y0-1
using ellipse equation
so 2 nested for loops + if condition deciding if you are inside or outside ellipse.
for (y=0;y<ys;y++)
for (x=0;x<xs;x++)
if (((x-x0)*(x-x0)/(a*a))+((y-y0)*(y-y0)/(b*b))<=1.0) pixel[y][x]=color_inside;
else pixel[y][x]=color_outside;
You can optimize this quite a lot by pre-computing the parts of the equations only if thy change so some are computed just once others on each x iteration and the rest on each y iteration. Also is better to multiply instead of dividing.
using parametric ellipse equation
x(t) = x0 + a*cos(t)
y(t) = y0 + b*sin(t)
t = <0,2.0*M_PI> // for whole ellipse
so one for loop creating quadrant coordinates and filling lines inside and outside for the 3 mirrors of the quadrant using only horizontal or only vertical lines. However this approach need a buffer to store the circumference points of one quadrant.
Using Bresenham ellipse algorithm
Using any Circle algorithm and stretch to ellipse
so simply use square area of size of the lesser resolution from xs,ys render circle and than stretch back to xs,ys. If you do not stretch during rasterization than you might create artifacts. In such case is better to use the bigger resolution and stretch down but that is slower of coarse.
Drawing an ellipse and storing it in a matrix can be accomplished with two different methods: either Rasterization (the recommended way) or pixel-by-pixel rendering. According to #Spektre's comment, I wonder if both methods are called "rasterization" since they both render the ellipse to raster image. Anyway, I'll explain how to use both methods in C++ to draw an ellipse and store it in your matrix.
Note: Here I'll assume that the origin of your matrix matrix[0][0] refers to the upper-left corner of the image. So points on the matrix are described by x- and y-coordinate pairs, such that x-coordinates increase to the right; y-coordinates increase from top to bottom.
Pixel-by-pixel ellipse rendering
With this method, you loop over all the pixels in your matrix to determine whether each pixel is inside or outside of the ellipse. If the pixel is inside, you make it white, otherwise, you make it black.
In the following example code, the isPointOnEllipse function determines the status of a point relative to the ellipse. It takes the coordinates of the point, coordinates of the center of the ellipse, and the lengths of semi-major and semi-minor axes as parameters. It then returns either one of the values PS_OUTSIDE, PS_ONPERIM, or PS_INSIDE, which indicate that the point lies outside of the ellipse, the point lies exactly on the ellipse's perimeter, or the point lies inside of the ellipse, respectively.
Obviously, if the point status is PS_ONPERIM, then the point is also part of the ellipse and must be made white; because the ellipse's outline must be colored in addition to its inner area.
You must call ellipseInMatrixPBP function to draw an ellipse, passing it a pointer to your matrix, and the width and height of your matrix. This function loops through every pixel in your matrix, and then calls isPointOnEllipse for every pixel to see if it is inside or outside of the ellipse. Finally, it modifies the pixel accordingly.
#include <math.h>
// Indicates the point lies outside of the ellipse.
#define PS_OUTSIDE (0)
// Indicates the point lies exactly on the perimeter of the ellipse.
#define PS_ONPERIM (1)
// Indicates the point lies inside of the ellipse.
#define PS_INSIDE (2)
short isPointOnEllipse(int cx, int cy, int rx, int ry, int x, int y)
{
double m = (x - cx) * ((double) ry) / ((double) rx);
double n = y - cy;
double h = sqrt(m * m + n * n);
if (h == ry)
return PS_ONPERIM;
else if (h < ry)
return PS_INSIDE;
else
return PS_OUTSIDE;
}
void ellipseInMatrixPBP(bool **matrix, int width, int height)
{
// So the ellipse shall be stretched to the whole matrix
// with a one-pixel margin.
int cx = width / 2;
int cy = height / 2;
int rx = cx - 1;
int ry = cy - 1;
int x, y;
short pointStatus;
// Loop through all the pixels in the matrix.
for (x = 0;x < width;x++)
{
for (y = 0;y < height;y++)
{
pointStatus = isPointOnEllipse(cx, cy, rx, ry, x, y);
// If the current pixel is outside of the ellipse,
// make it black (false).
// Else if the pixel is inside of the ellipse or on its perimeter,
// make it white (true).
if (pointStatus == PS_OUTSIDE)
matrix[x][y] = false;
else
matrix[x][y] = true;
}
}
}
Ellipse rasterization
If the pixel-by-pixel approach to rendering is too slow, then use the rasterization method. Here you determine which pixels in the matrix the ellipse affects, and then you modify those pixels (e.g. you turn them white). Unlike pixel-by-pixel rendering, rasterization does not have to pass through the pixels that are outside of the ellipse shape, which is why this approach is so faster.
To rasterize the ellipse, it is recommended that you use the so-called Mid-point Ellipse algorithm, which is an extended form of Bresenham's circle algorithm.
However, I've discovered an ellipse-drawing algorithm which is probably sophisticated enough (except for its performance) to compete with Bresenham's! So I'll post the function that you want - written in C++.
The following code defines a function named ellipseInMatrix that draws an ellipse with a one-pixel stroke, but does not fill that ellipse. You need to pass this function a pointer to the matrix that you have already allocated and initialized to false values, plus the dimensions of the matrix as integers. Note that ellipseInMatrix internally calls the rasterizeEllipse function which performs the main rasterizing operation. Whenever this function finds a point of the ellipse, it sets the corresponding pixel in the matrix to true, which causes the pixel to turn white.
#define pi (2 * acos(0.0))
#define coord_nil (-1)
struct point
{
int x;
int y;
};
double getEllipsePerimeter(int rx, int ry)
{
return pi * sqrt(2 * (rx * rx + ry * ry));
}
void getPointOnEllipse(int cx, int cy, int rx, int ry, double d, struct point *pp)
{
double theta = d * sqrt(2.0 / (rx * rx + ry * ry));
// double theta = 2 * pi * d / getEllipsePerimeter(rx, ry);
pp->x = (int) floor(cx + cos(theta) * rx);
pp->y = (int) floor(cy - sin(theta) * ry);
}
void rasterizeEllipse(bool **matrix, int cx, int cy, int rx, int ry)
{
struct point currentPoint, midPoint;
struct point previousPoint = {coord_nil, coord_nil};
double perimeter = floor(getEllipsePerimeter(rx, ry));
double i;
// Loop over the perimeter of the ellipse to determine all points on the ellipse path.
for (i = 0.0;i < perimeter;i++)
{
// Find the current point and determine its coordinates.
getPointOnEllipse(cx, cy, rx, ry, i, &currentPoint);
// So color the current point.
matrix[currentPoint.x][currentPoint.y] = true;
// So check if the previous point exists. Please note that if the current
// point is the first point (i = 0), then there will be no previous point.
if (previousPoint.x != coord_nil)
{
// Now check if there is a gap between the current point and the previous
// point. We know it's not OK to have gaps along the ellipse path!
if (!((currentPoint.x - 1 <= previousPoint.x) && (previousPoint.x <= currentPoint.x + 1) &&
(currentPoint.y - 1 <= previousPoint.y) && (previousPoint.y <= currentPoint.y + 1)))
{
// Find the missing point by defining its offset as a fraction
// between the current point offset and the previous point offset.
getPointOnEllipse(cx, cy, rx, ry, i - 0.5, &midPoint);
matrix[midPoint.x][midPoint.y] = true;
}
}
previousPoint.x = currentPoint.x;
previousPoint.y = currentPoint.y;
}
}
void ellipseInMatrix(bool **matrix, int width, int height)
{
// So the ellipse shall be stretched to the whole matrix
// with a one-pixel margin.
int cx = width / 2;
int cy = height / 2;
int rx = cx - 1;
int ry = cy - 1;
// Call the general-purpose ellipse rasterizing function.
rasterizeEllipse(matrix, cx, cy, rx, ry);
}
If you need to fill the ellipse with white pixels like the examples that you provided, you can use the following code instead to rasterize a filled ellipse. Call the filledEllipseInMatrix function with a similar syntax to the previous function.
#define pi (2 * acos(0.0))
#define coord_nil (-1)
struct point
{
int x;
int y;
};
double getEllipsePerimeter(int rx, int ry)
{
return pi * sqrt(2 * (rx * rx + ry * ry));
}
void getPointOnEllipse(int cx, int cy, int rx, int ry, double d, struct point *pp)
{
double theta = d * sqrt(2.0 / (rx * rx + ry * ry));
// double theta = 2 * pi * d / getEllipsePerimeter(rx, ry);
pp->x = (int) floor(cx + cos(theta) * rx);
pp->y = (int) floor(cy - sin(theta) * ry);
}
void fillBar(struct point seed, bool **matrix, int cx)
{
int bx;
if (seed.x > cx)
{
for (bx = seed.x;bx >= cx;bx--)
matrix[bx][seed.y] = true;
}
else
{
for (bx = seed.x;bx <= cx;bx++)
matrix[bx][seed.y] = true;
}
}
void rasterizeFilledEllipse(bool **matrix, int cx, int cy, int rx, int ry)
{
struct point currentPoint, midPoint;
struct point previousPoint = {coord_nil, coord_nil};
double perimeter = floor(getEllipsePerimeter(rx, ry));
double i;
// Loop over the perimeter of the ellipse to determine all points on the ellipse path.
for (i = 0.0;i < perimeter;i++)
{
// Find the current point and determine its coordinates.
getPointOnEllipse(cx, cy, rx, ry, i, &currentPoint);
// So fill the bar (horizontal line) that leads from
// the current point to the minor axis.
fillBar(currentPoint, matrix, cx);
// So check if the previous point exists. Please note that if the current
// point is the first point (i = 0), then there will be no previous point.
if (previousPoint.x != coord_nil)
{
// Now check if there is a gap between the current point and the previous
// point. We know it's not OK to have gaps along the ellipse path!
if (!((currentPoint.x - 1 <= previousPoint.x) && (previousPoint.x <= currentPoint.x + 1) &&
(currentPoint.y - 1 <= previousPoint.y) && (previousPoint.y <= currentPoint.y + 1)))
{
// Find the missing point by defining its offset as a fraction
// between the current point offset and the previous point offset.
getPointOnEllipse(cx, cy, rx, ry, i - 0.5, &midPoint);
fillBar(midPoint, matrix, cx);
}
}
previousPoint.x = currentPoint.x;
previousPoint.y = currentPoint.y;
}
}
void filledEllipseInMatrix(bool **matrix, int width, int height)
{
// So the ellipse shall be stretched to the whole matrix
// with a one-pixel margin.
int cx = width / 2;
int cy = height / 2;
int rx = cx - 1;
int ry = cy - 1;
// Call the general-purpose ellipse rasterizing function.
rasterizeFilledEllipse(matrix, cx, cy, rx, ry);
}

animating sine waves in processing

how do I animate the sin lines in the following code to move along the y-axis, to somehow look more like moving water waves?
-if you take out the velocity and acceleration codes you will see what I was trying to work with
float scaleVal = 6.0;
float angleInc = 0.19;
float velocity=0.0;
float acceleration=0.01;
void setup(){
size(750,750);
stroke(255);
}
void draw(){
background (0);
float angle=0.0;
for (int offset = -10; offset < width+10; offset += 10) {
for (int y = 1; y <= height; y += 3) {
float x = offset + (sin(angle) * scaleVal);
line(x, y, x, y+2);
angle += angleInc;
velocity += acceleration;
y += velocity;
}
angle += PI;
}
}
Try using sin() to change the y position instead of x.
The x position can simply increment.
The math may be daunting, but it gets fun once you get the hang of it.
Imagine going around a circle with the radius of 1.0 in a cartesian coordinate system (0 is centre , x and y increase to the right and down and decrease towards left and top):
Let's say you start at the top, the highest value, the length radius of your circle (1.0).
As you decrease the angle, the x move to the left, but the y will go towards the centre( 0.0 )
then x will increase as it gets close to the centre and y will drop to bottom of the circle (-1.0)
then x will keep increasing until it reaches the right edge of the circle and the y value will increase and reach the vertical centre (0.0)
finally the x will decrease until it reaches the horizontal centre and y will increase and reach back to the top of the circle (1.0)
This image explains it pretty well:
Essentially it's like a converter: you plug in an angle from 0 to 360 degrees or TWO_PI radians (as sin works with angles in radians) and you get back a value between -1.0 and 1.0.
If you want to draw a sine wave, you have to draw multiple points:
the x position will increase value directly
the y position will increase the angle, but use the result of the sin() function to obtain a value that goes up and down.
The last thing to do is multiple the result of the sin() function by a larger number to essentially scale the sine wave (from -1.0 to 1.0) to a size more appropate for the screen.
Here's a quick commented demo you can use the mouse position to play with:
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The gist of it is this line:
var y = sin(anglePerPoint * i) * waveHeight;
which can be broken down to:
//increment the angle
var incrementedAngle = anglePerPoint * i;
//compute sine (-1.0,1.0)
var sine = sin(incrementedAngle);
//scale sine result
var waveY = sine * waveHeight;
Once you can draw a static sine wave, it's pretty easy to animate: to the angle increment at each point you add an increasing value. This increases the angle and essentially goes around the circle (TWO_PI) for you.
You can create your own variable to increase at your own rate or you
can easily use an increasing value based on time(millis()) or frame(frameCount) which you can scale down (divide by a large number...or better yet multiple by a small fractional number):
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i + frameCount * 0.01) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
Hopefully the animation and simple demos above help illustrate the point.
In even simpler terms, it's a bit of an illustion: you draw points that only move up and down, but each point use an increasing angle along the circle.
Have a look at Reuben Margolin's kinectic sculpture system demo:
(I recommend checking out the whole PopTech talk: it's inspiring)
You should have a look at the Processing SineWave example as well.
Here's a more complex encapsulating the notions in a resuable function to draw multiple waves to hint at an atmospheric perspective:
int numWaves = 5;
void setup(){
size(400,400);
noStroke();
}
void draw(){
background(255);
for(int i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
void drawSineWave(float radians,float speed,float amplitude,int detail,float size,float y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
float xoffset = size / detail;
//compute angle offset between each point
float angleIncrement = radians / detail;
//for each point
for(int i = 0 ; i <= detail; i++){
//compute x position
float px = xoffset * i;
//use sine function compute y
//millis() * speed is like an ever increasing angle
//to which we add the angle increment for each point (so the the angle changes as we traverse x
//the result of sine is a value between -1.0 and 1.0 which we multiply to the amplitude (height of the wave)
//finally add the y offset
float py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
//add the point
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
void mouseDragged(){
numWaves = 1+(int)mouseX/40;
}
Which you can also run bellow:
var numWaves = 5;
function setup(){
createCanvas(400,400);
noStroke();
}
function draw(){
background(255);
for(var i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
function drawSineWave(radians,speed,amplitude,detail,size,y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
var xoffset = size / detail;
var angleIncrement = radians / detail;
for(var i = 0 ; i <= detail; i++){
var px = xoffset * i;
var py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
function mouseDragged(){
numWaves = ceil(mouseX/40);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The only other suggestion I have, in terms of rendering, it to have play with beginShape(). Rather than having to worry about where to draw each line, simply pass a bunch of points(via vertex(x,y)) in between beginShape()/endShape() calls and let Processing connect the dots for you.
Stack Overflow isn't really designed for general "how do I do this" type questions. It's for more specific "I tried X, expected Y, but got Z instead" type questions. That being said, I'll try to help in a general sense.
If you want to animate something going up and down, you have to modify its Y position over time.
One approach is to use the sin() or cos() functions to come up with a value that alternates between -1 and 1, which you can then multiply by a height and add to a center:
void setup() {
size(100, 200);
}
void draw() {
background (0);
float centerY = height/2;
float waveHeight = 75;
float input = frameCount/10.0;
float ballY = centerY+sin(input)*waveHeight;
ellipse(width/2, ballY, 10, 10);
}
Another approach is to keep track of the position and speed yourself. When the position reaches a min or max, just reverse the speed. Something like this:
float ballY = 100;
float ySpeed = 1;
void setup() {
size(100, 200);
}
void draw() {
background (0);
ballY += ySpeed;
if(ballY < 0 || ballY > height){
ySpeed *= -1;
}
ellipse(width/2, ballY, 10, 10);
}
You could also use the lerp() function. The point is that there are a million different ways to do this. The best thing you can do is to try something and post an MCVE if you get stuck. Good luck.

How do you add a swirl to an image (image distortion)?

I was trying to figure out how to make a swirl in the photo, tried looking everywhere for what exactly you do to the pixels. I was talking with a friend and we kinda talked about using sine functions for the redirection of pixels?
Let's say you define your swirl using 4 parameters:
X and Y co-ordinates of the center of the swirl
Swirl radius in pixels
Number of twists
Start with a source image and create a destination image with the swirl applied. For each pixel (in the destination image), you need to adjust the pixel co-ordinates based on the swirl and then read a pixel from the source image. To apply the swirl, figure out the distance of the pixel from the center of the swirl and it's angle. Then adjust the angle by an amount based on the number of twists that fades out the further you get from the center until it gets to zero when you get to the swirl radius. Use the new angle to compute the adjusted pixel co-ordinates to read from. In pseudo code it's something like this:
Image src, dest
float swirlX, swirlY, swirlRadius, swirlTwists
for(int y = 0; y < dest.height; y++)
{
for(int x = 0; x < dest.width; x++)
{
// compute the distance and angle from the swirl center:
float pixelX = (float)x - swirlX;
float pixelY = (float)y - swirlY;
float pixelDistance = sqrt((pixelX * pixelX) + (pixelY * pixelY));
float pixelAngle = arc2(pixelY, pixelX);
// work out how much of a swirl to apply (1.0 in the center fading out to 0.0 at the radius):
float swirlAmount = 1.0f - (pixelDistance / swirlRadius);
if(swirlAmount > 0.0f)
{
float twistAngle = swirlTwists * swirlAmount * PI * 2.0;
// adjust the pixel angle and compute the adjusted pixel co-ordinates:
pixelAngle += twistAngle;
pixelX = cos(pixelAngle) * pixelDistance;
pixelY = sin(pixelAngle) * pixelDistance;
}
// read and write the pixel
dest.setPixel(x, y, src.getPixel(swirlX + pixelX, swirlY + pixelY));
}
}

Fast algorithm for image distortion

I am working on a tool which distorts images, the purpose of the distortion is to project images to a sphere screen. The desired output is as the following image.
The code I use is as follow - for every Point(x, y) in the destination area, I calculate the corresponding pixel (sourceX, sourceY) in the original image to retrieve from.
But this approach is awkwardly slow, in my test, processing the sunset.jpg (800*600) requires more than 1500ms, if I remove the Mathematical/Trigonometrical calculations, calling cvGet2D and cvSet2D alone require more than 1200ms.
Is there a better way to do this? I am using Emgu CV (a .NET wrapper library for OpenCV) but examples in other language is also OK.
private static void DistortSingleImage()
{
System.Diagnostics.Stopwatch stopWatch = System.Diagnostics.Stopwatch.StartNew();
using (Image<Bgr, Byte> origImage = new Image<Bgr, Byte>("sunset.jpg"))
{
int frameH = origImage.Height;
using (Image<Bgr, Byte> distortImage = new Image<Bgr, Byte>(2 * frameH, 2 * frameH))
{
MCvScalar pixel;
for (int x = 0; x < 2 * frameH; x++)
{
for (int y = 0; y < 2 * frameH; y++)
{
if (x == frameH && y == frameH) continue;
int x1 = x - frameH;
int y1 = y - frameH;
if (x1 * x1 + y1 * y1 < frameH * frameH)
{
double radius = Math.Sqrt(x1 * x1 + y1 * y1);
double theta = Math.Acos(x1 / radius);
int sourceX = (int)(theta * (origImage.Width - 1) / Math.PI);
int sourceY = (int)radius;
pixel = CvInvoke.cvGet2D(origImage.Ptr, sourceY, sourceX);
CvInvoke.cvSet2D(distortImage, y, x, pixel);
}
}
}
distortImage.Save("Distort.jpg");
}
Console.WriteLine(stopWatch.ElapsedMilliseconds);
}
}
From my personal experience, I was doing some stereoscopic vision stuff, the best way to talk to openCV is through own wrapper, you could put your method in c++ and call it from c#, that would give you 1 call to native, faster code, and because under the hood Emgu's keeping OpenCV data, it's also possible to create an image with emgu, process it natively and enjoy processed image in c# again.
The get/set methods looks like Gdi's GetPixel / SetPixel ones, and, according to documentation they are "slow but safe way".
For staying with Emgu only, documentation tells that if you want to iterate over pixels, you should access .Data property:
The safe (slow) way
Suppose you are working on an Image. You can obtain the pixel on the y-th row and x-th column by calling
Bgr color = img[y, x];
Setting the pixel on the y-th row and x-th column is also simple
img[y,x] = color;
The fast way
The Image pixels values are stored in the Data property, a 3D array. Use this property if you need to iterate through the pixel values of the image.

Resources