Yam Big Richard

Big Rich from Birmingham likes music, art and parties. Will code for cash. Likes socialising with beer. Likes digital art. Reads too many magazines. Procrastinates far too much.
Who I Follow

Echo Lake - Even The Blind
Dead Berlin - Hipnosis
Ombre - Tormentas
Ssaliva - AVE
Will Stratton - Who Will
Jacaszek - White Wind Dance
The XX - Fiction (Kid Smpl Remix)
Black Sabbath - Planet aravan (Poolside Rework extended intro)
Monomono - Water Pass Gari (Pts 1 & 2)
Free Association - Purple Mikes
Fela Kuti - No Possible (Joystick Jays Vu Remix)

I answered some questions on the Processing forum which led to me writing this small function to determine the centroid of a polygon it uses this formula to determine the position of the centroid, Cx and Cy:

image

image

where

image

it might be useful for someone.


class pPoint {
 int x, y;
 
 pPoint(int x, int y) {
  this.x = x;
  this.y = y;
 } 
}

void setup() {
 
 size(400,400);
  
 noFill();
 rect(10,10,200,200);
 pPoint[] pArray = new pPoint[4];
 pArray[0] = new pPoint(10,10);
 pArray[1] = new pPoint(210,10);
 pArray[2] = new pPoint(210,210);
 pArray[3] = new pPoint(10,210);
  
 
  
 pPoint pp = getCentroid(pArray);
 
 println(pp.x + "," + pp.y);
 ellipse(pp.x, pp.y, 2, 2);
  
} 

pPoint getCentroid(pPoint[] pArray) {
  
  int X = 0;
  int Y = 0;
  int A = 0;
  
  int numPoints = pArray.length;
  println(numPoints);
  
  for (int i = 0; i < numPoints-1; i++ ) {
        
   X = X +  (pArray[i].x + pArray[i+1].x) * 
             (pArray[i].x*pArray[i+1].y - 
              pArray[i+1].x*pArray[i].y);
     
   Y = Y +  (pArray[i].y + pArray[i+1].y) * 
             (pArray[i].x*pArray[i+1].y - 
               pArray[i+1].x*pArray[i].y);
               
   A = A + ((pArray[i].x * pArray[i+1].y) - (pArray[i+1].x * pArray[i].y));
               
  }
  
  A = A/2;
  
  X = X/(6*A);
  Y = Y/(6*A);
  
  pPoint pp = new pPoint(X,Y);
  return pp;
  
  
}
  
  

BMXing

Edge Detection Video

imContinuing on with the image processing theme I looked at blurring an image.   Gaussian Blur is similar to the Sobel edge detection algorithm insomuch that for each pixel you are processing it looks at the surrounding pixels to determine what change needs to be done.  Each pixel becomes the average of the pixels around it, except that it is a weighted average, this means that the pixels closer to the centre are of more importance.

To what importance we need to give each pixel surrounding and including the centre, we need to use this equation:

image

Where x is horizontal distance from the centre pixel, y is the vertical distance from and sigma is the blur value (the higher the value the more the blur).

In processing the equation would look like:

    weightingValue = 1/(2*PI*sigma*sigma) *
                        exp(-1*((x*x)+(y*y))/(2*(sigma*sigma)));

By plugging in the x,y and sigma values for each pixel we end up with 9 weighting values that I store in an array.  These values need to be normalised before they can be used to change the colour values of a pixel, to do this is simple, add up all of the current weighting values and then multiply by 1/total, this ensures that the total of the new values will add up to 1.

Now you have the weighting values you can step through every pixel to determine the colour intensities of the surrounding values and then multiply them buy the weighted value which are then added together to create a new value.

Working out the top middle value and adding together would look like this:

      //top middle
      //get colour of top middle pixel
      px = pixels[((y-1)*width)+x];
      // get r,g and b values for top middle pixel and multiply by weighting
      redvalue = red(px)*kernelWeightings[1];
      bluevalue = blue(px)*kernelWeightings[1];
      greenvalue = green(px)*kernelWeightings[1];
      // add weighted r,g and b values together
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

Once all of the colour values of the surrounding pixels have been weighted and added together we can then plug them back into the orignal pixel, note that I have used a array of pixels to do this as we don’t want to change the original values until everyone of them has been modified.

     pixelarray[x+(width*y)] = color(redIntensity,greenIntensity,blueIntensity);                 

After this we can use the array of pixels to create a new image.

   for(int i = 0; i<width*height;i++) {
       pixels[i] = pixelarray[i];
   }    
background(0);   
   updatePixels();

Passing through the pixels more than once will produce an image that looks something like this: 

image

Full code:

float sigma = 3.5;  //The blur factor

float returnWeightingValue(float x, float y) {
  
  float weightingValue;
  
  //Gaussian Equation
  weightingValue = 1/(2*PI*sigma*sigma) *
                        exp(-1*((x*x)+(y*y))/(2*(sigma*sigma)));
  return weightingValue;
}

void gaussBlur() {
  float p = returnWeightingValue(0,0);
  float[] kernelWeightings =  new float[9];
 
  float normVal = 0;
  
  //top left
  kernelWeightings[0] = returnWeightingValue(1,1);
  normVal+= kernelWeightings[0];
  
  //top middle
  kernelWeightings[1] = returnWeightingValue(0,1);
  normVal+= kernelWeightings[1];
  
  //top right
  kernelWeightings[2] = returnWeightingValue(1,1);
  normVal+= kernelWeightings[2];
  
  //mid left
  kernelWeightings[3] = returnWeightingValue(1,0);
  normVal+= kernelWeightings[3];
  
  //middle
  kernelWeightings[4] = returnWeightingValue(0,0);
  normVal+= kernelWeightings[4];
  
  //mid right
  kernelWeightings[5] = returnWeightingValue(1,0);
  normVal+= kernelWeightings[5];
  
  //bottom left
  kernelWeightings[6] = returnWeightingValue(1,1);
  normVal+= kernelWeightings[6];
  
  //bottom middle
  kernelWeightings[7] = returnWeightingValue(0,1);
  normVal+= kernelWeightings[7];
  
  //bottom right
  kernelWeightings[8] = returnWeightingValue(1,1);
  normVal+= kernelWeightings[8];
  
  for (int i = 0; i<9; i++) {
    kernelWeightings[i] = (1/normVal)*kernelWeightings[i];
  }
  
  loadPixels();
  int[] pixelarray = new int[width*height];
  
  float redvalue, bluevalue, greenvalue;
  float redIntensity, greenIntensity, blueIntensity;
  
  color px;
  
  for (int x = 1 ; x < width-1; x++) {
    for (int y = 1; y < height-1; y++) {
  
    //top left Pixel
      px = pixels[((y-1)*width)+(x-1)];
      redvalue = red(px)*kernelWeightings[0];
      bluevalue = blue(px)*kernelWeightings[0];
      greenvalue = green(px)*kernelWeightings[0];
      redIntensity = redvalue;
      greenIntensity = greenvalue;
      blueIntensity = bluevalue;
      
      //top middle
      px = pixels[((y-1)*width)+x];
      redvalue = red(px)*kernelWeightings[1];
      bluevalue = blue(px)*kernelWeightings[1];
      greenvalue = green(px)*kernelWeightings[1];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;
      
      // top right 
      px = pixels[((y-1)*width)+x+1];
      redvalue = red(px)*kernelWeightings[2];
      bluevalue = blue(px)*kernelWeightings[2];
      greenvalue = green(px)*kernelWeightings[2];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      
      //middle left pixel
      px = pixels[(y*width)+(x-1)];
      redvalue = red(px)*kernelWeightings[3];
      bluevalue = blue(px)*kernelWeightings[3];
      greenvalue = green(px)*kernelWeightings[3];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      //middle
      px = pixels[(y*width)+x];
      redvalue = red(px)*kernelWeightings[4];
      bluevalue = blue(px)*kernelWeightings[4];
      greenvalue = green(px)*kernelWeightings[4];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;
      
      //middle right
      px = pixels[(y*width)+x+1];
      redvalue = red(px)*kernelWeightings[5];
      bluevalue = blue(px)*kernelWeightings[5];
      greenvalue = green(px)*kernelWeightings[5];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      
      //bottom left
      px = pixels[((y+1)*width)+(x-1)];
      redvalue = red(px)*kernelWeightings[6];
      bluevalue = blue(px)*kernelWeightings[6];
      greenvalue = green(px)*kernelWeightings[6];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      //bottom middle
      px = pixels[((y+1)*width)+x];
      redvalue = red(px)*kernelWeightings[7];
      bluevalue = blue(px)*kernelWeightings[7];
      greenvalue = green(px)*kernelWeightings[7];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      //bottom right
      px = pixels[((y+1)*width)+x+1];
      redvalue = red(px)*kernelWeightings[8];
      bluevalue = blue(px)*kernelWeightings[8];
      greenvalue = green(px)*kernelWeightings[8];
      redIntensity += redvalue;
      greenIntensity += greenvalue;
      blueIntensity += bluevalue;

      pixelarray[x+(width*y)] = color(redIntensity,greenIntensity,blueIntensity);              
    }
  }

 for(int i = 0; i<width*height;i++) {
  pixels[i] = pixelarray[i];
 }     
  
 background(0);    
 updatePixels();

  
  
}

void setup () {
  
  size(375,500);
  PImage img = loadImage("richard2.jpg");
  image(img,0,0);
   
}

void draw() {
  
  if (mousePressed == true) {
    gaussBlur();
  }
  
}

Here is a quick run through of the code used to do an edge detection in Processing.  First up I create an array that can contain all of the values of the screen intensities, place an image on the screen and load the image pixels into the system Pixels[] array:

  int[] pixelarray = new int[width*height];
  PImage img = loadImage(“image.jpg”);
  image(img,0,0);
  loadPixels(); 

Iterating through each individual pixel, I get red, green and blue intensity values for that pixel add them together and depending on the values in the Sobel operator I have multiplied and added them to the overall intensity.  For example the top left pixel in the Sobel matrix:

      px = pixels[((y-1)*width)+(x-1)];
      redvalue = red(px);
      bluevalue = blue(px);
      greenvalue = green(px);
      intensity = redvalue + greenvalue + bluevalue;
      Gx += -intensity;
      Gy += intensity;

Once I have worked out values for all of the surrounding pixels I work out using Pythagoras the overall gradient length.   Then I normalise it so that it can be used as a output value.

      //calculate normalised length of gradient
      glength = sqrt((Gx*Gx)+(Gy*Gy));
      glength = (glength/4328) * 255;     

I load this new information into the array of intensities which is used to create the image of the outline.  I have also used a threshold value to remove the detail from within the picture.

      if (glength > 10)
        pixelarray[x+(width*y)] = color(glength);
      else
        pixelarray[x+(width*y)] = color(0);

Finally I load the array into the system array of pixels which is used to display the new image.

   for(int i = 0; i<width*height;i++) {
     pixels[i] = pixelarray[i];
   }

Full code - https://github.com/bigrichardc/sketchbook/blob/master/sobelImageDetection.pde

I’ve been doing some experiments with altering colour values of digital images and video depending upon their initial values, this led me to looking into how edge detection worked, doing a quick web search led me to pages about the Sobel operator.  Back in the mists of time I did a mathematics degree but after many years of not using any of the hard (or even easy) maths I was taught, I have forgotten it all, and so was left scratching my head looking at the various matrices and equations and words like convolution that I came across.

After a bit more head scratching and considering putting on the too hard to do file, I found this Python/C++ tutorial on the which allowed me to work out what was going on and realise that the maths stuff just looked scary. 

In basic terms the Sobel operator is used to determine the intensity of colour of a pixel and of it’s neighbours then using a method called convolution approximates the difference in intensity along the x and y axis.  A bit of a mouthfull I know but basically it does this:

  1. Get the intensities of pixel x,y and of it’s 8 surrounding pixels.
  2. Work out the change in intensity of the pixels across the x-axis.
  3. Work out intensity change in the y-axis.
  4. Use Pythagoras to work out overall change for those pixels.

As seen in my bad diagram.

image

If you do this for each pixel on the screen you will get an intensity change level for each will allow you to build a picture showing the outlines like so:

image

Another thing you need to know is that the Sobel operator consists of two matrices that look like this:

Sobel Operator

Basically these are the values you multiply the intensity of each pixel surrounding the pixel you are working out the change in intensity for, going left to right (Gx) and from top to bottom (Gy).  So when working out the change across the x-axis the position in the matrix corresponds to the value you would multiply the intensity of the pixel by, for example the pixel intensity in the top left hand corner by -1 and the intensity of the bottom right by +1.

That really is all you need to know in order to be able to detect edges in an image, there are other types of operators that can be used to determine edges each with their own properties but as yet I have not looked at them.

For more formal information including scary looking maths here’s the Sobel operator Wiki page - http://en.wikipedia.org/wiki/Sobel_operator

If that is not making too much sense my next post will look at the code I used to produce the above image which hopefully makes things clearer.

Colour detection on BMX video.

Experimenting with pixel colours.

Screen shot of the rotating squares sketch below.

Experimenting a bit further with matrix co-ordinates, I realised that its quite easy to forget which order that you are supposed perform the order of things, so I (badly) drew an easy to follow diagram that shows me how to do it.

  • Step 1.  The initial step, the matrix 0,0 co-ordinate starts at the top left hand corner of your window.  If you are using more than one it is here that you will pushMatrix().
  • Step 2. The translation step, the matrix is moved along the x and y axis to your desired spot.
  • Step 3. The rotation, the matrix is rotated through the z axis.
  • Step 4. Drawing, you can now draw whatever you want on the matrix.  It is here that you would call the popMatrix() if you needed to draw on another matrix.

image
This sketch uses the translate, rotate and push and pop matrix functions to rotate rectangles held in an ArrayList as the mouse hovers over them.

class Square {
  
  int x, y;
  int sideLength = 50;
  int pen = 1;
  int r = 120;
  
  
  Square() {
    x = (int)random(width-sideLength);
    y = (int)random(height-sideLength);
  }
  
  Square(int x1, int y1) {
    x=x1;
    y=y1;
  }  
    
  void drawSquare() {
    strokeWeight(pen);
    fill(r,0,0);
    pushMatrix();
      translate(x,y);
      rect(0,0,sideLength, sideLength);
      line(-sideLength/2,-sideLength/2,sideLength/2,sideLength/2);
    popMatrix();
  }
  
  void drawRotatedSquare() {
    strokeWeight(pen);
    fill(r,255-r,r);
    pushMatrix();
      translate(x,y);
      rotate(90*PI/180);
      rect(0,0,sideLength, sideLength);
      line(-sideLength/2,-sideLength/2,sideLength/2,sideLength/2);
    popMatrix();
  }
  
  boolean mouseOver(int mx,int my) {
    if ( mx  >= x-sideLength/2 && mx < x+sideLength/2) {
      if ( my  >= y-sideLength/2 && my < y+sideLength/2) {
      return true;
      }
      else return false;
    } else return false;
  } 
}

Square sq;
ArrayList sqs = new ArrayList();
int rotCount = 0;


void setup()
{
  rectMode(CENTER);
  size(500,500);
  for (int y = 0; y<height-50; y+=100) {
    for (int x = 0; x < width-50; x+=100)
    {
      sq = new Square(x+50,y+50);
      sqs.add(sq);
    }
  }
}

void draw() {
  rotCount = 0;
  background(190,0,0);
  int listSize = (sqs.size());
  Square s;
  for (int i = 0; i<listSize; i++)
  {
    s = (Square)sqs.get(i);
    if (s.mouseOver(mouseX,mouseY)) {
      s.pen = 6;
      s.r = (int)random(255);
      s.drawRotatedSquare();
    }
    else {
      s.pen = 1;
      s.drawSquare();      
    }
  }
}



Output from sketch in previous post.

Being a bit lazy it’s taken me quite a while to work out how pushMatrix() and popMatrix() actually work and why I would need them.  Whenever I have tried to rotate things around point before they’ve just gone whizzing off around the screen and in no apparent order whatsoever so I went off in a huff and did something else instead.  Today I decided to sit down and actually see where I was going wrong.

With the help of these three helpful pages:

1. Daniel Shiffman’s Learning Processing
2. Tlll Nagel’s Creative Coding
3. Critical Zero

The rotate() function in Processing rotates the entire co-ordinate matrix which means that everything rotates around the same centre point.  A co-ordination matrix is like a glass surface with images drawn onto it which can then me moved around or rotated.  Calling the pushMatrix() function adds another co-ordinate matrix which would be similar to placing another glass surface over the original, this can also be moved and rotated and drawn on without effecting the original.  The popMatrix() function then returns you to the previous matrix and allows you to work on that.

This is a simple sketch that fills the screen with rectangles and using pushing and popping rotates each of them around their centre points:

float angle = 0;

void setup () { 
  size(500,500);
  rectMode(CENTER);
}

void draw() {
  background(0);
  angle+= 0.05;
  for (int y = 0; y < height-50; y+=50)
  {
  
    for (int x = 0; x < width-50; x+=50)
    {
  
    pushMatrix(); 
    translate(50+x,50+y);
    rotate(angle);
    rect(0,0,50,50);
    popMatrix();
    }
  }
}